private void SaveDataFrame(Http2Stream stream, DataFrame dataFrame)
        {
            string originalPath = stream.Headers.GetValue(CommonHeaders.Path.ToLower());
            //If user sets the empty file in get command we return notFound webpage
            string fileName = string.IsNullOrEmpty(Path.GetFileName(originalPath)) ? Index : Path.GetFileName(originalPath);
            string path     = Path.Combine(AssemblyPath, fileName);

            try
            {
                _fileHelper.SaveToFile(dataFrame.Data.Array, dataFrame.Data.Offset, dataFrame.Data.Count,
                                       path, stream.ReceivedDataAmount != 0);
            }
            catch (IOException)
            {
                Http2Logger.LogError("File is still downloading. Repeat request later");

                stream.Close(ResetStatusCode.InternalError);
                return;
            }

            stream.ReceivedDataAmount += dataFrame.Data.Count;

            if (dataFrame.IsEndStream)
            {
                if (stream.HalfClosedRemote)
                {
                    //send terminator
                    stream.WriteDataFrame(new ArraySegment <byte>(new byte[0]), true);
                    Http2Logger.LogConsole("Terminator was sent");
                }
                _fileHelper.RemoveStream(path);
                Http2Logger.LogConsole("Bytes received: " + stream.ReceivedDataAmount);
            }
        }
        public async void StartConnection()
        {
            Console.WriteLine("Start connection called");
            if (_useHttp20 && !_sessionAdapter.IsDisposed && !_isDisposed)
            {
                Dictionary <string, string> initialRequest = null;
                if (!_isSecure)
                {
                    initialRequest = new Dictionary <string, string>
                    {
                        { CommonHeaders.Path, _path },
                    };
                }

                await _sessionAdapter.StartSessionAsync(initialRequest);

                //GC.Collect();
            }

            if (!_sessionAdapter.IsDisposed)
            {
                return;
            }

            Http2Logger.LogError("Connection was aborted by the remote side. Check your session header.");
            Dispose(true);
        }
Exemple #3
0
        private void RequestSentHandler(object sender, RequestSentEventArgs args)
        {
            var stream = args.Stream;
            var method = stream.Headers.GetValue(":method");

            if (method == "put" || method == "post")
            {
                var    localPath    = stream.Headers.GetValue(":localPath".ToLower());
                byte[] binary       = null;
                bool   gotException = false;
                try
                {
                    binary = _fileHelper.GetFile(localPath);
                }
                catch (FileNotFoundException)
                {
                    gotException = true;
                    Http2Logger.LogError("Specified file not found: " + localPath);
                }
                if (!gotException)
                {
                    SendDataTo(args.Stream, binary);
                }
            }
        }
Exemple #4
0
 public async void StartConnection()
 {
     if (_useHttp20 && !_socket.IsClosed && !_isDisposed)
     {
         await _clientSession.Start();
     }
     else if (_socket.IsClosed || _isDisposed)
     {
         Http2Logger.LogError("Connection was aborted by the remote side. Check your session header.");
         Dispose(true);
     }
 }
Exemple #5
0
        private void SaveDataFrame(Http2Stream stream, DataFrame dataFrame)
        {
            lock (_writeLock)
            {
                string originalPath = stream.Headers.GetValue(":path".ToLower());
                //If user sets the empty file in get command we return notFound webpage
                string fileName = string.IsNullOrEmpty(Path.GetFileName(originalPath)) ? NotFound : Path.GetFileName(originalPath);
                string path     = Path.Combine(AssemblyPath, fileName);

                try
                {
                    _fileHelper.SaveToFile(dataFrame.Data.Array, dataFrame.Data.Offset, dataFrame.Data.Count,
                                           path, stream.ReceivedDataAmount != 0);
                }
                catch (IOException)
                {
                    Http2Logger.LogError("File is still downloading. Repeat request later");
                    stream.WriteDataFrame(new byte[0], true);
                    stream.Dispose();
                }

                stream.ReceivedDataAmount += dataFrame.FrameLength;

                if (dataFrame.IsEndStream)
                {
                    if (!stream.EndStreamSent)
                    {
                        //send terminator
                        stream.WriteDataFrame(new byte[0], true);
                        Http2Logger.LogConsole("Terminator was sent");
                    }
                    _fileHelper.RemoveStream(path);
                    Http2Logger.LogConsole("Bytes received " + stream.ReceivedDataAmount);
#if DEBUG
                    const string wayToServerRoot1 = @"..\..\..\..\..\Drop\Root";
                    const string wayToServerRoot2 = @".\Root";
                    var          areFilesEqual    = _fileHelper.CompareFiles(path, wayToServerRoot1 + originalPath) ||
                                                    _fileHelper.CompareFiles(path, wayToServerRoot2 + originalPath);
                    if (!areFilesEqual)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Http2Logger.LogError("Files are NOT EQUAL!");
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Http2Logger.LogConsole("Files are EQUAL!");
                    }
                    Console.ForegroundColor = ConsoleColor.Gray;
#endif
                }
            }
        }
Exemple #6
0
 public void ReadHeadersAndInspectHandshake()
 {
     try
     {
         _response            = Read11Headers();
         _wasResponseReceived = true;
     }
     catch (Exception ex)
     {
         Http2Logger.LogError(ex.Message);
         throw;
     }
 }
Exemple #7
0
        public HttpSocketServer(Func <IDictionary <string, object>, Task> next, IDictionary <string, object> properties)
        {
            _next = next;

            var addresses = (IList <IDictionary <string, object> >)properties[OwinConstants.CommonKeys.Addresses];

            var address = addresses.First();

            _port   = Int32.Parse(address.Get <string>("port"));
            _scheme = address.Get <string>("scheme");

            _useHandshake   = (bool)properties["use-handshake"];
            _usePriorities  = (bool)properties["use-priorities"];
            _useFlowControl = (bool)properties["use-flowControl"];

            int securePort;

            try
            {
                securePort = int.Parse(ConfigurationManager.AppSettings["securePort"]);
            }
            catch (Exception)
            {
                Http2Logger.LogError("Incorrect port in the config file!" + ConfigurationManager.AppSettings["securePort"]);
                return;
            }

            if (_port == securePort && _scheme == Uri.UriSchemeHttp ||
                _port != securePort && _scheme == Uri.UriSchemeHttps)
            {
                Http2Logger.LogError("Invalid scheme or port! Use https for secure port.");
                return;
            }

            var extensions = new[] { ExtensionType.Renegotiation, ExtensionType.ALPN };

            // protocols should be in order of their priority
            _options = _port == securePort ? new SecurityOptions(SecureProtocol.Tls1, extensions, new[] { Protocols.Http2, Protocols.Http1 }, ConnectionEnd.Server)
                                : new SecurityOptions(SecureProtocol.None, extensions, new[] { Protocols.Http2, Protocols.Http1 }, ConnectionEnd.Server);

            _options.VerificationType  = CredentialVerification.None;
            _options.Certificate       = Certificate.CreateFromCerFile(AssemblyName + CertificateFilename);
            _options.Flags             = SecurityFlags.Default;
            _options.AllowedAlgorithms = SslAlgorithms.RSA_AES_256_SHA | SslAlgorithms.NULL_COMPRESSION;

            _server = new SecureTcpListener(_port, _options);

            ThreadPool.SetMaxThreads(30, 10);

            Listen();
        }
