Example #1
0
        /// <summary>
        ///     Establish secured connection to destination server.
        /// </summary>
        /// <param name="context">current request context</param>
        protected override void ConnectToServer(ProcessingContext context)
        {
            base.ConnectToServer(context);

            if (context.ServerStream == null)
            {
                throw new InvalidContextException("ServerStream");
            }

            if (context.ServerEndPoint == null)
            {
                throw new InvalidContextException("ServerEndPoint");
            }

            var sslServerStream = new SslStream(context.ServerStream, false, _certificateValidationCallback);
            sslServerStream.AuthenticateAsClient(context.ServerEndPoint.Host);
            context.ServerStream = sslServerStream;

            if (Logger.IsDebugEnabled)
            {
                Logger.DebugFormat("Server SSL connection established: {0}:{1}",
                    context.ServerEndPoint.Host,
                    context.ServerEndPoint.Port
                    );
            }
        }
Example #2
0
        public void Start(ProcessingContext context)
        {
            for (context.Stage = ProcessingStage.ReceiveRequest; context.Stage <= ProcessingStage.Completed; context.Stage++) {
                if (!_processingActions.ContainsKey(context.Stage)) {
                    continue;
                }

                var action = _processingActions[context.Stage];

                if (action == null) {
                    continue;
                }

                try {
                    action.Invoke(context);
                } catch (Exception ex) {
                    context.Exception = ex;
                    context.Stage = ProcessingStage.Completed;
                }
            }
        }
Example #3
0
        /// <summary>
        ///     Accept client connection, create <see cref="ProcessingContext" /> and <see cref="ProcessingContext.ClientStream" />
        ///     and start processing request.
        /// </summary>
        /// <param name="clientSocket">Socket opened by the client</param>
        public void HandleClient(Socket clientSocket)
        {
            Contract.Requires <ArgumentNullException>(clientSocket != null, "clientSocket");

            var context = new ProcessingContext
            {
                ClientSocket = clientSocket,
                ClientStream = new NetworkStream(clientSocket, true)
                {
                    ReadTimeout  = (Int32)ClientReadTimeout.TotalMilliseconds,
                    WriteTimeout = (Int32)ClientWriteTimeout.TotalMilliseconds
                }
            };

            _pipeline.Start(context);

            if (context.Exception != null)
            {
                var errorMessage = new StringBuilder("Request processing failed.").AppendLine();

                if (context.RequestHeader != null)
                {
                    errorMessage.AppendLine("Request:");
                    errorMessage.WriteHttpTrace(context.RequestHeader);
                }

                if (context.ResponseHeader != null)
                {
                    errorMessage.AppendLine("Response:");
                    errorMessage.WriteHttpTrace(context.ResponseHeader);
                }

                errorMessage.AppendLine("Exception:");
                errorMessage.AppendLine(context.Exception.ToString());

                Logger.Error(errorMessage.ToString());
            }
        }
Example #4
0
        /// <summary>
        ///     Resolve <see cref="ProcessingContext.ServerEndPoint" /> based on <see cref="ProcessingContext.RequestHeader" />,
        ///     establish connection to destination server and open <see cref="ProcessingContext.ServerStream" />.
        ///     <see cref="ProcessingContext.RequestHeader" /> should be defined.
        /// </summary>
        /// <param name="context">current request context</param>
        protected virtual void ConnectToServer(ProcessingContext context)
        {
            ContractUtils.Requires <ArgumentNullException>(context != null, "context");
            ContractUtils.Requires <InvalidContextException>(context.RequestHeader != null, "RequestHeader");

            context.ServerEndPoint = DnsUtils.ResolveRequestEndpoint(context.RequestHeader, _defaultPort);

            context.ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            {
                ReceiveTimeout = (int)ServerReadTimeout.TotalMilliseconds,
                SendTimeout    = (int)ServerWriteTimeout.TotalMilliseconds
            };

            context.ServerSocket.Connect(context.ServerEndPoint.Host, context.ServerEndPoint.Port);

            context.ServerStream = new NetworkStream(context.ServerSocket, true);

            OnLog(LogLevel.Debug,
                  "Connection Established: {0}:{1}",
                  context.ServerEndPoint.Host,
                  context.ServerEndPoint.Port
                  );
        }
