예제 #1
0
        /// <summary>
        /// Parse the request and headers.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private HttpRequest ParseRequest(Stream input)
        {
            // Parse the request first
            RequestParseState state = RequestParseState.StartLine;
            string            line;
            HttpRequest       request = null;

            try
            {
                while (m_connected && (state != RequestParseState.Body))
                {
                    // Keep trying to read a line
                    if (!ReadLine(input, out line))
                    {
                        continue;
                    }
                    switch (state)
                    {
                    case RequestParseState.StartLine:
                        request = ParseRequestLine(line);
                        if (request == null)
                        {
                            return(null);    // Just let the connection close
                        }
                        state++;
                        break;

                    case RequestParseState.Headers:
                        if (line.Length == 0)
                        {
                            state++;
                        }
                        else
                        {
                            ParseHeaderLine(request, line);
                        }
                        break;
                    }
                }
            }
            catch (HttpException ex)
            {
                throw ex;
            }
            catch (Exception)
            {
                throw new HttpInternalServerErrorException("Error parsing request.");
            }
            // All done
            return(request);
        }
예제 #2
0
        private async void handleRequest(StreamSocket socket)
        {
            Logger.log("XHRProxy", "Received incoming HTTP request");

            DataWriter writer = new DataWriter(socket.OutputStream);

            writer.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

            // deny any request that isn't from localhost
            if (socket.Information.RemoteAddress.RawName != "::1")
            {
                Logger.log("XHRProxy", "403 Forbidden; remote address \"" + socket.Information.RemoteAddress.RawName + "\" != \"::1\"");
                requestError(writer, socket, "403 Forbidden", "Forbidden");
                return;
            }

            DataReader reader = new DataReader(socket.InputStream);

            reader.InputStreamOptions = InputStreamOptions.Partial;

            RequestParseState state             = RequestParseState.GetRequest;
            string            urlPrefix         = "/fetch/" + this.securityToken + "/";
            UInt32            numBytesRead      = 0;
            UInt32            requestBufferSize = 4096;
            string            buffer            = "";
            string            httpMethod        = "";
            string            url = "";
            bool           isLocalFile = true;
            Uri            httpUri = null;
            int            p, q;
            bool           needMoreData         = true;
            HttpWebRequest request              = null;
            Dictionary <string, string> headers = new Dictionary <string, string>();
            int responseBufferSize              = 4096;
            int responseBytesRead               = 0;
            int responseTotalBytesRead          = 0;

            byte[] responseBuffer = new byte[responseBufferSize];

            try {
                while (true)
                {
                    Logger.log("XHRProxy", "State = " + states[(int)state]);

                    if (needMoreData)
                    {
                        numBytesRead = await reader.LoadAsync(requestBufferSize);

                        Logger.log("XHRProxy", "Read " + numBytesRead + " bytes");
                        buffer += reader.ReadString(numBytesRead);
                    }

                    switch (state)
                    {
                    case RequestParseState.GetRequest:
                        // go until first \n
                        p = buffer.IndexOf("\r\n");
                        if (p != -1)
                        {
                            // parse out the request
                            string[] tokens = buffer.Substring(0, p).Split(' ');
                            if (tokens.Length != 3)
                            {
                                Logger.log("XHRProxy", "400 Bad Request; request had " + tokens.Length + " tokens, expected 3");
                                requestError(writer, socket, "400 Bad Request", "Bad Request");
                                return;
                            }

                            httpMethod = tokens[0].ToUpper();
                            Logger.log("XHRProxy", "Method = " + httpMethod);

                            url = tokens[1];
                            q   = url.IndexOf(urlPrefix);
                            if (q != 0)
                            {
                                Logger.log("XHRProxy", "400 Bad Request");
                                requestError(writer, socket, "400 Bad Request", "Bad Request");
                                return;
                            }

                            string encodedUrl = url.Substring(q + urlPrefix.Length);
                            string decodedUrl = HttpUtility.UrlDecode(encodedUrl).Replace(' ', '+');
                            byte[] data       = Convert.FromBase64String(decodedUrl);
                            url = Encoding.UTF8.GetString(data, 0, data.Length);
                            if (url.IndexOf("http://") == 0 || url.IndexOf("https://") == 0)
                            {
                                isLocalFile = false;
                            }
                            Logger.log("XHRProxy", "URL = " + url);

                            buffer       = buffer.Substring(p + 2);
                            needMoreData = false;
                            state        = RequestParseState.Headers;
                        }
                        else if (numBytesRead < requestBufferSize)
                        {
                            // not enough data, bad request
                            Logger.log("XHRProxy", "400 Bad Request; not enough data");
                            requestError(writer, socket, "400 Bad Request", "Bad Request");
                            return;
                        }
                        else
                        {
                            // need more data
                            Logger.log("XHRProxy", "Need more data...");
                            needMoreData = true;
                        }
                        break;

                    case RequestParseState.Headers:
                        p = buffer.IndexOf("\r\n\r\n");                                 // two line breaks
                        if (p != -1)
                        {
                            Logger.log("XHRProxy", "Original HTTP Request Headers:");
                            string[] lines = buffer.Substring(0, p).Split('\n');
                            foreach (string line in lines)
                            {
                                q = line.IndexOf(':');
                                if (q != -1)
                                {
                                    string name  = line.Substring(0, q);
                                    string value = line.Substring(q + 2).Trim();
                                    Logger.log("XHRProxy", "    " + name + ": " + value);
                                    headers[name] = value;
                                }
                                else
                                {
                                    Logger.log("XHRProxy", "    Bad HTTP header \"" + line + "\", ignoring");
                                }
                            }

                            buffer = buffer.Substring(p + 4);
                            state  = isLocalFile ? RequestParseState.ServeFile : RequestParseState.CreateRequest;
                        }
                        else if (numBytesRead < requestBufferSize)
                        {
                            // not enough data, bad request
                            Logger.log("XHRProxy", "400 Bad Request; not enough data");
                            requestError(writer, socket, "400 Bad Request", "Bad Request");
                            return;
                        }
                        else
                        {
                            // need more data
                            Logger.log("XHRProxy", "Need more data...");
                            needMoreData = true;
                        }

                        if (state == RequestParseState.ServeFile)
                        {
                            continue;
                        }
                        break;

                    case RequestParseState.ServeFile:
                        string originalFile = url;
                        string file         = collapsePath(originalFile);
                        if (file.IndexOf("..") == 0)
                        {
                            Logger.log("XHRProxy", "400 Bad Request");
                            Logger.log("XHRProxy", "Original file: " + originalFile);
                            Logger.log("XHRProxy", "Resolved file: " + file);
                            requestError(writer, socket, "400 Bad Request", "The requested file must not begin with \"..\"");
                            return;
                        }

                        file = file.Replace('/', '\\');

                        if (file.StartsWith("\\"))
                        {
                            file = "App" + file;
                        }
                        else
                        {
                            file = "App\\" + file;
                        }

                        StorageFolder installFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
                        StorageFile   theFile;
                        try {
                            theFile = await installFolder.GetFileAsync(file);
                        } catch (Exception e) {
                            Logger.log("XHRProxy", "404 File Not Found");
                            Logger.log("XHRProxy", "Original file: " + originalFile);
                            Logger.log("XHRProxy", "Resolved file: " + file);
                            requestError(writer, socket, "404 File Not Found", "File Not Found");
                            return;
                        }

                        var randomAccessStream = await theFile.OpenReadAsync();

                        Stream fs = randomAccessStream.AsStreamForRead();

                        FileInfo fi  = new FileInfo(file);
                        string   ext = fi.Extension.Substring(1);                               // trim the dot

                        string mimetype = "application/octet-stream";
                        if (mimeTypes.ContainsKey(ext))
                        {
                            mimetype = mimeTypes[ext];
                        }

                        Logger.log("XHRProxy", "Status: 200 OK");
                        Logger.log("XHRProxy", "Actual HTTP headers being returned:");
                        Logger.log("XHRProxy", "    Content-Type: " + mimetype);
                        Logger.log("XHRProxy", "    Content-Length: " + fi.Length);
                        Logger.log("XHRProxy", "    Connection: close");

                        writer.WriteString("HTTP/1.0 200 OK\r\n");
                        writer.WriteString("Content-Type: " + mimetype + "\r\n");
                        writer.WriteString("Content-Length: " + fi.Length + "\r\n");
                        writer.WriteString("Connection: close\r\n\r\n");

                        while ((responseBytesRead = fs.Read(responseBuffer, 0, responseBuffer.Length)) > 0)
                        {
                            responseTotalBytesRead += responseBytesRead;
                            writer.WriteBytes(responseBuffer);
                        }
                        Logger.log("XHRProxy", "Returned " + responseTotalBytesRead + " bytes");

                        await writer.StoreAsync();

                        socket.Dispose();
                        return;

                    case RequestParseState.CreateRequest:
                        httpUri        = new Uri(url, UriKind.Absolute);
                        request        = (HttpWebRequest)WebRequest.CreateHttp(httpUri);
                        request.Method = httpMethod;

                        Logger.log("XHRProxy", "Actual HTTP headers being sent:");
                        foreach (string key in headers.Keys)
                        {
                            if (key == "Accept")
                            {
                                Logger.log("XHRProxy", "    Accept: " + headers[key]);
                                request.Accept = headers[key];
                            }
                            else if (key == "Content-Type")
                            {
                                if (httpMethod == "POST" || httpMethod == "PUT")
                                {
                                    Logger.log("XHRProxy", "    Content-Type: " + headers[key]);
                                    request.ContentType = headers[key];
                                }
                            }
                            else if (key == "Host")
                            {
                                Logger.log("XHRProxy", "    Host: " + httpUri.Host);
                                request.Headers["Host"] = httpUri.Host;
                            }
                            else
                            {
                                Logger.log("XHRProxy", "    " + key + ": " + headers[key]);
                                request.Headers[key] = headers[key];
                            }
                        }

                        if (httpMethod == "POST" || httpMethod == "PUT")
                        {
                            Stream requestStream = await Task.Factory.FromAsync <Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null);

                            byte[] jsonAsBytes = Encoding.UTF8.GetBytes(buffer);
                            Logger.log("XHRProxy", "Body:");
                            Logger.log("XHRProxy", buffer);
                            await requestStream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);

                            if (numBytesRead == requestBufferSize)
                            {
                                // pump the rest of the data
                                while (true)
                                {
                                    numBytesRead = await reader.LoadAsync(requestBufferSize);

                                    if (numBytesRead == 0)
                                    {
                                        break;
                                    }
                                    Logger.log("XHRProxy", "Read " + numBytesRead + " bytes");
                                    buffer = reader.ReadString(numBytesRead);
                                    Logger.log("XHRProxy", buffer);
                                    byte[] jsonAsBytes2 = Encoding.UTF8.GetBytes(buffer);
                                    await requestStream.WriteAsync(jsonAsBytes2, 0, jsonAsBytes2.Length);

                                    if (numBytesRead < requestBufferSize)
                                    {
                                        break;
                                    }
                                }
                            }

                            requestStream.Close();
                        }

                        Logger.log("XHRProxy", "Sending request...");
                        request.BeginGetResponse(async callbackResult => {
                            try {
                                Logger.log("XHRProxy", "Reading response...");
                                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);

                                Logger.log("XHRProxy", "Status: " + (int)response.StatusCode + " " + response.StatusDescription);
                                writer.WriteString("HTTP/1.0 " + (int)response.StatusCode + " " + response.StatusDescription + "\r\n");

                                Logger.log("XHRProxy", "Original HTTP response headers:");
                                foreach (string key in response.Headers.AllKeys)
                                {
                                    Logger.log("XHRProxy", "    " + key + ": " + response.Headers[key]);
                                }

                                Logger.log("XHRProxy", "Actual HTTP headers being returned:");
                                foreach (string key in response.Headers.AllKeys)
                                {
                                    if (key == "Connection")
                                    {
                                        Logger.log("XHRProxy", "    Connection: close");
                                        writer.WriteString("Connection: close\r\n");
                                    }
                                    else
                                    {
                                        Logger.log("XHRProxy", "    " + key + ": " + response.Headers[key]);
                                        writer.WriteString(key + ": " + response.Headers[key] + "\r\n");
                                    }
                                }
                                writer.WriteString("\r\n");

                                Stream responseStream = response.GetResponseStream();
                                BinaryReader br       = new BinaryReader(responseStream);
                                byte[] responseBytes  = br.ReadBytes(4096);
                                while (responseBytes.Length > 0)
                                {
                                    responseTotalBytesRead += responseBytes.Length;
                                    writer.WriteBytes(responseBytes);
                                    responseBytes = br.ReadBytes(4096);
                                }
                                Logger.log("XHRProxy", "Returned " + responseTotalBytesRead + " bytes");

                                await writer.StoreAsync();
                                socket.Dispose();
                            } catch (WebException ex) {
                                // check if we have an expired or self-signed cert
                                if (ex.Status == WebExceptionStatus.UnknownError)
                                {
                                    if (ex.Response.Headers.Count == 0 && httpUri.Scheme == "https")
                                    {
                                        Logger.log("XHRProxy", "Invalid SSL certificate, returning a 400 Bad Request");
                                        requestError(writer, socket, "400 Bad Request", "Invalid SSL certificate");
                                    }
                                    else
                                    {
                                        Logger.log("XHRProxy", "File not found, returning a 404");
                                        requestError(writer, socket, "404 File Not Found", "File Not Found");
                                    }
                                }
                                else
                                {
                                    Logger.log("XHRProxy", "400 Bad Request");
                                    Logger.log("XHRProxy", ex.Status.ToString());
                                    requestError(writer, socket, "400 Bad Request", ex.Status.ToString());
                                }
                                return;
                            }
                        }, null);

                        return;
                    }
                }
            } catch (Exception ex) {
                Logger.log("XHRProxy", "500 Internal Server Error");
                foreach (string s in ex.ToString().Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None))
                {
                    Logger.log("XHRProxy", s);
                }
                requestError(writer, socket, "500 Internal Server Error", ex.Message);
            }
        }