c# Doesn't read all content from socket in local http server

0

I'm using a local server in a Windows Store App (http://blog.jsolutions.co.uk/?p=492) for serve html files.

The program reads the input from socket:

    StringBuilder inputRequestBuilder = new StringBuilder();

    // Read all the request data.
    // (This is assuming it is all text data of course)
    using (var input = socket.InputStream)
    {
        var data = new Windows.Storage.Streams.Buffer(BUFFER_SIZE);
        uint dataRead = BUFFER_SIZE;

        while (dataRead == BUFFER_SIZE)
        {
            await input.ReadAsync(data, BUFFER_SIZE, InputStreamOptions.Partial);

            var dataArray = data.ToArray();
            var dataString = Encoding.UTF8.GetString(dataArray, 0, dataArray.Length);

            inputRequestBuilder.Append(dataString);
            dataRead = data.Length;
        }
    }

But sometimes, when the user submit a html form, the inputRequestBuilder has not all the content, for example:

"POST /LMS/ajax.php?op=commitSCORM HTTP/1.1\r\nAccept: */*\r\nContent-Type: application/x-www-form-urlencoded\r\nReferer: http://localhost:8080/xxxxxxx.htm\r\nAccept-Language: es-ES,es;q=0.8,en-GB;q=0.5,en;q=0.3\r\nAccept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; WebView/1.0)\r\nHost: localhost:8080\r\nContent-Length: 2537\r\nConnection: Keep-Alive\r\nCache-Control: no-cache\r\nCookie: port=8080\r\n\r\n"

The content-length is 2537, but there is no content. So, I don't know what's the problem. Maybe the webview sends two packet (http header and form content) and... I don't know.

I tried to read from socket again, when all the content is not ready, but VS throws: Error 0x80072746 The remote host closed the connection.

Thanks!

c#
sockets
visual-studio-2012
windows-8
windows-store-apps
asked on Stack Overflow Nov 7, 2013 by JoniJnm

2 Answers

2

You are passing InputStreamOptions.Partial to ReadAsync. This implies that ReadAsync may return with less than BUFFER_SIZE even when there is more data in the wire.

Try using InputStreamOptions.None instead. But this may not work in your case, because the connection will remain open and ReadAsync will block. You will need to parse the Content-Length value from the headers, and read that amount of bytes after the \r\n\r\n.

answered on Stack Overflow Nov 8, 2013 by kiewic
1

With the comment of Kiewic, the ugly script that works:

StringBuilder inputRequestBuilder = new StringBuilder();
List<byte> bytes = new List<byte>();
List<byte> last4bytes = new List<byte>();
string request = null;
using (var input = socket.InputStream.AsStreamForRead())
{
    int b;
    while (true)
    {
        try
        {
            b = input.ReadByte();
        }
        catch(Exception e) {
            FileManager.WriteToDebug(e.ToString());
            break;
        }
        bytes.Add((byte)b);
        if (last4bytes.Count < 4)
        {
            last4bytes.Add((byte)b);
        }
        else
        {
            last4bytes.RemoveAt(0);
            last4bytes.Add((byte)b);
            if (last4bytes.ElementAt(0) == 13 && last4bytes.ElementAt(1) == 10
                && last4bytes.ElementAt(2) == 13 && last4bytes.ElementAt(3) == 10)
            {
                //after \r\n\r\n there is the content
                byte[] byteArray = bytes.ToArray();
                request = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
                inputRequestBuilder.Append(request);
                string contentLength = getValueFromHeader("Content-Length", request);
                if (!contentLength.Equals(""))
                {
                    int length = Convert.ToInt32(contentLength);
                    if (length > 0)
                    {
                        byteArray = new byte[length];
                        input.Read(byteArray, 0, length);
                        var dataString = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
                        inputRequestBuilder.Append(dataString);
                    }
                }
                break;
            }
        }
    }
}
request = inputRequestBuilder.ToString();
answered on Stack Overflow Nov 12, 2013 by JoniJnm

User contributions licensed under CC BY-SA 3.0