Exemple #8
0
        public static void Http11SendResponse(SecureSocket socket)
        {
            string[] headers  = GetHttp11Headers(socket);
            string   filename = GetFileName(headers);


            if (headers.Length == 0)
            {
                Http2Logger.LogError("Request headers empty!");
            }

            string path        = Path.GetFullPath(AssemblyPath + @"\root" + filename);
            string contentType = ContentTypes.GetTypeFromFileName(filename);

            if (!File.Exists(path))
            {
                Http2Logger.LogError("File " + filename + " not found");
                SendResponse(socket, new byte[0], StatusCode.Code404NotFound, contentType);
                socket.Close();
                return;
            }

            try
            {
                using (var sr = new StreamReader(path))
                {
                    string file = sr.ReadToEnd();

                    var fileBytes = Encoding.UTF8.GetBytes(file);

                    int sent = SendResponse(socket, fileBytes, StatusCode.Code200Ok, contentType);
                    Http2Logger.LogDebug(string.Format("Sent: {0} bytes", sent));
                    Http2Logger.LogInfo("File sent: " + filename);

                    socket.Close();

                    if (OnSocketClosed != null)
                    {
                        OnSocketClosed(null, new SocketCloseEventArgs());
                    }
                }
            }
            catch (Exception ex)
            {
                var msgBytes = Encoding.UTF8.GetBytes(ex.Message);
                SendResponse(socket, msgBytes, StatusCode.Code500InternalServerError, contentType);
                Http2Logger.LogError(ex.Message);
            }
        }
Exemple #9
0
 /// <summary>
 /// Pumps the outgoing data to write queue
 /// </summary>
 /// <returns></returns>
 private Task PumpOutgoingData()
 {
     return(Task.Run(() =>
     {
         try
         {
             _writeQueue.PumpToStream();
         }
         catch (Exception)
         {
             Http2Logger.LogError("Sending frame was cancelled because connection was lost");
             Dispose();
         }
     }));
 }
        private async void OpenHttp2Session(SecureSocket incomingClient, IDictionary <string, object> handshakeResult)
        {
            Http2Logger.LogDebug("Handshake successful");
            _session = new Http2Session(incomingClient, ConnectionEnd.Server, _usePriorities, _useFlowControl, handshakeResult);
            _session.OnFrameReceived += FrameReceivedHandler;

            try
            {
                await _session.Start();
            }
            catch (Exception)
            {
                Http2Logger.LogError("Client was disconnected");
            }
        }
Exemple #11
0
 private void Listen()
 {
     InitializeRootFileList();
     Http2Logger.LogInfo("Started on port " + _port);
     _server.Start();
     while (!_disposed)
     {
         try
         {
             var client = new HttpConnectingClient(_server, _options, _next, _useHandshake, _usePriorities, _useFlowControl, _listOfRootFiles);
             client.Accept();
         }
         catch (Exception ex)
         {
             Http2Logger.LogError("Unhandled exception was caught: " + ex.Message);
         }
     }
 }
Exemple #12
0
        private async void OpenHttp2Session(Stream incomingClientStream)
        {
            Http2Logger.LogDebug("Handshake successful");
            using (var messageHandler = new Http2OwinMessageHandler(incomingClientStream, ConnectionEnd.Server,
                                                                    incomingClientStream is SslStream, _next,
                                                                    _cancelClientHandling.Token))
            {
                try
                {
                    await messageHandler.StartSessionAsync();
                }
                catch (Exception)
                {
                    Http2Logger.LogError("Client was disconnected");
                }
            }

            // GC.Collect();
        }
Exemple #13
0
        /// <summary>
        /// Inspect if request if http2 upgrade
        /// If so starts http2 session via provider.
        /// Calls next layer if not.
        /// </summary>
        /// <returns></returns>
        public override async Task Invoke(IOwinContext context)
        {
            if (IsOpaqueUpgradePossible(context.Request) && IsRequestForHttp2Upgrade(context.Request))
            {
                var upgradeDelegate = context.Environment[CommonOwinKeys.OpaqueUpgrade] as UpgradeDelegate;
                Debug.Assert(upgradeDelegate != null, "upgradeDelegate is not null");

                // save original request parameters; used to complete request after upaque upgrade is done
                var requestCopy = GetInitialRequestParams(context.Request);

                upgradeDelegate.Invoke(new Dictionary <string, object>(), async opaque =>
                {
                    //use the same stream which was used during upgrade
                    var opaqueStream = opaque.Environment[CommonOwinKeys.OpaqueStream] as Stream;

                    //TODO Provide cancellation token here
                    // Move to method
                    try
                    {
                        using (var http2MessageHandler = new Http2OwinMessageHandler(opaqueStream,
                                                                                     ConnectionEnd.Server,
                                                                                     opaqueStream is SslStream,
                                                                                     Next.Invoke, CancellationToken.None)
                               )
                        {
                            await http2MessageHandler.StartSessionAsync(requestCopy);
                            // GC.Collect();
                        }
                    }
                    catch (Exception ex)
                    {
                        Http2Logger.LogError(ex.Message);
                    }
                });

                // specify Upgrade protocol
                context.Response.Headers.Add(CommonHeaders.Upgrade, new[] { Protocols.Http2NoTls });
                return;
            }

            //If we dont have upgrade delegate then pass request to the next layer
            await Next.Invoke(context);
        }
Exemple #14
0
        /// <summary>
        /// Pumps the outgoing data to write queue
        /// </summary>
        /// <returns></returns>
        private void PumpOutgoingData()
        {
            try
            {
                _writeQueue.PumpToStream(_cancelSessionToken);
            }
            catch (OperationCanceledException)
            {
                Http2Logger.LogError("Handling session was cancelled");
                Dispose();
            }
            catch (Exception)
            {
                Http2Logger.LogError("Sending frame was cancelled because connection was lost");
                Dispose();
            }

            Http2Logger.LogDebug("Write thread finished");
        }
