How can I accept "insecure" HTTP response headers in a Windows Phone / Store app?

Recently, some of the codes in a Windows Phone 8.1 Silverlight application that were used HttpClient

to access a third party REST API stopped working. I got the following error:

The first exception of type "System.Exception" occurred in mscorlib.ni.dll

More information: Crash (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

After trying to use this app on Windows Phone (Silverlight) and Store (RT), I rewrote the same code in WPF and finally got a helpful 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 issue.

Microsoft has stated that they will not fix / allow this , so I either have to find a third 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 classes would I consider? Is there a suitable sample code?

(This question might be too similar to this one , although after writing some test code, the idea of ​​using a custom handler with HttpClient

does not work either as the system handler is first called in response.)

+3


source to share


1 answer


It turns out that you can easily implement a basic HTTP client. Ignoring error handling and working 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 certain problems to solve:



  • The timeout is 10 seconds. But depending on which connection you are with, maybe that's okay?
  • In this case, waiting for a timeout is not the correct way to determine if the server has finished sending data. As Jon Skeet mentions in Getting data correctly with a StreamSocket hangs , the client has to read Content-Length

    from the header and request the appropriate number of bytes. Of course, since TCP is a stream , this also takes some work.

Also, this solution is mostly for Windows Phone 8.1 Silverlight. While it will also work on Windows Phone 8.1 / Windows Store apps (like WinRT), it might be easier to use MessageWebSocket

on that platform.

I have written three parts of articles on this subject since this seems to be a fairly common problem; this workaround is discussed in part two . It should also be noted that the error message CR must be followed by LF

may not be entirely accurate - it could also indicate that there is an invalid character in the header (including a space in one of the headers).

0


source







All Articles