예제 #1
0
        internal HttpStatusLine(SocketState hs)
        {
            string line;
            do
                line = hs.ReadAsciiLine().Trim(); while (line.Length == 0);

            string[] items = line.Split(sp, StringSplitOptions.RemoveEmptyEntries);

            // Note: the status line has three items: the HTTP protocol
            // version, the status code, and the reason phrase.
            // Only the reason phrase may be empty.
            if (items.Length < 2) {
                throw new HttpProtocolBroken("Unrecognized status line '" + line + "'");
            }

            ProtocolVersion = ParserHelper.ParseProtocolVersion(items[0]);

            string code = items[1];
            if (code.Length != 3 || char.IsDigit(code[0]) == false) {
                // we only test the first character
                throw new HttpProtocolBroken("Invalid status code '" + code + "'");
            }
            //string Reason = rest of the string; // we don't need it

            StatusCode = int.Parse(code);
            StatusLine = line;
        }
예제 #2
0
        internal HttpRequestLine(SocketState hs)
        {
            string line;
            do {
                line = hs.ReadAsciiLine().Trim();
            } while (line.Length == 0);

            string[] items = line.Split(sp, StringSplitOptions.RemoveEmptyEntries);

            if (items.Length != 3) {
                throw new HttpProtocolBroken("Unrecognized request line '" + line + "'");
            }

            RequestLine = line;
            Method = items[0];
            URI = items[1];
            URL = items[1];
            ProtocolVersion = ParserHelper.ParseProtocolVersion(items[2]);
        }
예제 #3
0
 public QTransfer(SocketState state)
 {
     BrowserSocket = state;
     RemoteSocket  = null;
 }
예제 #4
0
파일: SocketState.cs 프로젝트: Mexahoid/CSF
        /* Helper function */
        private void TunnelChunkedDataTo(SocketState dest, MessagePacketHandler mph)
        {
            // (RFC 2616, sections 3.6.1, 19.4.6)
            while (true) {
                string chunk_header = ReadAsciiLine();
                if (chunk_header.Length == 0) {
                    throw new HttpProtocolBroken("Expected chunk header missing");
                }
                int sc = chunk_header.IndexOfAny(c_ChunkSizeEnd);
                string hexa_size = sc > -1
                                       ? chunk_header.Substring(0, sc)
                                       : chunk_header;
                uint size;
                try {
                    size = Convert.ToUInt32(hexa_size, 16);
                }
                catch {
                    string s = chunk_header.Length > 20
                                   ? (chunk_header.Substring(0, 17) + "...")
                                   : chunk_header;
                    throw new HttpProtocolBroken(
                        "Could not parse chunk size in: " + s);
                }

                if (dest != null) {
                    dest.WriteAsciiLine(chunk_header);
                }
                if (size == 0) {
                    break;
                }
                TunnelDataTo(mph, size);
                // Read/write one more CRLF
                string new_line = ReadAsciiLine();
                Debug.Assert(new_line.Length == 0);
                if (dest != null) {
                    dest.WriteAsciiLine(new_line);
                }
            }
            string line;
            do {
                // Tunnel any trailing entity headers
                line = ReadAsciiLine();
                if (dest != null) {
                    dest.WriteAsciiLine(line);
                }
            } while (line.Length != 0);
        }
예제 #5
0
파일: SocketState.cs 프로젝트: Mexahoid/CSF
 /// <summary>
 ///     Read <c>nb_bytes</c> bytes from the socket,
 ///     and send it to the destination socket
 /// </summary>
 /// <returns>The number of bytes sent</returns>
 public uint TunnelDataTo(SocketState dest, uint nb_bytes)
 {
     return TunnelDataTo((b, o, s) => {
                             if (dest.WriteBinary(b, o, s) < s) {
                                 throw new IoBroken();
                             }
                         }, nb_bytes);
 }
예제 #6
0
파일: SocketState.cs 프로젝트: Mexahoid/CSF
        /// <summary>
        ///     Transfer data from this socket to the destination socket
        ///     until this socket closes
        /// </summary>
        /// <returns>The number of bytes sent</returns>
        public uint TunnelDataTo(SocketState dest)
        {
            uint total_sent = 0;

            try {
                if (AvailableData == 0) {
                    ReadRaw();
                }
                while (AvailableData > 0) {
                    uint sent = dest.WriteBinary(SocketBuffer, BufferPosition, AvailableData);
                    if (sent < AvailableData) {
                        throw new IoBroken();
                    }
                    total_sent += sent;
                    ReadRaw();
                }
            }
            catch (SocketException) {
                /* ignore */
            }

            return total_sent;
        }