Exemple #15
0
        public HttpSocketServer(Func <IOwinContext, Task> next, IDictionary <string, object> properties)
        {
            _next = next;
            var addresses = (IList <IDictionary <string, object> >)properties["host.Addresses"];

            var address = addresses.First();

            _port   = Int32.Parse(address.Get <string>("port"));
            _scheme = address.Get <string>("scheme");

            _cancelAccept = new CancellationTokenSource();

            _useHandshake   = (bool)properties["use-handshake"];
            _usePriorities  = (bool)properties["use-priorities"];
            _useFlowControl = (bool)properties["use-flowControl"];

            int securePort;

            if (!int.TryParse(ConfigurationManager.AppSettings["securePort"], out securePort))
            {
                Http2Logger.LogError("Incorrect port in the config file!");
                return;
            }

            try
            {
                _serverCert = LoadPKCS12Certificate(AssemblyName + CertificateFilename, "p@ssw0rd");
            }
            catch (Exception ex)
            {
                Http2Logger.LogInfo("Unable to start server. Check certificate. Exception: " + ex.Message);
                return;
            }

            _isSecure = _port == securePort;

            _server = new TcpListener(IPAddress.Any, _port);

            ThreadPool.SetMaxThreads(30, 10);

            _listenThread = new Thread(Listen);
            _listenThread.Start();
        }
Exemple #16
0
        private void Listen()
        {
            Http2Logger.LogInfo("Server running at port " + _port);
            _server.Start();
            while (!_disposed)
            {
                try
                {
                    var client = new HttpConnectingClient(_server, _next.Invoke, _serverCert, _isSecure, _useHandshake, _usePriorities, _useFlowControl);
                    client.Accept(_cancelAccept.Token);
                }
                catch (Exception ex)
                {
                    Http2Logger.LogError("Unhandled exception was caught: " + ex.Message);
                }
            }

            Http2Logger.LogDebug("Listen thread was finished");
        }
        private void HandleRequest(SecureSocket incomingClient, string alpnSelectedProtocol,
                                   bool backToHttp11, IDictionary <string, object> handshakeResult)
        {
            if (backToHttp11 || alpnSelectedProtocol == Protocols.Http1)
            {
                Http2Logger.LogDebug("Sending with http11");
                Http11Manager.Http11SendResponse(incomingClient);
                return;
            }

            if (GetSessionHeaderAndVerifyIt(incomingClient))
            {
                OpenHttp2Session(incomingClient, handshakeResult);
            }
            else
            {
                Http2Logger.LogError("Client has wrong session header. It was disconnected");
                incomingClient.Close();
            }
        }
Exemple #18
0
        /// <summary>
        /// Authenticate client.
        /// </summary>
        /// <param name="remoteEndpoint">Uri connect.</param>
        /// <param name="sslStream">Sslstreamn argument.</param>
        /// <returns>Returned true if success.</returns>
        private static bool AuthenticateAsClient(Uri remoteEndpoint, SslStream sslStream)
        {
            try
            {
                X509Certificate certificate = new X509Certificate("certificate.pfx");
                sslStream.AuthenticateAsClient(remoteEndpoint.Host, new X509CertificateCollection(new[] { certificate }), SslProtocols.Tls, false);
            }
            catch (AuthenticationException e)
            {
                Http2Logger.LogError(e.Message);
                if (e.InnerException != null)
                {
                    Http2Logger.LogError(string.Format("Inner exception: {0}", e.InnerException.Message));
                }

                Http2Logger.LogError("Authentication failed - closing the connection.");
                return(false);
            }

            return(true);
        }
Exemple #19
0
        private void HandleAcceptedClient(Stream incomingClient)
        {
            bool   backToHttp11     = false;
            string selectedProtocol = Protocols.Http1;

            if (_useHandshake)
            {
                try
                {
                    if (_isSecure)
                    {
                        incomingClient = new SslStream(incomingClient, false);

                        (incomingClient as SslStream).AuthenticateAsServer(_cert);

                        selectedProtocol = (incomingClient as SslStream).AlpnSelectedProtocol;
                    }
                }
                catch (OpenSslException)
                {
                    backToHttp11 = true;
                }
                catch (Exception e)
                {
                    Http2Logger.LogError("Exception occurred. Closing client's socket. " + e.Message);
                    incomingClient.Close();
                    return;
                }
            }
            try
            {
                HandleRequest(incomingClient, selectedProtocol, backToHttp11);
            }
            catch (Exception e)
            {
                Http2Logger.LogError("Exception occurred. Closing client's socket. " + e.Message);
                incomingClient.Close();
            }
        }
Exemple #20
0
        private static void SaveFile(string directory, string fileName, byte[] fileBytes)
        {
            string newfilepath;

            // create local file path
            if (!string.IsNullOrEmpty(directory))
            {
                if (directory[0] == '\\')
                {
                    directory = '.' + directory;
                }

                Directory.CreateDirectory(directory);
                newfilepath = directory + '\\' + fileName;
            }
            else
            {
                newfilepath = fileName;
            }

            if (File.Exists(newfilepath))
            {
                try
                {
                    File.Delete(newfilepath);
                }
                catch (Exception)
                {
                    Http2Logger.LogError("Cant overwrite file: " + newfilepath);
                }
            }
            using (var fs = new FileStream(newfilepath, FileMode.Create))
            {
                fs.Write(fileBytes, 0, fileBytes.Length);
            }

            Http2Logger.LogInfo("File saved: " + fileName);
        }
        private void SaveDataFrame(Http2Stream stream, DataFrame dataFrame)
        {
            lock (_writeLock)
            {
                string path = stream.Headers.GetValue(":path".ToLower());

                try
                {
                    string pathToSave = AssemblyPath + Root + path;
                    if (!Directory.Exists(Path.GetDirectoryName(pathToSave)))
                    {
                        throw new DirectoryNotFoundException("Access denied");
                    }
                    _fileHelper.SaveToFile(dataFrame.Data.Array, dataFrame.Data.Offset, dataFrame.Data.Count,
                                           pathToSave, stream.ReceivedDataAmount != 0);
                }
                catch (Exception ex)
                {
                    Http2Logger.LogError(ex.Message);
                    stream.WriteDataFrame(new byte[0], true);
                    stream.Dispose();
                }

                stream.ReceivedDataAmount += dataFrame.FrameLength;

                if (dataFrame.IsEndStream)
                {
                    if (!stream.EndStreamSent)
                    {
                        //send terminator
                        stream.WriteDataFrame(new byte[0], true);
                        Http2Logger.LogDebug("Terminator was sent");
                    }
                    _fileHelper.RemoveStream(AssemblyPath + Root + path);
                }
            }
        }
