Пример #1
0
        /// <summary>
        /// Sets up the socket reader to read the Content of the HTTP request
        /// </summary>
        private void SetUpReadingContent()
        {
            ContentLength = long.Parse(WebConnection.Headers["CONTENT-LENGTH"]);

            if (ContentLength <= WebServer.MaxInMemoryContentSize)
                Content = new AsyncWebConnectionContent.InMemory(ContentLength);
            else if (ContentLength <= WebServer.MaxContentSize)
                Content = new AsyncWebConnectionContent.OnDisk();
            else
            {
                Close(WebResults.FromString(Status._413_Request_Entity_Too_Large, "Too much data, max size: " + WebServer.MaxContentSize.ToString()));
                return;
            }

            // TODO: get rid of this
            /*if (BufferBytesRead > 4)
                if (Encoding.UTF8.GetString(Buffer).StartsWith("POST"))
                    System.Diagnostics.Debugger.Break();*/

            // Give the reader the additional read bytes

            if (BufferBytesRead >= ContentLength)
            {
                byte[] toCopy = new byte[ContentLength];
                Array.Copy(Buffer, 0, toCopy, 0, toCopy.Length);

                Content.TakeBytes(toCopy);

                if (BufferBytesRead == ContentLength)
                    BufferBytesRead = 0;
                else
                {
                    byte[] oldBuffer = Buffer;
                    Buffer = new byte[oldBuffer.Length];

                    Array.Copy(oldBuffer, ContentLength, Buffer, 0, BufferBytesRead - ContentLength);

                    BufferBytesRead = Convert.ToInt32(Convert.ToInt64(BufferBytesRead) - ContentLength);
                }

                DoIO = NoOp;
                WebConnectionIOState = WebConnectionIOState.PerformingRequest;

                PerformRequest();
            }
            else if (0 == BufferBytesRead)
            {
                ReadStartTime = DateTime.UtcNow;

                WebConnectionIOState = WebConnectionIOState.ReadingContent;
                DoIO = ReadContent;

                //StartReadingSocket();
            }
            else // Buffer has less bytes then what's needed
            {
                byte[] toCopy = new byte[BufferBytesRead];

                Array.Copy(Buffer, 0, toCopy, 0, BufferBytesRead);
                Content.TakeBytes(toCopy);

                BufferBytesRead = 0;

                ReadStartTime = DateTime.UtcNow;

                WebConnectionIOState = WebConnectionIOState.ReadingContent;
                DoIO = ReadContent;

                //StartReadingSocket();
            }
        }
Пример #2
0
        /// <summary>
        /// Handles when the results are sent.  This even works with non-blocking long-polling!
        /// </summary>
        void WebConnection_ResultsSent()
        {
            WebConnection.ResultsSent -= new GenericVoid(WebConnection_ResultsSent);

            if (null != Content)
            {
                Content.Dispose();
                Content = null;
            }

            if (!WebServer.KeepAlive)
                Close();
            else
            {
                /*if (BufferBytesRead > 0)
                {
                    // If there is a complete header in the buffer, use it before switching to the ReadingHeader mode
                    HeaderEnd = Array<byte>.IndexOf(
                        Buffer,
                        HeaderEndMarker,
                        0,
                        BufferBytesRead);

                    if (-1 != HeaderEnd)
                    {
                        WebConnectionIOState = WebConnectionIOState.ParsingHeader;
                        DoIO = NoOp;
                        HandleHeader();

                        return;
                    }
                }*/

                WebConnectionIOState = WebConnectionIOState.ReadingHeader;
                DoIO = ReadHeader;
                //StartReadingSocket();
            }
        }
Пример #3
0
        /// <summary>
        /// Called when the header is completely loaded
        /// </summary>
        /// <param name="socketReader"></param>
        private void PerformRequest()
        {
            WebConnectionIOState = WebConnectionIOState.PerformingRequest;
            DoIO = NoOp;

            WebConnection.ResultsSent += new GenericVoid(WebConnection_ResultsSent);

            //WebConnection.HandleConnection(Content);

            ThreadPool.QueueUserWorkItem(delegate(object wcc)
            {
                WebConnection.HandleConnection((IWebConnectionContent)wcc);
            },
            Content);

            /*Thread subThread = new Thread(delegate()
            {
                WebConnection.HandleConnection(Content);
                Thread.Sleep(TimeSpan.FromMinutes(5));
            });
            subThread.Start();*/
        }
