Пример #1
0
        public void HeaderRecvHandler(ref SelectControl selectControl, Socket clientSocket, Buf ignore)
        {
            builder.EnsureTotalCapacity(builder.contentLength + 128);

            UInt32 dataOffset;

            try
            {
                dataOffset = Http.ReadHttpHeaders(clientSocket, builder);
            }
            catch (Exception e)
            {
                if (WebServer.Logger != null)
                {
                    WebServer.Logger.WriteLine("[{0}] Closed: {1}", clientLogString, e.Message);
                }
                selectControl.RemoveReceiveSocket(clientSocket);
                return;
            }

            //
            // Parse the request
            //
            try
            {
                UInt32 parseOffset = 0;

                Slice httpMethod;
                httpMethod.offset = parseOffset;
                httpMethod.limit  = builder.bytes.IndexOfUInt32(parseOffset, dataOffset, (Byte)' ');
                if (httpMethod.limit == UInt32.MaxValue)
                {
                    throw new FormatException("Invalid request: no space after HTTP method");
                }
                parseOffset = (uint)httpMethod.limit + 1;

                Slice httpResource;
                httpResource.offset = parseOffset;
                httpResource.limit  = builder.bytes.IndexOfUInt32(parseOffset, dataOffset, (Byte)' ');
                if (httpResource.limit == UInt32.MaxValue)
                {
                    throw new FormatException("Invalid request: no space after HTTP resource");
                }
                parseOffset = (uint)httpResource.limit + 1;

                this.method   = httpMethod.Decode(builder.bytes);
                this.resource = httpResource.Decode(builder.bytes);

                headerContentLength = Http.GetContentLength(builder.bytes, 0, dataOffset);

                if (headerContentLength != UInt32.MaxValue)
                {
                    throw new NotImplementedException(String.Format("Content-Length {0} is not implemented", headerContentLength));
                }
            }
            catch (Exception e)
            {
                if (WebServer.Logger != null)
                {
                    WebServer.Logger.WriteLine("[{0}] InvalidRequest: {1}", clientLogString, e.Message);
                }
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
                selectControl.RemoveReceiveSocket(clientSocket);
                return;
            }

            if (WebServer.Logger != null)
            {
                WebServer.Logger.WriteLine("[{0}] {1} {2}", clientLogString, method, resource);
            }

            if (!method.Equals("GET"))
            {
                if (WebServer.Logger != null)
                {
                    WebServer.Logger.WriteLine("[{0}] Unsupported HTTP Method: {1}", clientLogString, method);
                }
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
                selectControl.RemoveReceiveSocket(clientSocket);
                return;
            }
            String filename = WebServer.HttpResourceToFile(resource);

            if (!File.Exists(filename))
            {
                clientSocket.Send(NotFound404);
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
                selectControl.RemoveReceiveSocket(clientSocket);
                return;
            }


            builder.Clear();
            FileInfo fileInfo   = new FileInfo(filename);
            Int64    fileLength = fileInfo.Length;

            builder.AppendAscii("HTTP/1.1 200 OK\r\nContent-Length: ");
            builder.AppendAscii(fileLength.ToString());
            builder.AppendAscii("\r\n\r\n");
            using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                UInt32 bufferLeft = (uint)builder.bytes.Length - builder.contentLength;

                if (fileLength <= bufferLeft)
                {
                    fileStream.ReadFullSize(builder.bytes, (int)builder.contentLength, (int)fileLength);
                    clientSocket.Send(builder.bytes, 0, (int)(builder.contentLength + fileLength), 0);
                }
                else
                {
                    Int64 fileLeft = fileLength;

                    fileStream.ReadFullSize(builder.bytes, (int)builder.contentLength, (int)bufferLeft);
                    clientSocket.Send(builder.bytes);
                    fileLeft -= bufferLeft;

                    while (fileLeft > builder.bytes.Length)
                    {
                        fileStream.ReadFullSize(builder.bytes, 0, builder.bytes.Length);
                        clientSocket.Send(builder.bytes);
                        fileLeft -= builder.bytes.Length;
                    }

                    if (fileLeft > 0)
                    {
                        fileStream.ReadFullSize(builder.bytes, 0, (int)fileLeft);
                        clientSocket.Send(builder.bytes, 0, (int)fileLeft, 0);
                    }
                }

                clientSocket.Close();
                selectControl.RemoveReceiveSocket(clientSocket);
            }
        }