Exemple #22
0
        /// <summary>
        /// Dispatches the incoming frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void DispatchIncomingFrame(Frame frame)
        {
            Http2Stream stream = null;

            //Spec 03 tells that frame with continues flag MUST be followed by a frame with the same type
            //and the same stread id.
            if (_toBeContinuedHeaders != null)
            {
                if (_toBeContinuedFrame.FrameType != frame.FrameType ||
                    _toBeContinuedFrame.StreamId != frame.StreamId)
                {
                    //If not, we must close the session.
                    Dispose();
                    return;
                }
            }

            try
            {
                switch (frame.FrameType)
                {
                case FrameType.Headers:
                    Http2Logger.LogDebug("New headers with id = " + frame.StreamId);
                    var headersFrame      = (HeadersFrame)frame;
                    var serializedHeaders = new byte[headersFrame.CompressedHeaders.Count];

                    Buffer.BlockCopy(headersFrame.CompressedHeaders.Array,
                                     headersFrame.CompressedHeaders.Offset,
                                     serializedHeaders, 0, serializedHeaders.Length);

                    var decompressedHeaders = _comprProc.Decompress(serializedHeaders);
                    var headers             = new HeadersList(decompressedHeaders);

                    if (!headersFrame.IsEndHeaders)
                    {
                        _toBeContinuedHeaders = decompressedHeaders;
                        _toBeContinuedFrame   = headersFrame;
                        break;
                    }

                    if (_toBeContinuedHeaders != null)
                    {
                        headers.AddRange(_toBeContinuedHeaders);
                    }

                    headersFrame.Headers.AddRange(headers);
                    foreach (var header in headers)
                    {
                        Http2Logger.LogDebug("Stream {0} header: {1}={2}", frame.StreamId, header.Key, header.Value);
                    }

                    stream = GetStream(headersFrame.StreamId);

                    if (stream == null)
                    {
                        // new stream
                        if (ActiveStreams.GetOpenedStreamsBy(_remoteEnd) + 1 > OurMaxConcurrentStreams)
                        {
                            //Remote side tries to open more streams than allowed
                            Dispose();
                            return;
                        }

                        string path = headers.GetValue(":path");

                        if (path == null)
                        {
                            path = _handshakeHeaders.ContainsKey(":path") ? _handshakeHeaders[":path"] : @"\index.html";
                            headers.Add(new KeyValuePair <string, string>(":path", path));
                        }

                        stream = new Http2Stream(headers, headersFrame.StreamId,
                                                 _writeQueue, _flowControlManager,
                                                 _comprProc);

                        ActiveStreams[stream.Id] = stream;

                        stream.OnClose += (o, args) =>
                        {
                            if (!ActiveStreams.Remove(ActiveStreams[args.Id]))
                            {
                                throw new ArgumentException("Cant remove stream from ActiveStreams");
                            }
                        };

                        _toBeContinuedFrame   = null;
                        _toBeContinuedHeaders = null;
                    }

                    break;

                case FrameType.Priority:
                    var priorityFrame = (PriorityFrame)frame;
                    Http2Logger.LogDebug("Priority frame. StreamId: {0} Priority: {1}", priorityFrame.StreamId, priorityFrame.Priority);
                    stream = GetStream(priorityFrame.StreamId);
                    if (_usePriorities)
                    {
                        stream.Priority = priorityFrame.Priority;
                    }
                    break;

                case FrameType.RstStream:
                    var resetFrame = (RstStreamFrame)frame;
                    stream = GetStream(resetFrame.StreamId);

                    if (stream != null)
                    {
                        Http2Logger.LogDebug("RST frame with code " + resetFrame.StatusCode);
                        stream.Dispose();
                    }
                    break;

                case FrameType.Data:
                    var dataFrame = (DataFrame)frame;
                    Http2Logger.LogDebug("Data frame. StreamId:{0} Length:{1}", dataFrame.StreamId, dataFrame.FrameLength);
                    stream = GetStream(dataFrame.StreamId);

                    //Aggressive window update
                    if (stream.IsFlowControlEnabled)
                    {
                        stream.WriteWindowUpdate(2000000);
                    }
                    break;

                case FrameType.Ping:
                    var pingFrame = (PingFrame)frame;
                    Http2Logger.LogDebug("Ping frame with StreamId:{0} Payload:{1}", pingFrame.StreamId, pingFrame.Payload.Count);

                    if (pingFrame.FrameLength != PingFrame.PayloadLength)
                    {
                        throw new ProtocolError(ResetStatusCode.ProtocolError, "Ping payload size is not equal to 8");
                    }

                    if (pingFrame.IsPong)
                    {
                        _wasPingReceived = true;
                        _pingReceived.Set();
                    }
                    else
                    {
                        var pongFrame = new PingFrame(true, pingFrame.Payload.ToArray());
                        _writeQueue.WriteFrame(pongFrame);
                    }
                    break;

                case FrameType.Settings:
                    //Not first frame in the session.
                    //Client initiates connection and sends settings before request.
                    //It means that if server sent settings before it will not be a first frame,
                    //because client initiates connection.
                    if (_ourEnd == ConnectionEnd.Server && !_wasSettingsReceived && ActiveStreams.Count != 0)
                    {
                        Dispose();
                        return;
                    }

                    var settingFrame = (SettingsFrame)frame;
                    Http2Logger.LogDebug("Settings frame. Entry count: {0} StreamId: {1}", settingFrame.EntryCount, settingFrame.StreamId);
                    _wasSettingsReceived = true;
                    _settingsManager.ProcessSettings(settingFrame, this, _flowControlManager);
                    break;

                case FrameType.WindowUpdate:
                    if (_useFlowControl)
                    {
                        var windowFrame = (WindowUpdateFrame)frame;
                        Http2Logger.LogDebug("WindowUpdate frame. Delta: {0} StreamId: {1}", windowFrame.Delta, windowFrame.StreamId);
                        stream = GetStream(windowFrame.StreamId);

                        if (stream != null)
                        {
                            stream.UpdateWindowSize(windowFrame.Delta);
                            stream.PumpUnshippedFrames();
                        }
                    }
                    break;

                case FrameType.GoAway:
                    _goAwayReceived = true;
                    Http2Logger.LogDebug("GoAway frame received");
                    Dispose();
                    break;

                default:
                    throw new NotImplementedException(frame.FrameType.ToString());
                }

                if (stream != null && frame is IEndStreamFrame && ((IEndStreamFrame)frame).IsEndStream)
                {
                    //Tell the stream that it was the last frame
                    Http2Logger.LogDebug("Final frame received for stream with id = " + stream.Id);
                    stream.EndStreamReceived = true;
                }

                if (stream != null && OnFrameReceived != null)
                {
                    OnFrameReceived(this, new FrameReceivedEventArgs(stream, frame));
                }
            }

            //Frame came for already closed stream. Ignore it.
            //Spec:
            //An endpoint that sends RST_STREAM MUST ignore
            //frames that it receives on closed streams if it sends RST_STREAM.
            //
            //An endpoint MUST NOT send frames on a closed stream.  An endpoint
            //that receives a frame after receiving a RST_STREAM or a frame
            //containing a END_STREAM flag on that stream MUST treat that as a
            //stream error (Section 5.4.2) of type PROTOCOL_ERROR.
            catch (Http2StreamNotFoundException)
            {
                if (stream != null)
                {
                    stream.WriteRst(ResetStatusCode.ProtocolError);
                }
                else
                {
                    //GoAway?
                }
            }
            catch (CompressionError ex)
            {
                //The endpoint is unable to maintain the compression context for the connection.
                Http2Logger.LogError("Compression error occured: " + ex.Message);
                Close(ResetStatusCode.CompressionError);
            }
            catch (ProtocolError pEx)
            {
                Http2Logger.LogError("Protocol error occured: " + pEx.Message);
                Close(pEx.Code);
            }
        }