Example #5
0
        /// <summary>
        ///     Send respose to <see cref="ProcessingContext.ClientStream" /> containing
        ///     <see cref="ProcessingContext.ResponseHeader" />
        ///     and rest of<see cref="ProcessingContext.ServerStream" />.
        ///     Expect <see cref="ProcessingContext.ServerStream" />, <see cref="ProcessingContext.ClientStream" /> and
        ///     <see cref="ProcessingContext.ResponseHeader" /> to be defined.
        /// </summary>
        /// <param name="context">current request context</param>
        protected virtual void SendResponse(ProcessingContext context)
        {
            ContractUtils.Requires <ArgumentNullException>(context != null, "context");
            ContractUtils.Requires <InvalidContextException>(context.ServerStream != null, "ServerStream");
            ContractUtils.Requires <InvalidContextException>(context.ResponseHeader != null, "ResponseHeader");
            ContractUtils.Requires <InvalidContextException>(context.ClientStream != null, "ClientStream");
            ContractUtils.Requires <InvalidContextException>(context.ServerSocket != null, "ServerSocket");

            var responseWriter = new HttpResponseWriter(context.ClientStream);

            try
            {
                responseWriter.Write(context.ResponseHeader, context.ServerStream, context.ServerSocket.Available);

                OnLog(LogLevel.Debug, "Response Sent. {0}", TraceUtils.GetHttpTrace(context.ResponseHeader));
            }
            catch (IOException ex)
            {
                if (ex.IsSocketException(SocketError.TimedOut))
                {
                    OnLog(LogLevel.Warn, "Request to remote server has timed out. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));

                    responseWriter.WriteGatewayTimeout();
                }
                else if (ex.IsSocketException(SocketError.ConnectionReset, SocketError.ConnectionAborted))
                {
                    OnLog(LogLevel.Debug, "Request Aborted. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else
                {
                    throw;
                }

                context.StopProcessing();
            }
        }
Example #6
0
        public void Start(ProcessingContext context)
        {
            for (context.Stage = ProcessingStage.ReceiveRequest; context.Stage <= ProcessingStage.Completed; context.Stage++)
            {
                if (!_processingActions.ContainsKey(context.Stage))
                {
                    continue;
                }

                var action = _processingActions[context.Stage];

                if (action == null)
                {
                    continue;
                }

                try {
                    action.Invoke(context);
                } catch (Exception ex) {
                    context.Exception = ex;
                    context.Stage     = ProcessingStage.Completed;
                }
            }
        }
Example #7
0
        /// <summary>
        ///     Establish secured connection with client and receive HTTP request using it.
        /// </summary>
        /// <param name="context">current request context</param>
        protected override void ReceiveRequest(ProcessingContext context)
        {
            base.ReceiveRequest(context);

            if (context.RequestHeader == null)
            {
                throw new InvalidOperationException("Not SSL request");
            }

            if (context.RequestHeader.MethodType != RequestMethodTypes.CONNECT)
            {
                throw new InvalidContextException("RequestHeader");
            }

            if (context.ClientStream == null)
            {
                throw new InvalidContextException("ClientStream");
            }

            var responseWriter = new HttpResponseWriter(context.ClientStream);

            var sslStream = new SslStream(context.ClientStream, false, _certificateValidationCallback);

            try
            {
                responseWriter.WriteConnectionEstablished();

                sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls, false);

                context.ClientStream = sslStream;

                if (Logger.IsDebugEnabled)
                {
                    Logger.Debug("Client SSL connection established");
                }

                base.ReceiveRequest(context);
            }
            catch (IOException ex)
            {
                context.StopProcessing();

                if (SocketUtils.IsSocketException(ex, SocketError.ConnectionReset, SocketError.ConnectionAborted))
                {
                    if (Logger.IsDebugEnabled)
                    {
                        Logger.Debug("Request aborted");
                    }
                }
                else
                {
                    Logger.Error("Failed to read request", ex);
                    Logger.Error(context.RequestHeader);

                    throw;
                }
            }
        }
Example #8
0
        /// <summary>
        ///     Establish secured connection with client and receive HTTP request using it.
        /// </summary>
        /// <param name="context">current request context</param>
        protected override void ReceiveRequest(ProcessingContext context)
        {
            base.ReceiveRequest(context);

            if (context.Processed)
            {
                return;
            }

            if (context.RequestHeader == null)
            {
                throw new InvalidContextException("RequestHeader");
            }

            if (context.RequestHeader.MethodType != RequestMethodTypes.CONNECT)
            {
                throw new InvalidOperationException("Not SSL request");
            }

            if (context.ClientStream == null)
            {
                throw new InvalidContextException("ClientStream");
            }

            var responseWriter = new HttpResponseWriter(context.ClientStream);

            var sslStream = new SslStream(context.ClientStream, false, _certificateValidationCallback);

            try
            {
                responseWriter.WriteConnectionEstablished();
                sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls, false);
                context.ClientStream = sslStream;

                base.ReceiveRequest(context);
            }
            catch (IOException ex)
            {
                if (ex.IsSocketException(SocketError.ConnectionReset, SocketError.ConnectionAborted))
                {
                    Logger.WarnFormat("Request Aborted. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else if(ex.IsSocketException(SocketError.TimedOut))
                {
                    Logger.WarnFormat("Client request time out. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else
                {
                    throw;
                }

                context.StopProcessing();
            }
        }
Example #9
0
        /// <summary>
        ///     Send respose to <see cref="ProcessingContext.ClientStream" /> containing
        ///     <see cref="ProcessingContext.ResponseHeader" />
        ///     and rest of<see cref="ProcessingContext.ServerStream" />.
        ///     Expect <see cref="ProcessingContext.ServerStream" />, <see cref="ProcessingContext.ClientStream" /> and
        ///     <see cref="ProcessingContext.ResponseHeader" /> to be defined.
        /// </summary>
        /// <param name="context">current request context</param>
        protected virtual void SendResponse(ProcessingContext context)
        {
            Contract.Requires<ArgumentNullException>(context != null, "context");
            Contract.Requires<InvalidContextException>(context.ServerStream != null, "ServerStream");
            Contract.Requires<InvalidContextException>(context.ResponseHeader != null, "ResponseHeader");
            Contract.Requires<InvalidContextException>(context.ClientStream != null, "ClientStream");
            Contract.Requires<InvalidContextException>(context.ServerSocket != null, "ServerSocket");

            var responseWriter = new HttpResponseWriter(context.ClientStream);

            try
            {
                responseWriter.Write(context.ResponseHeader, context.ServerStream, context.ServerSocket.Available);

                if (Logger.IsDebugEnabled)
                {
                    Logger.DebugFormat("Response Sent. {0}", TraceUtils.GetHttpTrace(context.ResponseHeader));
                }
            }
            catch (IOException ex)
            {
                if (ex.IsSocketException(SocketError.TimedOut))
                {
                    Logger.WarnFormat("Request to remote server has timed out. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));

                    responseWriter.WriteGatewayTimeout();
                }
                else if (ex.IsSocketException(SocketError.ConnectionReset, SocketError.ConnectionAborted))
                {
                    if (Logger.IsDebugEnabled)
                    {
                        Logger.DebugFormat("Request Aborted. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                    }
                }
                else
                {
                    throw;
                }

                context.StopProcessing();
            }
        }
Example #10
0
        /// <summary>
        ///     Read <see cref="ProcessingContext.RequestHeader" /> from <see cref="ProcessingContext.ClientStream" />.
        ///     <see cref="ProcessingContext.ClientStream" /> should be defined at this point.
        /// </summary>
        /// <param name="context">current request context</param>
        protected virtual void ReceiveRequest(ProcessingContext context)
        {
            Contract.Requires<ArgumentNullException>(context != null, "context");
            Contract.Requires<InvalidContextException>(context.ClientStream != null, "ClientStream");

            var headerReader = new HttpHeaderReader(new PlainStreamReader(context.ClientStream));

            try
            {
                context.RequestHeader = new HttpRequestHeader(headerReader.ReadHttpMessageHeader());

                if (Logger.IsDebugEnabled)
                {
                    Logger.DebugFormat("Request Received. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
            }
            catch (IOException ex)
            {
                if (ex.IsSocketException(SocketError.OperationAborted, SocketError.ConnectionReset))
                {
                    Logger.WarnFormat("Request was terminated by client. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else if (ex is EndOfStreamException)
                {
                    Logger.ErrorFormat("Failed to read request. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else if(ex.IsSocketException(SocketError.TimedOut))
                {
                    Logger.WarnFormat("Client request time out. {0}", TraceUtils.GetHttpTrace(context.RequestHeader));
                }
                else
                {
                    throw;
                }

                context.StopProcessing();
            }
        }
Example #11
0
        /// <summary>
        ///     Resolve <see cref="ProcessingContext.ServerEndPoint" /> based on <see cref="ProcessingContext.RequestHeader" />,
        ///     establish connection to destination server and open <see cref="ProcessingContext.ServerStream" />.
        ///     <see cref="ProcessingContext.RequestHeader" /> should be defined.
        /// </summary>
        /// <param name="context">current request context</param>
        protected virtual void ConnectToServer(ProcessingContext context)
        {
            Contract.Requires<ArgumentNullException>(context != null, "context");
            Contract.Requires<InvalidContextException>(context.RequestHeader != null, "RequestHeader");

            context.ServerEndPoint = DnsUtils.ResolveRequestEndpoint(context.RequestHeader, _defaultPort);

            context.ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            {
                ReceiveTimeout = (Int32) ServerReadTimeout.TotalMilliseconds,
                SendTimeout = (Int32) ServerWriteTimeout.TotalMilliseconds
            };

            context.ServerSocket.Connect(context.ServerEndPoint.Host, context.ServerEndPoint.Port);

            context.ServerStream = new NetworkStream(context.ServerSocket, true);

            if (Logger.IsDebugEnabled)
            {
                Logger.DebugFormat("Connection Established: {0}:{1}",
                    context.ServerEndPoint.Host,
                    context.ServerEndPoint.Port
                );
            }
        }
Example #12
0
        /// <summary>
        ///     Close client and server connections.
        ///     Expect <see cref="ProcessingContext.ClientStream" /> and <see cref="ProcessingContext.ServerStream" /> to be
        ///     defined.
        /// </summary>
        /// <param name="context"></param>
        protected virtual void CompleteProcessing(ProcessingContext context)
        {
            Contract.Requires<ArgumentNullException>(context != null, "context");

            if (context.ClientStream != null)
            {
                context.ClientStream.Close();
            }

            if (context.ServerStream != null)
            {
                context.ServerStream.Close();
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.DebugFormat("[{0}] processed", context.RequestHeader.StartLine);
            }
        }
Example #13
0
        /// <summary>
        ///     Accept client connection, create <see cref="ProcessingContext" /> and <see cref="ProcessingContext.ClientStream" />
        ///     and start processing request.
        /// </summary>
        /// <param name="clientSocket">Socket opened by the client</param>
        public void HandleClient(Socket clientSocket)
        {
            Contract.Requires<ArgumentNullException>(clientSocket != null, "clientSocket");

            var context = new ProcessingContext
            {
                ClientSocket = clientSocket,
                ClientStream = new NetworkStream(clientSocket, true)
                {
                    ReadTimeout = (Int32) ClientReadTimeout.TotalMilliseconds,
                    WriteTimeout = (Int32) ClientWriteTimeout.TotalMilliseconds
                }
            };

            _pipeline.Start(context);

            if (context.Exception != null)
            {
                var errorMessage = new StringBuilder("Request processing failed.").AppendLine();

                if (context.RequestHeader != null)
                {
                    errorMessage.AppendLine("Request:");
                    errorMessage.WriteHttpTrace(context.RequestHeader);
                }

                if (context.ResponseHeader != null)
                {
                    errorMessage.AppendLine("Response:");
                    errorMessage.WriteHttpTrace(context.ResponseHeader);
                }

                errorMessage.AppendLine("Exception:");
                errorMessage.AppendLine(context.Exception.ToString());

                Logger.Error(errorMessage.ToString());
            }
        }