예제 #1
0
        private void SendGZipResponse(HeyHttpResponse response)
        {
            using (MemoryStream compressedStream = new MemoryStream())
            {
                using (GZipStream gzipStream = new GZipStream(compressedStream, CompressionMode.Compress))
                {
                    response.ContentStream.CopyTo(gzipStream);

                    // Not sure why, but gzip stream must be close before getting the data.
                    gzipStream.Close();

                    byte[] bytes = compressedStream.ToArray();

                    // Send response headers.
                    response.Headers.Add("Content-Encoding: gzip");
                    response.Headers.Add("Content-Length: " + bytes.Length);
                    response.Headers.Add("Content-Type: " + GetMediaType(request.Path));
                    response.CopyHeadersTo(networkStream);

                    //compressedStream.CopyTo(networkStream);
                    //networkStream.Flush();

                    // For debugging.
                    networkStream.Write(bytes, 0, bytes.Length);
                    logger.WriteBodyLine(BitConverter.ToString(bytes));
                }
            }
        }
예제 #2
0
        private static void Reply407AndClose(HeyLogger logger, NetworkStream clientStream)
        {
            HeyHttpResponse response = new HeyHttpResponse(logger);

            response.Version = "HTTP/1.0";
            response.Status  = "407 Proxy Authentication Required";
            response.Headers.Add("Proxy-agent: Netscape-Proxy/1.1");
            response.Headers.Add("Proxy-Authenticate: Basic realm=\"WallyWorld\"");
            response.Headers.Add("Content-Length: 0");
            response.Headers.Add("Connection: close");
            response.CopyHeadersTo(clientStream);
            clientStream.Close();
        }
예제 #3
0
        private static void OnAccept(IAsyncResult asyncResult)
        {
            HeyLogger logger         = new HeyLogger();
            Socket    socketListener = asyncResult.AsyncState as Socket;
            Socket    client         = socketListener.EndAccept(asyncResult);

            socketListener.BeginAccept(OnAccept, asyncResult.AsyncState);

            try
            {
                HeyHttpRequest request = new HeyHttpRequest(logger);

                // Client got connected.
                logger.WriteLine(String.Format("Connected: {0}", client.RemoteEndPoint));

                // Read HTTP headers.
                NetworkStream clientStream = new NetworkStream(client);
                MemoryStream  tempStream   = new MemoryStream();
                request.ReadHeaders(clientStream, tempStream);

                // Authentication.
                if (settings.AuthenticationRequired && !IsAuthenticated(request))
                {
                    Reply407AndClose(logger, clientStream);
                    return;
                }

                // Find server host name.
                logger.WriteLine(String.Format("Trying to connect to {0}", request.Host));

                // Get IP address for the given server hostname.
                IPHostEntry hostEntry = Dns.GetHostEntry(request.Host);
                if (hostEntry.AddressList.Length == 0)
                {
                    throw new Exception("Unknow server hostname.");
                }
                IPAddress address = hostEntry.AddressList[0];

                // Connect to server.
                Socket server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                server.Connect(new IPEndPoint(address, request.Port));

                logger.WriteLine(String.Format("Connected to {0}", request.Host));

                // Send cached data to server.
                NetworkStream serverStream = new NetworkStream(server);

                // When using the CONNECT method, proxy must send a HTTP response to client.
                // See "Tunneling TCP based protocols through Web proxy servers" internet-draft.
                if (request.Method == "CONNECT")
                {
                    HeyHttpResponse response = new HeyHttpResponse(logger);
                    response.Status = "200 Connection established";
                    response.Headers.Add("Proxy-agent: Happy-Sockets-Proxy/1.0");
                    response.CopyHeadersTo(clientStream);
                }
                else
                {
                    // Only forward headers when it is not a CONNECT request.
                    tempStream.Seek(0, SeekOrigin.Begin);
                    tempStream.CopyTo(serverStream);
                }

                // Forward data.
                ParameterizedThreadStart serverToClientStart = new ParameterizedThreadStart(ForwardData);
                Thread serverToClientThread = new Thread(serverToClientStart);
                serverToClientThread.Start(
                    new StreamsPair
                {
                    StreamA = serverStream,
                    StreamB = clientStream,
                    Label   = "server to client",
                    Logger  = logger
                });

                ParameterizedThreadStart clientToServerStart = new ParameterizedThreadStart(ForwardData);
                Thread clientToServerThread = new Thread(clientToServerStart);
                clientToServerThread.Start(
                    new StreamsPair
                {
                    StreamA = clientStream,
                    StreamB = serverStream,
                    Label   = "client to server",
                    Logger  = logger
                });

                //serverToClientThread.Join();
                //clientToServerThread.Join();

                // TODO: make sure streams do not go out of scope.
                // TODO: wait until threads end and ensure connections are close.
            }
            catch (SocketException ex)
            {
                WriteLine(ConsoleColor.Red, ex.Message);
                logger.WriteLine(ex.ToString());

                // We couldn't connect to the  server, terminate connection with the client.
                client.Close();
            }
            catch (IOException ex)
            {
                WriteLine(ConsoleColor.Red, ex.Message);
                logger.WriteLine(ex.ToString());

                // The client closed the connection, terminate the connection with the server.
                client.Close();
            }
            catch (Exception ex)
            {
                WriteLine(ConsoleColor.Red, ex.Message);
                logger.WriteLine(ex.ToString());
            }
        }