Exemple #23
0
        /// <summary>
        /// Dispatches the incoming frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void DispatchIncomingFrame(Frame frame)
        {
            Http2Stream stream = null;

            try
            {
                if (frame.PayloadLength > Constants.MaxFramePayloadSize)
                {
                    throw new ProtocolError(ResetStatusCode.FrameSizeError,
                                            String.Format("Frame too large: Type: {0} {1}", frame.FrameType,
                                                          frame.PayloadLength));
                }

                /* 12 -> 6.5
                 * A SETTINGS frame MUST be sent by both endpoints at the start of a
                 * connection, and MAY be sent at any other time by either endpoint over
                 * the lifetime of the connection.*/
                if (frame.FrameType != FrameType.Settings && !_wasSettingsReceived)
                {
                    throw new ProtocolError(ResetStatusCode.ProtocolError,
                                            "Settings frame was not the first frame in the session");
                }

                Http2Logger.LogDebug("Incoming frame: " + frame.FrameType);

                switch (frame.FrameType)
                {
                case FrameType.Headers:
                    HandleHeaders(frame as HeadersFrame, out stream);
                    break;

                case FrameType.Continuation:
                    HandleContinuation(frame as ContinuationFrame, out stream);
                    break;

                case FrameType.Priority:
                    HandlePriority(frame as PriorityFrame, out stream);
                    break;

                case FrameType.RstStream:
                    HandleRstFrame(frame as RstStreamFrame, out stream);
                    break;

                case FrameType.Data:
                    HandleDataFrame(frame as DataFrame, out stream);
                    break;

                case FrameType.Ping:
                    HandlePingFrame(frame as PingFrame);
                    break;

                case FrameType.Settings:
                    HandleSettingsFrame(frame as SettingsFrame);
                    if (!(frame as SettingsFrame).IsAck)
                    {
                        // sending ACK settings
                        WriteSettings(new SettingsPair[0], true);
                    }
                    break;

                case FrameType.WindowUpdate:
                    HandleWindowUpdateFrame(frame as WindowUpdateFrame, out stream);
                    break;

                case FrameType.GoAway:
                    HandleGoAwayFrame(frame as GoAwayFrame);
                    break;

                case FrameType.PushPromise:
                    HandlePushPromiseFrame(frame as PushPromiseFrame, out stream);
                    if (stream != null)     //This means that sequence is complete
                    {
                        _promisedResources.Add(stream.Id, stream.Headers.GetValue(CommonHeaders.Path));
                    }
                    break;

                case FrameType.AltSvc:
                    HandleAltSvcFrame(frame);
                    break;

                case FrameType.Blocked:
                    HandleBlockedFrame(frame);
                    break;

                default:
                    /* 12 -> 4.1
                     * Implementations MUST treat the receipt of an unknown frame type
                     * (any frame types not defined in this document) as a connection
                     * error of type PROTOCOL_ERROR. */
                    throw new ProtocolError(ResetStatusCode.ProtocolError, "Unknown frame type detected");
                }

                _lastFrame = frame;

                if (frame is IEndStreamFrame && ((IEndStreamFrame)frame).IsEndStream)
                {
                    //Tell the stream that it was the last frame
                    Http2Logger.LogDebug("Final frame received for stream id=" + stream.Id);
                    stream.HalfClosedRemote = true;

                    //Promised resource has been pushed
                    if (_promisedResources.ContainsKey(stream.Id))
                    {
                        _promisedResources.Remove(stream.Id);
                    }
                }

                if (stream == null || OnFrameReceived == null)
                {
                    return;
                }

                OnFrameReceived(this, new FrameReceivedEventArgs(stream, frame));
                stream.FramesReceived++;
            }

            //09
            //5.1.  Stream States
            //An endpoint MUST NOT send frames on a closed stream.  An endpoint
            //that receives a frame after receiving a RST_STREAM [RST_STREAM] or
            //a frame containing a END_STREAM flag on that stream MUST treat
            //that as a stream error (Section 5.4.2) of type STREAM_CLOSED
            //[STREAM_CLOSED].
            catch (Http2StreamNotFoundException ex)
            {
                Http2Logger.LogDebug("Frame for already Closed stream with stream id={0}", ex.Id);
                var rstFrame = new RstStreamFrame(ex.Id, ResetStatusCode.StreamClosed);

                Http2Logger.LogDebug("Sending RST_STREAM frame: stream id={0}, status code={1}",
                                     rstFrame.StreamId, rstFrame.StatusCode);

                _writeQueue.WriteFrame(rstFrame);
                stream.WasRstSent = true;
            }
            catch (CompressionError ex)
            {
                //The endpoint is unable to maintain the compression context for the connection.
                Http2Logger.LogError("Compression error occurred: " + ex.Message);
                Close(ResetStatusCode.CompressionError);
            }
            catch (ProtocolError pEx)
            {
                Http2Logger.LogError("Protocol error occurred: " + pEx.Message);
                Close(pEx.Code);
            }
            catch (MaxConcurrentStreamsLimitException)
            {
                //Remote side tries to open more streams than allowed
                Dispose();
            }
            catch (Exception ex)
            {
                Http2Logger.LogError("Unknown error occurred: " + ex.Message);
                Close(ResetStatusCode.InternalError);
            }
        }
Exemple #24
0
        /// <summary>
        /// Processes incoming request.
        /// </summary>
        public async void ProcessRequest()
        {
            try
            {
                // invalid connection, skip
                if (!_client.CanRead)
                {
                    return;
                }

                var rawHeaders = Http11Helper.ReadHeaders(_client);

                Http2Logger.LogDebug("Http1.1 Protocol Handler. Process request " + string.Join(" ", rawHeaders));

                // invalid connection, skip
                if (rawHeaders == null || rawHeaders.Length == 0)
                {
                    return;
                }

                // headers[0] contains METHOD, URI and VERSION like "GET /api/values/1 HTTP/1.1"
                var headers = Http11Helper.ParseHeaders(rawHeaders.Skip(1).ToArray());

                // client MUST include Host header due to HTTP/1.1 spec
                if (!headers.ContainsKey("Host"))
                {
                    throw new ApplicationException("Host header is missing");
                }

                // parse request parameters: method, path, host, etc
                var splittedRequestString = rawHeaders[0].Split(' ');
                var method = splittedRequestString[0];

                if (!IsMethodSupported(method))
                {
                    throw new NotSupportedException(method + " method is not currently supported via HTTP/1.1");
                }

                var scheme = _protocol == SslProtocols.None ? Uri.UriSchemeHttp : Uri.UriSchemeHttps;

                var path = splittedRequestString[1];

                // main OWIN environment components
                // OWIN request and response below shares the same environment dictionary instance
                _environment = CreateOwinEnvironment(method, scheme, "", path, headers);
                _request     = new OwinRequest(_environment);
                _response    = new OwinResponse(_environment);

                // we may need to populate additional fields if request supports UPGRADE
                AddOpaqueUpgradeIfNeeded();

                await _next.Invoke(new OwinContext(_environment));

                if (_opaqueCallback == null)
                {
                    EndResponse();
                }
                else
                {
                    // do not close connection
                    EndResponse(false);

                    var opaqueEnvironment = CreateOpaqueEnvironment();
                    await _opaqueCallback(new OwinContext(opaqueEnvironment));
                }
            }
            catch (Exception ex)
            {
                Http2Logger.LogError(ex.Message);
                EndResponse(ex);
                Http2Logger.LogDebug("Closing connection");
                _client.Close();
            }
        }
