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.)
source to share
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).
source to share