예제 #4
0
        private void SendChunkedResponse(HeyHttpResponse response)
        {
            Stream stream = response.ContentStream;

            // Send headers.
            response.Headers.Add("Transfer-Encoding: chunked");
            response.Headers.Add("Trailer: \"Foo\"");
            response.Headers.Add("Content-Type: " + GetMediaType(request.Path));
            response.CopyHeadersTo(networkStream);

            // Send a random amount of bytes.
            Random random = new Random();

            int bytesRead = 0;

            while (bytesRead < stream.Length)
            {
                byte[] buffer;
                int    chunkSize = random.Next(1, MaxChunckSize);

                if (stream.Length - bytesRead < chunkSize)
                {
                    chunkSize = (int)stream.Length - bytesRead;
                }

                // Send chunck size and CRLF.
                string chunkSizeString = String.Format("{0:X}\r\n", chunkSize);
                buffer = Encoding.ASCII.GetBytes(chunkSizeString);
                networkStream.Write(buffer, 0, buffer.Length);

                // Send chunck.
                buffer = new byte[chunkSize];
                int localBytesRead = stream.Read(buffer, 0, buffer.Length);
                networkStream.Write(buffer, 0, localBytesRead);

                // Send CRLF.
                buffer = Encoding.ASCII.GetBytes("\r\n");
                networkStream.Write(buffer, 0, buffer.Length);

                networkStream.Flush();

                bytesRead += localBytesRead;
                logger.WriteBodyLine(
                    String.Format("Chunk of {0,13:N0} bytes, {1,13:N0} of {2,13:N0} bytes sent.",
                                  chunkSize,
                                  bytesRead,
                                  stream.Length));

                Thread.Sleep(100);
            }

            StringBuilder theEnd = new StringBuilder();

            // Add last chunk.
            theEnd.Append("0\r\n");

            // Add trailer.
            theEnd.Append("Foo: Bar\r\n");

            // Add last CRLF.
            theEnd.Append("\r\n");

            byte[] lastChunkBuffer = Encoding.ASCII.GetBytes(theEnd.ToString());
            networkStream.Write(lastChunkBuffer, 0, lastChunkBuffer.Length);
        }
예제 #5
0
        private void SendSlowResponse(
            HeyHttpResponse response,
            int delayInMilliseconds,
            HttpResponseOption option)
        {
            Stream stream = response.ContentStream;

            long idleLength;

            if (!request.QueryStringHas("idleLength", out idleLength))
            {
                idleLength = -1;
            }

            // Calculate positions.

            long totalBytesRead = 0;
            long firstPosition  = 0;

            if (response.FirstPosition > 0)
            {
                firstPosition   = response.FirstPosition;
                stream.Position = firstPosition;
            }

            long length = response.ContentStream.Length;

            if (response.LastPosition > 0)
            {
                length = response.LastPosition - firstPosition + 1;
            }

            // Send headers.
            response.Headers.Add("Content-Length: " + length);
            response.Headers.Add("Content-Type: " + GetMediaType(request.Path));
            response.CopyHeadersTo(networkStream);

            // Server must not send a message body when using HEAD method (RFC 7231 4.3.2 HEAD).
            if (request.IsHeadMethod)
            {
                return;
            }

            // Calulate buffer size.
            int bufferLength;

            if (!request.QueryStringHas("bufferLength", out bufferLength))
            {
                bufferLength = 1000000; // 1 MB
            }
            byte[] buffer = new byte[bufferLength];

            while (totalBytesRead < length)
            {
                long remainingBytes = length - totalBytesRead;
                int  loopLength     = (int)Math.Min(bufferLength, remainingBytes);
                int  localBytesRead = stream.Read(buffer, 0, loopLength);

                if (option == HttpResponseOption.Pause)
                {
                    BlockThreadUntilEnterIsPressed();
                }

                if (option == HttpResponseOption.Slow)
                {
                    Thread.Sleep(delayInMilliseconds);
                }

                networkStream.Write(buffer, 0, localBytesRead);
                networkStream.Flush();

                totalBytesRead += localBytesRead;
                logger.WriteBodyLine(String.Format(
                                         "{0,13:N0} of {1,13:N0} bytes sent.",
                                         totalBytesRead,
                                         length));

                if (idleLength >= 0 && totalBytesRead >= idleLength)
                {
                    BlockThreadUntilClientIsDisconnected();
                }
            }

            logger.WriteBodyLine("Response completed!\r\n");
        }