Пример #2
0
        // Returns the request offset into the builder buffer
        public UInt32 Build(ByteBuilder builder, HttpClient client, Boolean keepAlive)
        {
            if (method == null)
            {
                throw new InvalidOperationException("The HttpRequest method must be set");
            }
            //
            // <METHOD> <resource> HTTP/1.1\r\n
            //
            builder.AppendAscii(method); // Todo: Should I verify that method is ascii beforehand?
            builder.AppendAscii(' ');
            if (!String.IsNullOrEmpty(resource))
            {
                builder.AppendAscii(resource); // Todo: Should I verify that resource is ascii beforehand?
            }
            else if (resourceAppender != null)
            {
                resourceAppender(builder);
            }
            else
            {
                throw new InvalidOperationException("The HttpRequest resource must be set");
            }
            builder.Append(VersionPart);
            //
            // Host: <host>[:<port>]
            //
            builder.Append(Http.HostHeaderPrefix);
            if (overrideHostHeader != null)
            {
                builder.AppendAscii(overrideHostHeader);
            }
            else
            {
                builder.AppendAscii(client.IPOrHost);
                if (client.Port != 80 || forcePortInHostHeader)
                {
                    builder.AppendAscii(':');
                    builder.AppendNumber(client.Port, 10);
                }
            }
            builder.Append(Http.Newline);
            //
            // Header: Content-Length
            //
            // TODO: when do I not need a Content-Length?
            UInt32 contentLengthOffset = UInt32.MaxValue;

            {
                Boolean hasContent;
                UInt32  contentLength;
                if (content.contentAsBytes != null)
                {
                    hasContent    = true;
                    contentLength = (UInt32)content.contentAsBytes.Length;
                }
                else if (content.contentAsString != null)
                {
                    hasContent    = true;
                    contentLength = content.contentAsStringEncoder.GetEncodeLength(content.contentAsString);
                }
                else if (content.contentAppender != null)
                {
                    hasContent    = true;
                    contentLength = UInt32.MaxValue; // Placeholder
                }
                else
                {
                    hasContent    = false;
                    contentLength = 0;
                }
                if (hasContent)
                {
                    builder.Append(Http.ContentLengthHeaderPrefix);
                    contentLengthOffset = builder.contentLength;
                    builder.AppendNumber(contentLength);
                    builder.Append(Http.Newline);
                    if (content.contentType != null)
                    {
                        builder.Append(Http.ContentTypeHeaderPrefix);
                        builder.AppendAscii(content.contentType);
                        builder.Append(Http.Newline);
                    }
                }
            }
            //
            // Header: Connection
            //
            if (keepAlive)
            {
                builder.Append(Http.ConnectionHeaderPrefix);
                builder.Append(Http.ConnectionKeepAlive);
                builder.Append(Http.Newline);
            }
            else
            {
                builder.Append(Http.ConnectionHeaderPrefix);
                builder.Append(Http.ConnectionClose);
                builder.Append(Http.Newline);
            }
            //
            // Extra Headers
            //
            if (extraHeaders != null)
            {
                builder.Append(extraHeaders);
            }
            if (extraHeadersAppender != null)
            {
                extraHeadersAppender(builder);
            }
            //
            // End of Headers \r\n\r\n
            //
            builder.Append(Http.Newline);
            //
            // Content
            //
            if (content.contentAsBytes != null)
            {
                builder.Append(content.contentAsBytes);
            }
            else if (content.contentAsString != null)
            {
                builder.Append(content.contentAsStringEncoder, content.contentAsString);
            }
            else if (content.contentAppender != null)
            {
                //
                // Get the content
                //
                var contentStart = builder.contentLength;
                content.contentAppender(builder);
                UInt32 contentLength = builder.contentLength - contentStart;
                // Patch the request with the new content length
                UInt32 shift; // Shift everything before Content-Length: value to the right
                if (contentLength == 0)
                {
                    builder.bytes[contentLengthOffset + 9] = (Byte)'0';
                    shift = 9; // Shift everything
                }
                else
                {
                    shift = 9;
                    var temp = contentLength;
                    while (true)
                    {
                        builder.bytes[contentLengthOffset + shift] = (Byte)('0' + (temp % 10));
                        temp = temp / 10;
                        if (temp == 0)
                        {
                            break;
                        }
                        shift--;
                    }
                }
                // Shift the beginning of the request to compensate for a smaller Content-Length
                if (shift > 0)
                {
                    var offset = contentLengthOffset - 1;
                    while (true)
                    {
                        builder.bytes[offset + shift] = builder.bytes[offset];
                        if (offset == 0)
                        {
                            break;
                        }
                        offset--;
                    }
                }
                return(shift);
            }
            return(0);
        }