Exemple #25
0
        public static void Main(string[] args)
        {
            Console.SetWindowSize(125, 29);
            Http2Logger.WriteToFile = false;

            _sessions    = new Dictionary <string, Http2SessionHandler>();
            _environment = ArgsHelper.GetEnvironment(args);

            var isTestsEnabled     = ConfigurationManager.AppSettings["testModeEnabled"] == "true";
            var waitForTestsFinish = new ManualResetEvent(!isTestsEnabled);

            Console.WriteLine();
            Console.WriteLine();
            Http2Logger.LogDebug("Tests enabled: " + isTestsEnabled);

            ThreadPool.SetMaxThreads(10, 10);

            var uri = ArgsHelper.TryGetUri(args);

            if (!isTestsEnabled)
            {
                HelpDisplayer.ShowMainMenuHelp();
                Console.WriteLine("Enter command");
            }

            do
            {
                try
                {
                    Command cmd;
                    string  command;
                    if (uri != null)
                    {
                        command = Verbs.Get + " " + uri; //TODO set up method correctly
                    }
                    else
                    {
                        Console.Write(">");
                        command = Console.ReadLine();
                    }

                    try
                    {
                        cmd = CommandParser.CommandParser.Parse(command);
                    }
                    catch (Exception ex)
                    {
                        Http2Logger.LogError(ex.Message);
                        continue;
                    }
                    //Scheme and port were checked during parsing get cmd.
                    switch (cmd.GetCmdType())
                    {
                    case CommandType.Put:
                    case CommandType.Post:
                    case CommandType.Get:
                    case CommandType.Delete:
                    case CommandType.Dir:
                        Http2Logger.LogConsole("Uri command detected");
                        var uriCmd = (IUriCommand)cmd;

                        string method = uriCmd.Method;

                        //Only unique sessions can be opened
                        if (_sessions.ContainsKey(uriCmd.Uri.Authority))
                        {
                            Http2Logger.LogConsole("Session already exists");
                            _sessions[uriCmd.Uri.Authority].SendRequestAsync(uriCmd.Uri, method);
                            break;
                        }

                        Http2Logger.LogConsole("Creating new session");
                        var sessionHandler = new Http2SessionHandler(_environment);
                        _sessions.Add(uriCmd.Uri.Authority, sessionHandler);
                        sessionHandler.OnClosed +=
                            (sender, eventArgs) =>
                        {
                            _sessions.Remove(sessionHandler.ServerUri);
                            Http2Logger.LogDebug("Session deleted from collection: " + sessionHandler.ServerUri);

                            waitForTestsFinish.Set();
                        };

                        //Get cmd is equivalent for connect -> get. This means, that each get request
                        //will open new session.
                        Console.WriteLine(uriCmd.Uri.ToString());
                        bool success = sessionHandler.Connect(uriCmd.Uri);
                        if (!success)
                        {
                            Http2Logger.LogError("Connection failed");
                            break;
                        }

                        if (!sessionHandler.WasHttp1Used)
                        {
                            sessionHandler.StartConnection();

                            if (sessionHandler.Protocol != SslProtocols.None)
                            {
                                sessionHandler.SendRequestAsync(uriCmd.Uri, method);
                            }
                        }
                        break;

                    case CommandType.Help:
                        ((HelpCommand)cmd).ShowHelp.Invoke();
                        break;

                    case CommandType.Ping:
                        string url = ((PingCommand)cmd).Uri.Authority;
                        if (_sessions.ContainsKey(url))
                        {
                            _sessions[url].Ping();
                        }
                        else
                        {
                            Http2Logger.LogError("Can't ping until session is opened.");
                        }
                        break;

                    case CommandType.Exit:

                        var sessionsDictCopy = new Dictionary <string, Http2SessionHandler>(_sessions);
                        foreach (var sessionUri in sessionsDictCopy.Keys)
                        {
                            sessionsDictCopy[sessionUri].Dispose(false);
                        }
                        sessionsDictCopy.Clear();
                        return;
                    }
                }
                catch (Exception e)
                {
                    Http2Logger.LogError("Problems occurred - please restart client. Error: " + e.Message);
                }
            } while (!isTestsEnabled);

            waitForTestsFinish.WaitOne(5000);

            Http2Logger.LogDebug("Exiting");
            Console.WriteLine();
            Console.WriteLine();
        }