Пример #4
0
        /// <summary>
        /// Callback for when there's incoming data on the socket
        /// </summary>
        /// <param name="ar"></param>
        private void ReadCallback(IAsyncResult ar)
        {
            #if DEBUG
            //ThreadIds.Add(Thread.CurrentThread.ManagedThreadId);
            #endif

            if (!Socket.Connected)
            {
                WebConnectionIOState = WebConnectionIOState.Disconnected;
                return;
            }

            try
            {
                ReadingSocket = false;

                int read = Socket.EndReceive(ar);

                if (read > 0)
                {
                    //log.Trace("Contents recieved:\n" + Encoding.UTF8.GetString(Buffer, BufferBytesRead, read));

                    BufferBytesRead = BufferBytesRead + read;

                    /*if (Encoding.UTF8.GetString(Buffer).StartsWith("POST /TestLargeTextFile"))
                        if (System.Diagnostics.Debugger.IsAttached)
                            System.Diagnostics.Debugger.Break();*/

            #if DEBUG
                    DoIOName = DoIO.Method.Name;
                    Read = read;
            #endif

                    DoIO();
                }

                //if (BufferBytesRead < Buffer.Length)

                while (Buffer.Length == BufferBytesRead)
                    Thread.Sleep(5);

                StartReadingSocket();
            }
            catch (Exception e)
            {
                log.Error("Error when reading from a socket", e);

                // Attempt to gracefully close the socket
                try
                {
                    Close(WebResults.FromString(Status._500_Internal_Server_Error, "An unhandled error occured"));
                }
                catch { }
            }
        }
Пример #5
0
        /// <summary>
        /// Instructs the object to read a bit of the header
        /// </summary>
        /// <returns></returns>
        public void ReadHeader()
        {
            HeaderEnd = Array<byte>.IndexOf(
                    Buffer,
                    HeaderEndMarker,
                    0,
                    BufferBytesRead);

                // If the header end is found, then stop reading the socket and start handling the connection
                if (-1 != HeaderEnd)
                {
                    WebConnectionIOState = WebConnectionIOState.ParsingHeader;
                    DoIO = NoOp;

                    HandleHeader();
                }

                else if (BufferBytesRead == WebServer.HeaderSize)
                    // The header is too long
                    Close(WebResults.FromString(Status._414_Request_URI_Too_Long, "Max header length: " + WebServer.HeaderSize.ToString()));

                else if (ReadStartTime + WebServer.HeaderTimeout < DateTime.UtcNow)
                    // The sending header timed out
                    Close(WebResults.FromString(Status._408_Request_Timeout, "Headers time out after: " + WebServer.HeaderTimeout.ToString()));

                //else
                    //StartReadingSocket();
        }
Пример #6
0
 /// <summary>
 /// Closes the socket reader, for all intents and purposes
 /// </summary>
 private void Close()
 {
     Socket.Close();
     WebConnectionIOState = WebConnectionIOState.Disconnected;
     DoIO = NoOp;
 }
Пример #7
0
        /// <summary>
        /// Sets up the socket reader to read the Content of the HTTP request
        /// </summary>
        private void SetUpReadingContent()
        {
            ContentLength = long.Parse(WebConnection.Headers["CONTENT-LENGTH"]);

            if (ContentLength <= WebServer.MaxInMemoryContentSize)
                Content = new WebConnectionContent.InMemory(ContentLength);
            else if (ContentLength <= WebServer.MaxContentSize)
                Content = new WebConnectionContent.OnDisk();
            else
            {
                Close(WebResults.From(Status._413_Request_Entity_Too_Large, "Too much data, max size: " + WebServer.MaxContentSize.ToString()));
                return;
            }

            if (BufferBytesRead >= ContentLength)
            {
                byte[] toCopy = new byte[ContentLength];
                Array.Copy(Buffer, 0, toCopy, 0, toCopy.Length);

                Content.TakeBytes(toCopy);

                if (BufferBytesRead == ContentLength)
                    BufferBytesRead = 0;
                else
                {
                    byte[] oldBuffer = Buffer;
                    Buffer = new byte[oldBuffer.Length];

                    Array.Copy(oldBuffer, ContentLength, Buffer, 0, BufferBytesRead - ContentLength);
                    //System.Buffer.BlockCopy(Buffer, Convert.ToInt32(ContentLength), Buffer, 0, Convert.ToInt32(BufferBytesRead - ContentLength));

                    BufferBytesRead = Convert.ToInt32(Convert.ToInt64(BufferBytesRead) - ContentLength);
                }

                WebConnectionIOState = WebConnectionIOState.PerformingRequest;

                PerformRequest();
                return;
            }
            else if (0 == BufferBytesRead)
            {
                ReadStartTime = DateTime.UtcNow;

                WebConnectionIOState = WebConnectionIOState.ReadingContent;
            }
            else // Buffer has less bytes then what's needed
            {
                byte[] toCopy = new byte[BufferBytesRead];

                Array.Copy(Buffer, 0, toCopy, 0, BufferBytesRead);
                Content.TakeBytes(toCopy);

                BufferBytesRead = 0;

                ReadStartTime = DateTime.UtcNow;

                WebConnectionIOState = WebConnectionIOState.ReadingContent;
            }

            ReadContent();
        }
