How can I accept “unsafe” HTTP response headers in a Windows Phone/Store app?

雨燕双飞 提交于 2019-12-10 20:57:15

问题


Recently, some code in a Windows Phone 8.1 Silverlight app that used HttpClient to access a 3rd-party REST API stopped working. I got the following error:

A first chance exception of type 'System.Exception' occurred in mscorlib.ni.dll

Additional information: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

After trying this in Windows Phone (Silverlight) and Store (RT) apps, I rewrote the same code in WPF and finally got a useful error message:

The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF"

There is also a great in-depth blog post about this problem.

Microsoft has stated that they will not fix/allow this so I'm either forced to find a 3rd-party HTTP library that will allow unsafe headers or write my own.

How can I solve this problem? If I write my own library from scratch, what would be the appropriate classes to consider? Is there any relevant sample code available?

(This question might be too similar to this one although after writing some test code, the idea of using a custom handler with HttpClient doesn't work either since the system handler is called first on response.)


回答1:


It turns out that you can implement a basic HTTP client fairly easily. Ignoring error handling and dealing with Content-Length (more on that later), this code should do the trick.

var hostname = new HostName("www.w3.org");
var socket = new StreamSocket();
await socket.ConnectAsync(hostname, "80");

var request = "GET /Protocols/rfc2616/rfc2616-sec4.html HTTP/1.1\r\n" +
          "Host: www.w3.org\r\n" +
          "\r\n";

var writer = new DataWriter(socket.OutputStream);
writer.WriteString(request);
await writer.StoreAsync();

var reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;

string data = string.Empty;    
var cts = new CancellationTokenSource();

bool doneReading = false;
uint bytesToRead = 10240;

while (!doneReading)
{
  try
  {
    cts.CancelAfter(10 * 1000);
    await reader.LoadAsync(bytesToRead).AsTask(cts.Token);
    data += reader.ReadString(reader.UnconsumedBufferLength);

    totalBytesRead += bytesRead;
  }
  catch (TaskCanceledException)
  {
    doneReading = true;
  }
}

socket.Dispose();

There are definitely some issues to solve:

  • The timeout is 10 seconds. But depending on what kind of connection you're on, perhaps that's ok?
  • For that matter, waiting for a timeout is the wrong way to determine if the server has finished sending data. As Jon Skeet mentioned in Correctly receiving data using StreamSocket hangs, the client should read Content-Length from the header and request the appropriate number of bytes. Of course, since TCP is a stream this takes a bit of work as well.

Also, this solution is mainly for Windows Phone 8.1 Silverlight. Although it will also work on Windows Phone 8.1/Windows Store (i.e. WinRT) apps, it might be easier to use MessageWebSocket on that platform.

I wrote a three-part series of posts on this since it appears to be a fairly common issue; this work-around is discussed in part two. Also of note is that the error message CR must be followed by LF may not be completely accurate -- it could also means there's an invalid character in the header (including a space in one of the header names).



来源:https://stackoverflow.com/questions/25209693/how-can-i-accept-unsafe-http-response-headers-in-a-windows-phone-store-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!