Exemple #26
0
        public static void Main(string[] args)
        {
            Console.SetWindowSize(125, 29);
            Http2Logger.WriteToFile = false;

            _sessions = new Dictionary <string, Http2SessionHandler>();
            var argsList = new List <string>(args);

            _environment = new Dictionary <string, object>
            {
                { "useHandshake", !argsList.Contains("-no-handshake") },
                { "usePriorities", !argsList.Contains("-no-priorities") },
                { "useFlowControl", !argsList.Contains("-no-flowcontrol") },
            };

            HelpDisplayer.ShowMainMenuHelp();
            ThreadPool.SetMaxThreads(10, 10);

            Console.WriteLine("Enter command");
            while (true)
            {
                try
                {
                    Console.Write(">");
                    string  command = Console.ReadLine();
                    Command cmd;

                    try
                    {
                        cmd = CommandParser.Parse(command);
                    }
                    catch (Exception ex)
                    {
                        Http2Logger.LogError(ex.Message);
                        continue;
                    }
                    //Scheme and port were checked during parsing get cmd.
                    switch (cmd.GetCmdType())
                    {
                    case CommandType.Put:
                    case CommandType.Post:
                    case CommandType.Get:
                    case CommandType.Delete:
                    case CommandType.Dir:
                        var uriCmd = (IUriCommand)cmd;

                        string method        = uriCmd.Method;
                        string localPath     = null;
                        string serverPostAct = null;

                        if (cmd is PostCommand)
                        {
                            localPath     = (cmd as PostCommand).LocalPath;
                            serverPostAct = (cmd as PostCommand).ServerPostAct;
                        }
                        else if (cmd is PutCommand)
                        {
                            localPath = (cmd as PutCommand).LocalPath;
                        }

                        //Only unique sessions can be opened
                        if (_sessions.ContainsKey(uriCmd.Uri.Authority))
                        {
                            _sessions[uriCmd.Uri.Authority].SendRequestAsync(uriCmd.Uri, method, localPath, serverPostAct);
                            break;
                        }

                        var sessionHandler = new Http2SessionHandler(_environment);
                        _sessions.Add(uriCmd.Uri.Authority, sessionHandler);
                        sessionHandler.OnClosed +=
                            (sender, eventArgs) => _sessions.Remove(sessionHandler.ServerUri);

                        //Get cmd is equivalent for connect -> get. This means, that each get request
                        //will open new session.
                        bool success = sessionHandler.Connect(uriCmd.Uri);
                        if (!success)
                        {
                            Http2Logger.LogError("Connection failed");
                            break;
                        }

                        Task.Run(() => sessionHandler.StartConnection());

                        using (var waitForConnectionStart = new ManualResetEvent(false))
                        {
                            waitForConnectionStart.WaitOne(200);
                        }

                        sessionHandler.SendRequestAsync(uriCmd.Uri, method, localPath, serverPostAct);
                        break;

                    case CommandType.Help:
                        ((HelpCommand)cmd).ShowHelp.Invoke();
                        break;

                    case CommandType.Ping:
                        string url = ((PingCommand)cmd).Uri.Authority;
                        if (_sessions.ContainsKey(url))
                        {
                            _sessions[url].Ping();
                        }
                        else
                        {
                            Http2Logger.LogError("Can't ping until session is opened.");
                        }
                        break;

                    case CommandType.Exit:
                        foreach (var sessionUri in _sessions.Keys)
                        {
                            _sessions[sessionUri].Dispose(false);
                        }
                        _sessions.Clear();
                        return;
                    }
                }
                catch (Exception e)
                {
                    Http2Logger.LogError("Problems occured - please restart client. Error: " + e.Message);
                }
            }
        }
Exemple #27
0
        public bool Connect(Uri connectUri)
        {
            _path     = connectUri.PathAndQuery;
            _version  = Protocols.Http2;
            _scheme   = connectUri.Scheme;
            _host     = connectUri.Host;
            _port     = connectUri.Port;
            ServerUri = connectUri.Authority;

            if (_clientSession != null)
            {
                return(false);
            }

            try
            {
                int port = connectUri.Port;

                int securePort;

                if (!int.TryParse(ConfigurationManager.AppSettings["securePort"], out securePort))
                {
                    Http2Logger.LogError("Incorrect port in the config file!");
                    return(false);
                }


                //Connect alpn extension, set known protocols
                var extensions = new[] { ExtensionType.Renegotiation, ExtensionType.ALPN };

                _options = port == securePort
                               ? new SecurityOptions(SecureProtocol.Tls1, extensions, new[] { Protocols.Http1, Protocols.Http2 },
                                                     ConnectionEnd.Client)
                               : new SecurityOptions(SecureProtocol.None, extensions, new[] { Protocols.Http1, Protocols.Http2 },
                                                     ConnectionEnd.Client);

                _options.VerificationType  = CredentialVerification.None;
                _options.Certificate       = Org.Mentalis.Security.Certificates.Certificate.CreateFromCerFile(CertificatePath);
                _options.Flags             = SecurityFlags.Default;
                _options.AllowedAlgorithms = SslAlgorithms.RSA_AES_256_SHA | SslAlgorithms.NULL_COMPRESSION;

                _socket = new SecureSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, _options);
                IDictionary <string, object> handshakeResult = null;
                using (var monitor = new ALPNExtensionMonitor())
                {
                    monitor.OnProtocolSelected += (o, args) => { _selectedProtocol = args.SelectedProtocol; };
                    _socket.Connect(new DnsEndPoint(connectUri.Host, connectUri.Port), monitor);

                    if (_useHandshake)
                    {
                        var handshakeEnvironment = MakeHandshakeEnvironment(_socket);
                        //Handshake manager determines what handshake must be used: upgrade or secure
                        handshakeResult = HandshakeManager.GetHandshakeAction(handshakeEnvironment).Invoke();

                        Http2Logger.LogDebug("Handshake finished");

                        if (_selectedProtocol == Protocols.Http1)
                        {
                            _useHttp20 = false;
                            return(true);
                        }
                    }
                }

                SendSessionHeader();
                _useHttp20     = true;
                _clientSession = new Http2Session(_socket, ConnectionEnd.Client, _usePriorities, _useFlowControl, handshakeResult);

                //For saving incoming data
                _clientSession.OnFrameReceived   += FrameReceivedHandler;
                _clientSession.OnRequestSent     += RequestSentHandler;
                _clientSession.OnSessionDisposed += (sender, args) => Dispose(false);
            }
            catch (Http2HandshakeFailed ex)
            {
                if (ex.Reason == HandshakeFailureReason.InternalError)
                {
                    _useHttp20 = false;
                }
                else
                {
                    Http2Logger.LogError("Specified server did not respond");
                    Dispose(true);
                    return(false);
                }
            }
            catch (SocketException)
            {
                Http2Logger.LogError("Check if any server listens port " + connectUri.Port);
                Dispose(true);
                return(false);
            }
            catch (Exception ex)
            {
                Http2Logger.LogError("Unknown connection exception was caught: " + ex.Message);
                Dispose(true);
                return(false);
            }

            return(true);
        }
        public IDictionary <string, object> Handshake()
        {
            var response = new HandshakeResponse();

            _readThread = new Thread((object state) =>
            {
                var handle = state as EventWaitHandle;

                try
                {
                    response             = Read11Headers();
                    _wasResponseReceived = true;
                    if (handle != null)
                    {
                        handle.Set();
                    }
                }
                catch (Exception ex)
                {
                    Http2Logger.LogError(ex.Message);

                    // singal that there is an error
                    if (handle != null)
                    {
                        handle.Set();
                    }
                    _error = ex;
                    throw;
                }
            });

            _readThread.IsBackground = true;
            _readThread.Start(_responseReceivedRaised);

            if (_end == ConnectionEnd.Client)
            {
                // Build the request
                var builder = new StringBuilder();
                builder.AppendFormat("{0} {1} {2}\r\n", "GET", _headers[":path"], "HTTP/1.1");
                //TODO pass here requested filename
                builder.AppendFormat("Host: {0}\r\n", _headers[":host"]);
                builder.Append("Connection: Upgrade, Http2-Settings\r\n");
                builder.Append("Upgrade: HTTP-DRAFT-04/2.0\r\n");
                builder.Append("Http2-Settings: ");
                //TODO check out how to send window size and max_conc_streams

                if (_headers != null)
                {
                    var http2Settings = new StringBuilder();
                    foreach (var key in _headers.Keys)
                    {
                        if (!string.Equals(":path", key, StringComparison.OrdinalIgnoreCase))
                        {
                            http2Settings.AppendFormat("{0}: {1}\r\n", key, _headers[key]);
                        }
                    }
                    byte[] settingsBytes = Encoding.UTF8.GetBytes(http2Settings.ToString());
                    builder.Append(Convert.ToBase64String(settingsBytes));
                }
                builder.Append("\r\n\r\n");
                byte[] requestBytes = Encoding.UTF8.GetBytes(builder.ToString());
                InternalSocket.Send(requestBytes, 0, requestBytes.Length, SocketFlags.None);

                _responseReceivedRaised.WaitOne(Timeout);
                _responseReceivedRaised.Dispose();
            }
            else
            {
                _responseReceivedRaised.WaitOne(Timeout);
                _responseReceivedRaised.Dispose();

                if (response.Result == HandshakeResult.Upgrade)
                {
                    const string status   = "101";
                    const string protocol = "HTTP/1.1";
                    const string postfix  = "Switching Protocols";

                    var builder = new StringBuilder();
                    builder.AppendFormat("{0} {1} {2}\r\n", protocol, status, postfix);
                    builder.Append("Connection: Upgrade\r\n");
                    builder.Append("Upgrade: HTTP-draft-04/2.0\r\n");
                    builder.Append("\r\n");

                    byte[] requestBytes = Encoding.ASCII.GetBytes(builder.ToString());
                    InternalSocket.Send(requestBytes, 0, requestBytes.Length, SocketFlags.None);
                }
            }

            if (!_wasResponseReceived)
            {
                if (_readThread.IsAlive)
                {
                    _readThread.Abort();
                    _readThread.Join();
                }
                throw new Http2HandshakeFailed(HandshakeFailureReason.Timeout);
            }

            if (_error != null)
            {
                throw _error;
            }

            if (response.Result != HandshakeResult.Upgrade)
            {
                throw new Http2HandshakeFailed(HandshakeFailureReason.InternalError);
            }

            if (_readThread.IsAlive)
            {
                _readThread.Abort();
            }
            _readThread.Join();

            return(_handshakeResult);
        }