Пример #8
0
        /// <summary>
        /// Asyncronous read for starting a new request
        /// </summary>
        /// <param name="result"></param>
        private void StartNewConnection(IAsyncResult result)
        {
            log.Trace("Incoming request on keepalive socket");

            try
            {
                BufferBytesRead += Socket.EndReceive(result);
            }
            catch { }

            WebConnectionIOState = WebConnectionIOState.ReadingHeader;

            try
            {
                Start();
            }
            // If there's an exception, it means the socket is disconnected.
            catch
            {
                WebConnectionIOState = WebConnectionIOState.Disconnected;
            }
        }
Пример #9
0
        /// <summary>
        /// Sends the stream to the browser.  This should be called on the same thread that owns this web connection
        /// </summary>
        /// <param name="stream"></param>
        private void SendToBrowserInt(Stream stream)
        {
            byte[] buffer = new byte[60000];
            DateTime sendEnd = DateTime.UtcNow.AddMinutes(5);

            using (stream)
                try
                {
                    if (Socket.Connected)
                    {
                        int bytesRead;
                        do
                        {
                            bytesRead = stream.Read(buffer, 0, buffer.Length);

                            int bytesSent = 0;

                            if (bytesRead > 0)
                                do
                                {
                                    if (DateTime.UtcNow > sendEnd)
                                    {
                                        log.Warn("Sending timed out");
                                        Close();
                                        return;
                                    }

                                    bytesSent += Socket.Send(buffer, bytesSent, bytesRead - bytesSent, SocketFlags.None);
                                }
                                while (bytesSent < bytesRead);

                        } while (bytesRead > 0);
                    }
                    else
                    {
                        log.Debug("Connection Dropped....");
                        return;
                    }

                    if (KeepAlive)
                    {
                        ReadStartTime = DateTime.UtcNow;

                        //WebConnectionIOState = WebConnectionIOState.ReadingHeader;
                        //Start();

                        // I currently syspect that going into Async mode between requests is causing weird delays and slowness

                        // If data is available, immediately start reading the header, else, end the thread and use a callback to restart it
                        if (Socket.Available > 0 || BufferBytesRead > 0)
                        {
                            WebConnectionIOState = WebConnectionIOState.ReadingHeader;

                            // Another thread is used because this method needs to be non-blocking
                            Start();
                        }

                        else
                        {
                            WebConnectionIOState = WebConnectionIOState.Idle;

                            // Set the timeout to the total header timeout
                            Socket.ReceiveTimeout = Convert.ToInt32(WebServer.HeaderTimeout.TotalMilliseconds);

                            try
                            {
                                Socket.BeginReceive(
                                    Buffer,
                                    0,
                                    Buffer.Length,
                                    SocketFlags.None,
                                    StartNewConnection,
                                    null);
                            }
                            // If there's an exception, it means the socket is disconnected.
                            catch
                            {
                                WebConnectionIOState = WebConnectionIOState.Disconnected;
                            }
                        }
                    }
                    else
                        Close();
                }
                catch (Exception e)
                {
                    log.Error("Error Occurred", e);
                    Close();
                }
                finally
                {
                    stream.Close();

                    if (null != Content)
                    {
                        Content.Dispose();
                        Content = null;
                    }
                }
        }