예제 #7
0
파일: SocketState.cs 프로젝트: Mexahoid/CSF
 /// <summary>
 ///     Tunnel a HTTP-chunked blob of data
 /// </summary>
 /// <param name="dest">The destination socket</param>
 /// <remarks>
 ///     The tunneling stops when the last chunk, identified by a
 ///     size of 0, arrives. The optional trailing entities are also
 ///     transmitted (but otherwise ignored).
 /// </remarks>
 public void TunnelChunkedDataTo(SocketState dest)
 {
     TunnelChunkedDataTo(dest, (buffer, offset, size) => {
                                   if (dest.WriteBinary(buffer, offset, size) < size) {
                                       throw new IoBroken();
                                   }
                               });
 }
예제 #8
0
파일: QServer.cs 프로젝트: Mexahoid/CSF
        /// <summary>
        ///     Callback method for accepting new connections
        /// </summary>
        private void AcceptCallback(IAsyncResult ar)
        {
            if (listeningThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId) {
                new Thread(() => AcceptCallback(ar)).Start();
                return;
            }

            if (IsShuttingDown) {
                return;
            }

            // Get the socket that handles the client request
            var listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            // Signal the main thread to continue
            listenThreadSwitch.Set();

            // Create the state object
            var state = new SocketState(handler);
            state.guid = Guid.NewGuid();

            lock (ConnectedSockets) {
                ConnectedSockets[state.guid] = state;
            }

            QTransfer transfer = null;
            try {
                transfer = new QTransfer(state);
                transfer.OnReceiveRequest = OnReceiveRequest;
                transfer.OnReceiveResponse = OnReceiveResponse;
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
            if (transfer == null) {
                CloseSocket(state);
                return;
            }

            // No need for asynchronous I/O from now on
            try {
                while (transfer.LogicLoop()) {
                    if (IsShuttingDown || state.IsSocketDead()) {
                        break;
                    }
                }
            }
            catch (SocketException) {
                /* ignore */
            }
            catch (IoBroken) {
                /* ignore */
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
                Console.WriteLine("Closing socket on error");
            }

            CloseSocket(state);
        }
예제 #9
0
 internal void SendTo(SocketState hs)
 {
     hs.WriteAsciiLine(RequestLine);
 }
예제 #10
0
파일: QTransfer.cs 프로젝트: Mexahoid/CSF
        /// <summary>
        ///     If necessary, connect the remote <c>RemoteSocket</c> socket
        ///     to the given host and port
        /// </summary>
        /// <param name="hostname">Remote host name</param>
        /// <param name="port">Remote port</param>
        /// <remarks>
        ///     If RemoteSocket is already connected to the right host and port,
        ///     the socket is reused as is.
        /// </remarks>
        protected void Connect(string hostname, int port)
        {
            Debug.Assert(!String.IsNullOrEmpty(hostname));
            Debug.Assert(port > 0);

            if (DestinationHostName != null &&
                DestinationHostName.Equals(hostname) &&
                DestinationPort == port &&
                (RemoteSocket != null && !RemoteSocket.IsSocketDead())) {
                // Nothing to do, just reuse the socket
                return;
            }

            if (RemoteSocket != null) {
                // We have a socket connected to the wrong host (or port)
                RemoteSocket.CloseSocket();
                RemoteSocket = null;
            }

            IPAddress[] ips = Dns.GetHostAddresses(hostname);
            Socket socket = null;
            Exception e = null;
            foreach (var ip in ips) {
                try {
                    socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    socket.Connect(ip, port);
                    break;
                }
                catch (Exception ee) {
                    if (ip.Equals(IPAddress.IPv6Loopback)) {
                        // Do not log that
                        continue;
                    }
                    if (e == null) {
                        e = ee;
                    }
                    if (socket != null) {
                        socket.Close();
                        socket = null;
                    }
                }
            }
            if (socket == null) {
                throw e;
            }

            // Checked up, and good to go
            RemoteSocket = new SocketState(socket);
            DestinationHostName = hostname;
            DestinationPort = port;
        }
예제 #11
0
파일: QTransfer.cs 프로젝트: Mexahoid/CSF
 /// <summary>
 ///     Pipeline step: close the connections and stop
 /// </summary>
 protected void AbortRequest()
 {
     if (RemoteSocket != null) {
         RemoteSocket.CloseSocket();
         RemoteSocket = null;
     }
     State.PersistConnectionBrowserSocket = false;
     State.NextStep = null;
 }
예제 #12
0
파일: QTransfer.cs 프로젝트: Mexahoid/CSF
 public QTransfer(SocketState state)
 {
     BrowserSocket = state;
     RemoteSocket = null;
 }
예제 #13
0
        /// <summary>
        ///     Callback method for accepting new connections
        /// </summary>
        private void AcceptCallback(IAsyncResult ar)
        {
            if (listeningThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId)
            {
                new Thread(() => AcceptCallback(ar)).Start();
                return;
            }

            if (IsShuttingDown)
            {
                return;
            }

            // Get the socket that handles the client request
            var    listener = (Socket)ar.AsyncState;
            Socket handler  = listener.EndAccept(ar);

            // Signal the main thread to continue
            listenThreadSwitch.Set();

            // Create the state object
            var state = new SocketState(handler);

            state.guid = Guid.NewGuid();

            lock (ConnectedSockets) {
                ConnectedSockets[state.guid] = state;
            }

            QTransfer transfer = null;

            try {
                transfer = new QTransfer(state);
                transfer.OnReceiveRequest  = OnReceiveRequest;
                transfer.OnReceiveResponse = OnReceiveResponse;
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
            if (transfer == null)
            {
                CloseSocket(state);
                return;
            }

            // No need for asynchronous I/O from now on
            try {
                while (transfer.LogicLoop())
                {
                    if (IsShuttingDown || state.IsSocketDead())
                    {
                        break;
                    }
                }
            }
            catch (SocketException) {
                /* ignore */
            }
            catch (IoBroken) {
                /* ignore */
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
                Console.WriteLine("Closing socket on error");
            }

            CloseSocket(state);
        }
예제 #14
0
 internal void SendTo(SocketState hs)
 {
     hs.WriteAsciiLine(StatusLine);
 }
예제 #15
0
 internal void SendTo(SocketState hs)
 {
     hs.WriteAsciiLine(StatusLine);
 }
예제 #16
0
        /// <summary>
        ///     Read and parse HTTP headers from a connected socket
        /// </summary>
        public HttpHeaders(SocketState source)
            : this()
        {
            var sb = new StringBuilder(512);

            while (true)
            {
                var line = source.ReadAsciiLine();
                if (line.Length == 0)
                {
                    break;
                }
                sb.Append(line);
                sb.Append("\r\n"); // Note: if the header newline was
                // incorrectly formatted (i.e. LF instead of CRLF),
                // we correct it here. This is one point where our
                // proxy is not fully transparent.

                var iSplit = line.IndexOf(':');
                if (iSplit <= 0)
                {
                    throw new HttpProtocolBroken("No colon in HTTP header");
                }

                // Header names are case-insensitive, but only some header
                // values are.
                string HeaderName  = line.Substring(0, iSplit).Trim().ToLower();
                string HeaderValue = line.Substring(iSplit + 1).Trim();
                if (IsHeaderValueCaseInsensitive(HeaderName))
                {
                    HeaderValue = HeaderValue.ToLower();
                }

                string previous_value;
                if (Headers.TryGetValue(HeaderName, out previous_value))
                {
                    // Duplicate headers: concatenate them
                    // (RFC 2616, section 4.2)

                    // However, this should only occur if the value of that
                    // header is a comma-separated list. In the real world,
                    // it has been observed that headers with
                    // non-comma-separated values, such as Content-Length, *are*
                    // in some rare cases repeated, so we should not concatenate
                    // the values.
                    if (HeaderName.Equals("content-length") == false)
                    {
                        Headers[HeaderName] = previous_value + "," + HeaderValue;
                    }
                }
                else
                {
                    Headers[HeaderName] = HeaderValue;
                }
            }

            HeadersInOrder = sb.ToString();

            // Parse a subset of the header values.
            // If headers are added, don't forget to update RemoveHeader
            // as well.
            Connection       = ParseMultipleStringValues("connection");
            ContentEncoding  = ParseStringValue("content-encoding");
            ContentLength    = ParseIntValue("content-length");
            Host             = ParseStringValue("host");
            ProxyConnection  = ParseMultipleStringValues("proxy-connection");
            Referer          = ParseStringValue("referer");
            TransferEncoding = ParseMultipleStringValues("transfer-encoding");
        }
예제 #17
0
파일: QTransfer.cs 프로젝트: Mexahoid/CSF
        private void CallOnReceiveResponse(string responseMessageChunked)
        {
            var transferItem = new TransferItem();
            transferItem.Headers = ResponseHeaders;
            transferItem.HttpRequestLine = RequestLine;
            transferItem.ResponseStatusLine = ResponseStatusLine;
            transferItem.BrowserSocket = BrowserSocket;
            transferItem.RemoteSocket = RemoteSocket;
            transferItem.State = State;
            transferItem.Response = GetResponse(responseMessageChunked);
            OnReceiveResponse(transferItem);

            if (State.PersistConnectionRemoteSocket == false && RemoteSocket != null) {
                RemoteSocket.CloseSocket();
                RemoteSocket = null;
            }

            State.NextStep = null;
        }
예제 #18
0
 internal void SendTo(SocketState hs)
 {
     hs.WriteAsciiLine(RequestLine);
 }
예제 #19
0
파일: QServer.cs 프로젝트: Mexahoid/CSF
        /// <summary>
        ///     Remove the socket contained in the given state object
        ///     from the connected array list and hash table, then close the
        ///     socket
        /// </summary>
        protected virtual void CloseSocket(SocketState state)
        {
            lock (ConnectedSockets) {
                SocketState actual_state;
                if (ConnectedSockets.TryGetValue(state.guid, out actual_state) == false) {
                    return;
                }

                Debug.Assert(actual_state == state);
                ConnectedSockets.Remove(state.guid);
            }

            state.CloseSocket();
        }