Exemple #29
0
        /// <summary>
        /// Get files via http request.
        /// </summary>
        /// <param name="content">Downloaded file.</param>
        /// <param name="type">Type of file.</param>
        /// <param name="requestUri">Full name of file.</param>
        /// <param name="uri">The address site.</param>
        private void PrivateGetFile(byte[] content, string type, Uri requestUri, string uri)
        {
            byte[] headers = this.GetHeaders(content);
            if (headers == null)
            {
                Http2Logger.LogError("HTTP response: Invalid");
                return;
            }

            this.httpMonitor.LogResponse(headers, content.Length);

            int status = this.GetStatus(headers);

            if (useHttp2Handshake)
            {
                Http2Logger.LogDebug(Encoding.UTF8.GetString(headers));
            }

            Http2Logger.LogInfo(string.Format("HTTP response: {0}, length: {1}  name:{2}", status, content.LongLength, uri));

            if (status == 200 || status == 101)
            {
                string url       = requestUri.Scheme + "://" + requestUri.Authority;
                string directory = string.Empty;
                string localDir  = string.Empty;
                string file      = requestUri.LocalPath;
                string localFile = Path.GetFileName(uri);

                for (int i = 0; i < requestUri.Segments.Length - 1; i++)
                {
                    directory += requestUri.Segments[i];
                    localDir  += requestUri.Segments[i].Replace('/', '\\');
                }

                if (!string.IsNullOrEmpty(localDir))
                {
                    if (localDir[0] == '\\')
                    {
                        localDir = '.' + localDir;
                    }

                    Directory.CreateDirectory(localDir);
                    localFile = localDir + '\\' + localFile;
                }

                int contentOffset = headers.Length;
                using (var fs = new FileStream(localFile, FileMode.Create))
                {
                    fs.Write(content, contentOffset, content.Length - contentOffset);
                }

                if (type == ContentTypes.TextHtml)
                {
                    string strContent = Encoding.UTF8.GetString(content, contentOffset, content.Length - contentOffset)
                                        .Replace("http2frame_start\r\n", "")
                                        .Replace("http2frame_end", "");

                    XHtmlDocument document = XHtmlDocument.Parse(strContent);

                    string path = url + directory;
                    foreach (var image in document.Images)
                    {
                        this.AddNameToDownloadList(string.Format("{0}/{1}", path.ToLower(), image.ToLower()));
                    }

                    foreach (var link in document.Links)
                    {
                        this.AddNameToDownloadList(string.Format("{0}/{1}", path.ToLower(), link.ToLower()));
                    }

                    foreach (var script in document.Scripts)
                    {
                        this.AddNameToDownloadList(string.Format("{0}/{1}", path.ToLower(), script.ToLower()));
                    }
                }
            }             // if status 200
        }
        private void HandleAcceptedClient(SecureSocket incomingClient)
        {
            bool   backToHttp11         = false;
            string alpnSelectedProtocol = Protocols.Http2;
            var    handshakeEnvironment = MakeHandshakeEnvironment(incomingClient);
            IDictionary <string, object> handshakeResult = null;

            //Think out smarter way to get handshake result.
            //DO NOT change Middleware function. If you will do so, server will not even launch. (It's owin's problem)
            Func <Task> handshakeAction = () =>
            {
                var handshakeTask = new Task(() =>
                {
                    handshakeResult = HandshakeManager.GetHandshakeAction(handshakeEnvironment).Invoke();
                });
                return(handshakeTask);
            };

            if (_useHandshake)
            {
                var environment = new Dictionary <string, object>
                {
                    //Sets the handshake action depends on port.
                    { "HandshakeAction", handshakeAction },
                };

                try
                {
                    var handshakeTask = _next(environment);

                    handshakeTask.Start();
                    if (!handshakeTask.Wait(6000))
                    {
                        incomingClient.Close();
                        Http2Logger.LogError("Handshake timeout. Connection dropped.");
                        return;
                    }

                    alpnSelectedProtocol = incomingClient.SelectedProtocol;
                }
                catch (Http2HandshakeFailed ex)
                {
                    if (ex.Reason == HandshakeFailureReason.InternalError)
                    {
                        backToHttp11 = true;
                    }
                    else
                    {
                        incomingClient.Close();
                        Http2Logger.LogError("Handshake timeout. Client was disconnected.");
                        return;
                    }
                }
                catch (Exception e)
                {
                    Http2Logger.LogError("Exception occured. Closing client's socket. " + e.Message);
                    incomingClient.Close();
                    return;
                }
            }
            try
            {
                HandleRequest(incomingClient, alpnSelectedProtocol, backToHttp11, handshakeResult);
            }
            catch (Exception e)
            {
                Http2Logger.LogError("Exception occured. Closing client's socket. " + e.Message);
                incomingClient.Close();
            }
        }