Пример #10
0
        /// <summary>
        /// Call for when the web connection is reading content
        /// </summary>
        /// <returns></returns>
        private void ReadContent()
        {
            while (true)
            {
                int bytesRead = Socket.Receive(Buffer, BufferBytesRead, Buffer.Length - BufferBytesRead, SocketFlags.None);

                if (0 == bytesRead)
                {
                    WebConnectionIOState = WebConnectionIOState.Disconnected;
                    Close();

                    return;
                }

                BufferBytesRead += bytesRead;

                if (Content.BytesRead + BufferBytesRead <= ContentLength)
                {
                    byte[] localBuffer = new byte[BufferBytesRead];
                    Array.Copy(Buffer, localBuffer, BufferBytesRead);

                    BufferBytesRead = 0;

                    Content.TakeBytes(localBuffer);
                }
                else
                {
                    // Additional data needs to stay on the buffer
                    byte[] localBuffer = new byte[ContentLength - Content.BytesRead];
                    Array.Copy(Buffer, localBuffer, localBuffer.Length);

                    byte[] oldBuffer = Buffer;
                    Buffer = new byte[oldBuffer.Length];
                    Array.Copy(oldBuffer, localBuffer.Length, Buffer, 0, BufferBytesRead - localBuffer.Length);
                    //System.Buffer.BlockCopy(Buffer, localBuffer.Length, Buffer, 0, BufferBytesRead - localBuffer.Length);

                    BufferBytesRead = BufferBytesRead - localBuffer.Length;

                    Content.TakeBytes(localBuffer);
                }

                // If the header end is found, then stop reading the socket and start handling the connection
                if (Content.BytesRead >= ContentLength)
                {
                    WebConnectionIOState = WebConnectionIOState.PerformingRequest;

                    PerformRequest();
                    return;
                }
                else if (ReadStartTime + WebServer.ContentTimeout < DateTime.UtcNow)
                {
                    // The sending header timed out

                    Content.Dispose();

                    WebConnectionIOState = WebConnectionIOState.Disconnected;

                    WebConnection.SendResults(WebResults.From(Status._408_Request_Timeout, "Content times out after: " + WebServer.HeaderTimeout.ToString()));
                    Socket.Close();

                    return;
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Closes the socket reader, for all intents and purposes
        /// </summary>
        internal void Close()
        {
            try
            {
                Socket.Shutdown(SocketShutdown.Both);
                Socket.Close();
            }
            catch { }

            WebConnectionIOState = WebConnectionIOState.Disconnected;

            WebServer.WebServerTerminating -= new EventHandler<EventArgs>(WebServer_WebServerTerminating);

            if (null != Closed)
                Closed(this, new EventArgs());
        }
Пример #12
0
        /// <summary>
        /// Instructs the object to read a bit of the header
        /// </summary>
        /// <returns></returns>
        public void ReadHeader()
        {
            #if DEBUG
            int headerHandled = 0;
            #endif

            while (true)
            {
                if (BufferBytesRead > HeaderEndMarker.Length)
                {
                    int headerEnd = Array<byte>.IndexOf(Buffer, HeaderEndMarker);

                    if (headerEnd != -1)
                    {
                        WebConnectionIOState = WebConnectionIOState.ParsingHeader;

            #if DEBUG
                        headerHandled++;
            #endif

                        HandleHeader(headerEnd);
                        return;
                    }
                }

                if (BufferBytesRead >= WebServer.HeaderSize)
                {
                    // The header is too long
                    Close(WebResults.From(Status._414_Request_URI_Too_Long, "Max header length: " + WebServer.HeaderSize.ToString()));
                    return;
                }

                else if (ReadStartTime + WebServer.HeaderTimeout < DateTime.UtcNow)
                {
                    // The sending header timed out
                    Close(WebResults.From(Status._408_Request_Timeout, "Headers time out after: " + WebServer.HeaderTimeout.ToString()));
                    return;
                }

                // If the header is incomplete, read more of it
                int bytesRead = Socket.Receive(Buffer, BufferBytesRead, Buffer.Length - BufferBytesRead, SocketFlags.None);

                if (0 == bytesRead)
                {
                    WebConnectionIOState = WebConnectionIOState.Disconnected;
                    Close();

                    return;
                }

                BufferBytesRead += bytesRead;
            }
        }
Пример #13
0
        /// <summary>
        /// Overall driver for watching the socket.  This is started on its own thread
        /// </summary>
        public void MonitorSocket()
        {
            try
            {
                // Timeout if the client takes a really long time to send bytes
                Socket.ReceiveTimeout = Convert.ToInt32(TimeSpan.FromSeconds(15).TotalMilliseconds);

                WebConnection = new WebConnection(WebServer, Socket.RemoteEndPoint, SendToBrowser);

                ReadHeader();
            }
            catch (ThreadAbortException)
            {
                Close();
            }
            // Exceptions that occur when a socket is closed are just swallowed; this keeps the logs clean
            catch (ObjectDisposedException)
            {
                WebConnectionIOState = WebConnectionIOState.Disconnected;
                Close();
            }
            catch (SocketException)// se)
            {
                //log.InfoFormat("Error when performing IO for a connection from {0}", se, RemoteEndPoint);

                WebConnectionIOState = WebConnectionIOState.Disconnected;
                Close();
            }
            catch (Exception e)
            {
                log.ErrorFormat("Fatal error when performing IO for a connection from {0}", e, RemoteEndPoint);

                WebConnectionIOState = WebConnectionIOState.Disconnected;
                Close();
            }
        }