コード例 #1
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Process cookies.
        /// </summary>
        /// <param name="toProcess">The header list containing the cookies.</param>
        private void ProcessCookie(HeadersList toProcess)
        {
            /* 12 -> 8.1.3.4.
             * If there are multiple Cookie header fields after
             * decompression, these MUST be concatenated into a single octet string
             * using the two octet delimiter of 0x3B, 0x20 (the ASCII string "; "). */

            const string delimiter = "; ";
            var          cookie    = new StringBuilder(String.Empty);

            for (int i = 0; i < toProcess.Count; i++)
            {
                if (!toProcess[i].Key.Equals(CommonHeaders.Cookie))
                {
                    continue;
                }

                cookie.Append(toProcess[i].Value);
                cookie.Append(delimiter);
                toProcess.RemoveAt(i--);
            }

            if (cookie.Length > 0)
            {
                // Add without last delimeter
                toProcess.Add(new KeyValuePair <string, string>(CommonHeaders.Cookie,
                                                                cookie.ToString(cookie.Length - 2, 2)));
            }
        }
コード例 #2
0
        public void ClearReferenceSet()
        {
            var bytes = new byte[] { 0x30 }; // this value depends on pattern

            var clientHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":method", "get")
            };

            var clientCompressionProc = new CompressionProcessor();
            var serverCompressionProc = new CompressionProcessor();

            serverCompressionProc.Decompress(clientCompressionProc.Compress(clientHeaders));

            stateBefore = new CompProcState(serverCompressionProc);

            Assert.True(stateBefore.LocalRefSet.Count > 0);

            serverCompressionProc.Decompress(bytes);

            stateAfter = new CompProcState(serverCompressionProc);

            serverCompressionProc.Dispose();
            clientCompressionProc.Dispose();

            Assert.True(stateAfter.LocalRefSet == null ||
                        stateAfter.LocalRefSet.Count == 0);
        }
コード例 #3
0
        public void HeadersList()
        {
            var collection = new HeadersList(new[]
            {
                new KeyValuePair <string, string>("myKey1", "myValue1"),
                new KeyValuePair <string, string>("myKey2", "myValue2"),
                new KeyValuePair <string, string>("myKey3", "myValue3"),
                new KeyValuePair <string, string>("myKey4", "myValue4"),
                new KeyValuePair <string, string>("myKey5", "myValue5"),
                new KeyValuePair <string, string>("myKey6", "myValue6"),
                new KeyValuePair <string, string>("myKey7", "myValue7"),
                new KeyValuePair <string, string>("myKey8", "myValue8"),
                new KeyValuePair <string, string>("myKey9", "myValue9"),
                new KeyValuePair <string, string>("myKey0", "myValue0")
            });

            Assert.Equal(collection.Count, 10);
            Assert.Equal(collection.StoredHeadersSize, 60 + 80 + 32 * collection.Count);

            collection.Add(new KeyValuePair <string, string>("someAddKey1", "someAddValue1"));
            collection.Add(new KeyValuePair <string, string>("someAddKey2", "someAddValue2"));

            Assert.Equal(collection.Count, 12);
            Assert.Equal(collection.StoredHeadersSize, 60 + 80 + 32 * collection.Count + 22 + 26);

            int headersSize = collection.Sum(header => header.Key.Length + header.Value.Length + 32);

            Assert.Equal(collection.StoredHeadersSize, headersSize);
        }
コード例 #4
0
ファイル: Http2Stream.cs プロジェクト: sgrebnov/http2-katana
 //Incoming
 internal Http2Stream(HeadersList headers, int id,
                    WriteQueue writeQueue, FlowControlManager flowCrtlManager, 
                    ICompressionProcessor comprProc, Priority priority = Priority.Pri3)
     : this(id, writeQueue, flowCrtlManager, comprProc, priority)
 {
     Headers = headers;
 }
コード例 #5
0
        /// <summary>
        /// Adopts protocol terms into owin environment.
        /// </summary>
        /// <param name="headers">The headers.</param>
        /// <returns></returns>
        private OwinContext PopulateEnvironment(HeadersList headers)
        {
            var owinContext = new OwinContext();

            var headersAsDict = headers.ToDictionary(header => header.Key, header => new[] {header.Value}, StringComparer.OrdinalIgnoreCase);

            owinContext.Environment[CommonOwinKeys.RequestHeaders] = headersAsDict;
            owinContext.Environment[CommonOwinKeys.ResponseHeaders] = new Dictionary<string, string[]>();

            var owinRequest = owinContext.Request;
            var owinResponse = owinContext.Response;

            owinRequest.Method = headers.GetValue(CommonHeaders.Method);
            owinRequest.Path = headers.GetValue(CommonHeaders.Path);
            owinRequest.CallCancelled = CancellationToken.None;

            owinRequest.Host = headers.GetValue(CommonHeaders.Host);
            owinRequest.PathBase = String.Empty;
            owinRequest.QueryString = String.Empty;
            owinRequest.Body = new MemoryStream();
            owinRequest.Protocol = Protocols.Http2;
            owinRequest.Scheme = headers.GetValue(CommonHeaders.Scheme) == Uri.UriSchemeHttp ? Uri.UriSchemeHttp : Uri.UriSchemeHttps;
            owinRequest.RemoteIpAddress = _transportInfo.RemoteIpAddress;
            owinRequest.RemotePort = Convert.ToInt32(_transportInfo.RemotePort);
            owinRequest.LocalIpAddress = _transportInfo.LocalIpAddress;
            owinRequest.LocalPort = _transportInfo.LocalPort;

            owinResponse.Body = new ResponseStream{Capacity = 16384};

            return owinContext;
        }
コード例 #6
0
        public void NeverIndexedEmission()
        {
            var serverCompressionProc = new CompressionProcessor();
            var header = new KeyValuePair <string, string>("custom-key", "custom-value");

            byte[] index       = { 0x10 };
            byte[] name        = Encoding.UTF8.GetBytes(header.Key);
            byte[] nameLength  = name.Length.ToUVarInt(7);
            byte[] value       = Encoding.UTF8.GetBytes(header.Value);
            byte[] valueLength = value.Length.ToUVarInt(7);

            byte[] encodedHeader = new byte[index.Length + name.Length +
                                            value.Length + nameLength.Length + valueLength.Length];

            // creates encoded header
            int offset = 0;

            Buffer.BlockCopy(index, 0, encodedHeader, 0, index.Length);
            offset += index.Length;
            Buffer.BlockCopy(nameLength, 0, encodedHeader, offset, nameLength.Length);
            offset += nameLength.Length;
            Buffer.BlockCopy(name, 0, encodedHeader, offset, name.Length);
            offset += name.Length;
            Buffer.BlockCopy(valueLength, 0, encodedHeader, offset, valueLength.Length);
            offset += valueLength.Length;
            Buffer.BlockCopy(value, 0, encodedHeader, offset, value.Length);

            HeadersList deserializedHeaders = serverCompressionProc.Decompress(encodedHeader);

            Assert.Equal(deserializedHeaders[0].Key, header.Key);
            Assert.Equal(deserializedHeaders[0].Value, header.Value);
        }
コード例 #7
0
ファイル: Http2Stream.cs プロジェクト: Nangal/http2-katana
        //Outgoing
        internal Http2Stream(int id, WriteQueue writeQueue, FlowControlManager flowCrtlManager, int priority = Constants.DefaultStreamPriority)
        {
            if (id <= 0)
                throw new ArgumentOutOfRangeException("invalid id for stream");

            if (priority < 0 || priority > Constants.MaxPriority)
                throw  new ArgumentOutOfRangeException("priority out of range");

            _id = id;
            Priority = priority;
            _writeQueue = writeQueue;
            _flowCrtlManager = flowCrtlManager;

            _unshippedFrames = new Queue<DataFrame>(16);
            Headers = new HeadersList();

            SentDataAmount = 0;
            ReceivedDataAmount = 0;
            IsFlowControlBlocked = false;
            IsFlowControlEnabled = _flowCrtlManager.IsFlowControlEnabled;
            WindowSize = _flowCrtlManager.StreamsInitialWindowSize;

            _flowCrtlManager.NewStreamOpenedHandler(this);
            OnFrameSent += (sender, args) => FramesSent++;
        }
コード例 #8
0
ファイル: Http2Logger.cs プロジェクト: zhangrl/http2-katana
 public static void LogHeaders(HeadersList headers)
 {
     Console.WriteLine("Headers set:");
     foreach (var header in headers)
     {
         Console.WriteLine("{0}: {1}", header.Key, header.Value);
     }
 }
コード例 #9
0
        /// <summary>
        /// Writes the status header to the stream.
        /// </summary>
        /// <param name="final">if set to <c>true</c> then marks headers frame as final.</param>
        private void SendHeaders(bool final)
        {
            var responseHeaders = new HeadersList(_responseHeaders)
            {
                new KeyValuePair <string, string>(CommonHeaders.Status, _owinContext.Response.StatusCode.ToString(CultureInfo.InvariantCulture))
            };

            _protocolStream.WriteHeadersFrame(responseHeaders, final, true);
        }
コード例 #10
0
        private bool ValidateHeaders(IFormFile file)
        {
            using (var stream = new StreamReader(file.OpenReadStream()))
            {
                var list = stream.ReadLine()?.Split(',');

                return(HeadersList.SequenceEqual(list));
            }
        }
コード例 #11
0
        private void WriteStatus(Http2Stream stream, int statusCode, bool final)
        {
            var headers = new HeadersList
            {
                new KeyValuePair <string, string>(":status", statusCode.ToString()),
            };

            stream.WriteHeadersFrame(headers, final);
        }
コード例 #12
0
        public byte[] Compress(HeadersList headers)
        {
            var toSend = new HeadersList();
            var toDelete = new HeadersList(_remoteRefSet);

            ClearStream(_serializerStream, (int) _serializerStream.Position);

            foreach (var header in headers)
            {
                if (header.Key == null || header.Value == null)
                {
                    throw new InvalidHeaderException(header);
                }
                if (!_remoteRefSet.Contains(header))
                {
                    //Not there, Will send
                    toSend.Add(header);
                }
                else
                {
                    //Already there, don't delete
                    toDelete.Remove(header);
                }
            }

            foreach (var header in toDelete)
            {
                //Anything left in toDelete, should send, so it is deleted from ref set.
                CompressIndexed(header);
                _remoteRefSet.Remove(header); //Update our copy
            }

            foreach (var header in toSend)
            {
                //Send whatever was left in headersCopy
                if (_remoteHeadersTable.Contains(header) || _staticTable.Contains(header))
                {
                    CompressIndexed(header);
                }
                else
                {
                    CompressIncremental(header);
                }

                _remoteRefSet.Add(header);
            }

            _serializerStream.Flush();
            var result = new byte[_serializerStream.Position];

            var streamBuffer = _serializerStream.GetBuffer();

            Buffer.BlockCopy(streamBuffer, 0, result, 0, (int)_serializerStream.Position);

            return result;
        }
コード例 #13
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Compress the header list.
        /// </summary>
        /// <param name="headers">The headers.</param>
        /// <returns>The compressed headers.</returns>
        public byte[] Compress(HeadersList headers)
        {
            var toSend   = new HeadersList();
            var toDelete = new HeadersList(_remoteRefSet);

            ClearStream(_serializerStream, (int)_serializerStream.Position);

            foreach (var header in headers)
            {
                if (header.Key == null || header.Value == null)
                {
                    throw new InvalidHeaderException(header);
                }
                if (!_remoteRefSet.Contains(header))
                {
                    // Not there, Will send
                    toSend.Add(header);
                }
                else
                {
                    // Already there, don't delete
                    toDelete.Remove(header);
                }
            }

            foreach (var header in toDelete)
            {
                // Anything left in toDelete, should send, so it is deleted from ref set.
                CompressIndexed(header);
                _remoteRefSet.Remove(header); // Update our copy
            }

            foreach (var header in toSend)
            {
                // Send whatever was left in headersCopy
                if (_remoteHeadersTable.Contains(header) || Constants.StaticTable.Contains(header))
                {
                    CompressIndexed(header);
                }
                else
                {
                    CompressIncremental(header);
                }

                _remoteRefSet.Add(header);
            }

            _serializerStream.Flush();
            var result = new byte[_serializerStream.Position];

            var streamBuffer = _serializerStream.GetBuffer();

            Buffer.BlockCopy(streamBuffer, 0, result, 0, (int)_serializerStream.Position);

            return(result);
        }
コード例 #14
0
        //Incoming
        internal Http2Stream(HeadersList headers, int id,
                           WriteQueue writeQueue, FlowControlManager flowCrtlManager, 
                           ICompressionProcessor comprProc, int priority = Constants.DefaultStreamPriority)
            : this(id, writeQueue, flowCrtlManager, comprProc, priority)
        {
            if (headers == null)
                throw new ArgumentNullException("cannot create stream with null headers");

            Headers = headers;
        }
コード例 #15
0
        /// <summary>
        /// Writes the status header to the stream.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="statusCode">The status code.</param>
        /// <param name="final">if set to <c>true</c> then marks headers frame as final.</param>
        /// <param name="headers">Additional headers</param>
        private void WriteStatus(Http2Stream stream, int statusCode, bool final, HeadersList headers = null)
        {
            if (headers == null)
            {
                headers = new HeadersList();
            }
            headers.Add(new KeyValuePair <string, string>(CommonHeaders.Status, statusCode.ToString(CultureInfo.InvariantCulture)));

            stream.WriteHeadersFrame(headers, final, true);
        }
コード例 #16
0
 public void SendRequest(HeadersList pairs, int priority, bool isEndStream)
 {
     if (_wereFirstSettingsSent)
     {
         _session.SendRequest(pairs, priority, isEndStream);
     }
     else
     {
         OnFirstSettingsSent += (o, args) => _session.SendRequest(pairs, priority, isEndStream);
     }
 }
コード例 #17
0
ファイル: CompProcState.cs プロジェクト: Nangal/http2-katana
 public CompProcState(CompressionProcessor proc)
 {
     IsSettingHeaderTableSizeReceived = (bool)GetFieldValue(typeof(CompressionProcessor),
         "_isSettingHeaderTableSizeReceived", proc);
     SettingsHeaderTableSize = (int)GetFieldValue(typeof(CompressionProcessor),
         "_settingsHeaderTableSize", proc);
     MaxHeaderByteSize = (int)GetFieldValue(typeof(CompressionProcessor),
         "_maxHeaderByteSize", proc);
     LocalRefSet = (HeadersList)GetFieldValue(typeof(CompressionProcessor),
         "_localRefSet", proc);
 }
コード例 #18
0
ファイル: CompProcState.cs プロジェクト: zhangrl/http2-katana
 public CompProcState(CompressionProcessor proc)
 {
     IsSettingHeaderTableSizeReceived = (bool)GetFieldValue(typeof(CompressionProcessor),
                                                            "_isSettingHeaderTableSizeReceived", proc);
     SettingsHeaderTableSize = (int)GetFieldValue(typeof(CompressionProcessor),
                                                  "_settingsHeaderTableSize", proc);
     MaxHeaderByteSize = (int)GetFieldValue(typeof(CompressionProcessor),
                                            "_maxHeaderByteSize", proc);
     LocalRefSet = (HeadersList)GetFieldValue(typeof(CompressionProcessor),
                                              "_localRefSet", proc);
 }
コード例 #19
0
        private void HandleContinuation(ContinuationFrame contFrame, out Http2Stream stream)
        {
            if (!(_lastFrame is ContinuationFrame || _lastFrame is HeadersFrame))
                throw new ProtocolError(ResetStatusCode.ProtocolError,
                                        "Last frame was not headers or continuation");

            Http2Logger.LogDebug("New continuation with id = " + contFrame.StreamId);

            if (contFrame.StreamId == 0)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError,
                                        "Incoming continuation frame with id = 0");
            }

            var serHeaders = new byte[contFrame.CompressedHeaders.Count];

            Buffer.BlockCopy(contFrame.CompressedHeaders.Array,
                                contFrame.CompressedHeaders.Offset,
                                serHeaders, 0, serHeaders.Length);

            var decomprHeaders = _comprProc.Decompress(serHeaders);
            var contHeaders = new HeadersList(decomprHeaders);
            foreach (var header in contHeaders)
            {
                Http2Logger.LogDebug("Stream {0} header: {1}={2}", contFrame.StreamId, header.Key, header.Value);
            }
            contFrame.Headers.AddRange(contHeaders);
            var sequence = _headersSequences.Find(seq => seq.StreamId == contFrame.StreamId);
            if (sequence == null)
            {
                sequence = new HeadersSequence(contFrame.StreamId, contFrame);
                _headersSequences.Add(sequence);
            }
            else
            {
                sequence.AddHeaders(contFrame);
            }

            if (!sequence.IsComplete)
            {
                stream = null;
                return;
            }

            stream = GetStream(contFrame.StreamId);
            if (stream == null)
            {
                stream = CreateStream(sequence.Headers, contFrame.StreamId, sequence.Priority);
            }
            else
            {
                stream.Headers.AddRange(sequence.Headers);
            }
        }
コード例 #20
0
 public PushPromiseFrame(Int32 streamId, Int32 promisedStreamId,
                         bool isEndPushPromise, HeadersList headers = null)
     : base(new byte[HeadersOffset])
 {
     Contract.Assert(streamId > 0 && promisedStreamId > 0);
     StreamId = streamId;
     FrameType = FrameType.PushPromise;
     FrameLength = Buffer.Length - Constants.FramePreambleSize;
     PromisedStreamId = promisedStreamId;
     Headers = headers ?? new HeadersList();
     IsEndPushPromise = isEndPushPromise;
 }
コード例 #21
0
 public void SendRequest(HeadersList pairs, int priority, bool isEndStream)
 {
     if (_wereFirstSettingsSent)
     {
         _session.SendRequest(pairs, priority, isEndStream);
     }
     else
     {
         OnFirstSettingsSent += (o, args) =>
             {
                 //unsec handled via upgrade handshake
                 if (_isSecure)
                     _session.SendRequest(pairs, priority, isEndStream);
             };
     }
 }
コード例 #22
0
        private void EvictHeaderTableEntries(HeadersList headersTable, HeadersList refTable)
        {
            /* 07 -> 3.3.2
            Whenever the maximum size for the header table is made smaller,
            entries are evicted from the end of the header table until the size
            of the header table is less than or equal to the maximum size. */
            while (headersTable.StoredHeadersSize >= _maxHeaderByteSize && headersTable.Count > 0)
            {
                var header = headersTable[headersTable.Count - 1];
                headersTable.RemoveAt(headersTable.Count - 1);

                /* 07 -> 3.3.2
                Whenever an entry is evicted from the header table, any reference to
                that entry contained by the reference set is removed. */
                if (refTable.Contains(header))
                    refTable.Remove(header);
            }
        }
コード例 #23
0
        public CompressionProcessor(ConnectionEnd end)
        {
            if (end == ConnectionEnd.Client)
            {
                _localHeaderTable = CompressionInitialHeaders.ResponseInitialHeaders;
                _remoteHeaderTable = CompressionInitialHeaders.RequestInitialHeaders;
            }
            else
            {
                _localHeaderTable = CompressionInitialHeaders.RequestInitialHeaders;
                _remoteHeaderTable = CompressionInitialHeaders.ResponseInitialHeaders;
            }
            _localRefSet = new HeadersList();
            _remoteRefSet = new HeadersList();

            InitCompressor();
            InitDecompressor();
        }
コード例 #24
0
 public void SendRequest(HeadersList pairs, int priority, bool isEndStream)
 {
     if (_wereFirstSettingsSent)
     {
         _session.SendRequest(pairs, priority, isEndStream);
     }
     else
     {
         OnFirstSettingsSent += (o, args) =>
         {
             //unsec handled via upgrade handshake
             if (_isSecure)
             {
                 _session.SendRequest(pairs, priority, isEndStream);
             }
         };
     }
 }
コード例 #25
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Header delta compression algorithm.
        /// </summary>
        public HeaderCompression()
        {
            //The initial value is 4,096 bytes.
            _maxHeaderByteSize = 4096;
            _isSettingHeaderTableSizeReceived = false;

            //The header table is initially empty.
            _remoteHeadersTable = new HeadersList();
            _localHeadersTable  = new HeadersList();

            _remoteRefSet = new HeadersList();
            _localRefSet  = new HeadersList();

            _huffmanProc = new Processor();

            InitCompressor();
            InitDecompressor();
        }
コード例 #26
0
ファイル: Http2Tests.cs プロジェクト: zhangrl/http2-katana
        private static HeadersList GetHeadersList(Uri uri)
        {
            const string method  = "get";
            var          path    = uri.PathAndQuery;
            var          version = Protocols.Http2;
            var          scheme  = uri.Scheme;
            var          host    = uri.Host;

            var pairs = new HeadersList
            {
                new KeyValuePair <string, string>(":method", method),
                new KeyValuePair <string, string>(":path", path),
                new KeyValuePair <string, string>(":version", version),
                new KeyValuePair <string, string>(":authority", host + ":" + uri.Port),
                new KeyValuePair <string, string>(":scheme", scheme),
            };

            return(pairs);
        }
コード例 #27
0
        // for outgoing
        public PushPromiseFrame(Int32 streamId, Int32 promisedStreamId, bool hasPadding, bool isEndHeaders,
                                HeadersList headers = null)
        {
            Contract.Assert(streamId > 0 && promisedStreamId > 0);

            int preambleLength = Constants.FramePreambleSize + PromisedIdLength;

            if (hasPadding)
            {
                preambleLength += PadHighLowLength;
            }

            // construct frame without Headers Block and Padding bytes
            Buffer = new byte[preambleLength];

            /* 12 -> 6.6
             * The PUSH_PROMISE frame includes optional padding. Padding fields and
             * flags are identical to those defined for DATA frames. */

            if (hasPadding)
            {
                // generate padding
                var padHigh = (byte)1;
                var padLow  = (byte)new Random().Next(1, 7);

                HasPadHigh = true;
                HasPadLow  = true;
                PadHigh    = padHigh;
                PadLow     = padLow;
            }

            PayloadLength = Buffer.Length - Constants.FramePreambleSize;
            FrameType     = FrameType.PushPromise;
            StreamId      = streamId;

            PromisedStreamId = promisedStreamId;
            IsEndHeaders     = isEndHeaders;

            if (headers != null)
            {
                Headers = headers;
            }
        }
コード例 #28
0
        //localPath should be provided only for post and put cmds
        //serverPostAct should be provided only for post cmd
        private void SubmitRequest(Uri request, string method)
        {
            //Submit request if http2 was chosen
            Http2Logger.LogConsole("Submitting request");

            var headers = new HeadersList
            {
                new KeyValuePair <string, string>(CommonHeaders.Method, method.ToLower()),
                new KeyValuePair <string, string>(CommonHeaders.Path, request.PathAndQuery.ToLower()),
                new KeyValuePair <string, string>(CommonHeaders.Authority, _host.ToLower()),
                new KeyValuePair <string, string>(CommonHeaders.Scheme, _scheme.ToLower()),
            };

            Http2Logger.LogHeaders(headers);

            //Sending request with default  priority
            _sessionAdapter.SendRequest(headers, Constants.DefaultStreamPriority, true);
            Http2Logger.LogConsole("Request sent");
        }
コード例 #29
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Decompress the headers.
        /// </summary>
        /// <param name="serializedHeaders">The serialised headers.</param>
        /// <returns>The header list.</returns>
        public HeadersList Decompress(byte[] serializedHeaders)
        {
            try
            {
                _currentOffset = 0;
                var unindexedHeadersList = new HeadersList();

                while (_currentOffset != serializedHeaders.Length)
                {
                    var entry = ParseHeader(serializedHeaders);

                    // parsed indexed header which was already in the refSet
                    if (entry == null)
                    {
                        continue;
                    }

                    var header = new KeyValuePair <string, string>(entry.Item1, entry.Item2);

                    if (entry.Item3 == IndexationType.WithoutIndexation ||
                        entry.Item3 == IndexationType.NeverIndexed)
                    {
                        unindexedHeadersList.Add(header);
                    }
                }

                // Base result on already modified reference set
                var result = new HeadersList(_localRefSet);

                // Add to result Without indexation and Never Indexed
                // They were not added into reference set
                result.AddRange(unindexedHeadersList);

                ProcessCookie(result);

                return(result);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
コード例 #30
0
        public CompressionProcessor(ConnectionEnd end)
        {
            //default max headers table size
            _maxHeaderByteSize = 4096;

            //05 The header table is initially empty.
            _remoteHeadersTable = new HeadersList();
            _localHeadersTable = new HeadersList();

            //05 The reference set is initially empty.
            _remoteRefSet = new HeadersList();
            _localRefSet = new HeadersList();

            _huffmanProc = new HuffmanCompressionProcessor();

            _localEnd = end;

            InitCompressor();
            InitDecompressor();
        }
コード例 #31
0
        public CompressionProcessor()
        {
            /* 12 -> 6.5.2
             * The initial value is 4,096 bytes. */
            _maxHeaderByteSize = 4096;
            _isSettingHeaderTableSizeReceived = false;

            /* 07 -> 3.1.2
             * The header table is initially empty. */
            _remoteHeadersTable = new HeadersList();
            _localHeadersTable  = new HeadersList();

            _remoteRefSet = new HeadersList();
            _localRefSet  = new HeadersList();

            _huffmanProc = new HuffmanCompressionProcessor();

            InitCompressor();
            InitDecompressor();
        }
コード例 #32
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Evict header table entry.
        /// </summary>
        /// <param name="headersTable"></param>
        /// <param name="refTable"></param>
        private void EvictHeaderTableEntries(HeadersList headersTable, HeadersList refTable)
        {
            /* 07 -> 3.3.2
             * Whenever the maximum size for the header table is made smaller,
             * entries are evicted from the end of the header table until the size
             * of the header table is less than or equal to the maximum size. */
            while (headersTable.StoredHeadersSize >= _maxHeaderByteSize && headersTable.Count > 0)
            {
                var header = headersTable[headersTable.Count - 1];
                headersTable.RemoveAt(headersTable.Count - 1);

                /* 07 -> 3.3.2
                 * Whenever an entry is evicted from the header table, any reference to
                 * that entry contained by the reference set is removed. */
                if (refTable.Contains(header))
                {
                    refTable.Remove(header);
                }
            }
        }
コード例 #33
0
ファイル: Http2Stream.cs プロジェクト: sgrebnov/http2-katana
        //Outgoing
        internal Http2Stream(int id, WriteQueue writeQueue, FlowControlManager flowCrtlManager,
                           ICompressionProcessor comprProc, Priority priority = Priority.Pri3)
        {
            _id = id;
            Priority = priority;
            _writeQueue = writeQueue;
            _compressionProc = comprProc;
            _flowCrtlManager = flowCrtlManager;

            _unshippedFrames = new Queue<DataFrame>(16);
            Headers = new HeadersList();

            SentDataAmount = 0;
            ReceivedDataAmount = 0;
            IsFlowControlBlocked = false;
            IsFlowControlEnabled = _flowCrtlManager.IsStreamsFlowControlledEnabled;
            WindowSize = _flowCrtlManager.StreamsInitialWindowSize;

            _flowCrtlManager.NewStreamOpenedHandler(this);
        }
コード例 #34
0
        public CompressionProcessor()
        {
            /* 12 -> 6.5.2
            The initial value is 4,096 bytes. */
            _maxHeaderByteSize = 4096;
            _isSettingHeaderTableSizeReceived = false;

            /* 07 -> 3.1.2
            The header table is initially empty. */
            _remoteHeadersTable = new HeadersList();
            _localHeadersTable = new HeadersList();

            _remoteRefSet = new HeadersList();
            _localRefSet = new HeadersList();

            _huffmanProc = new HuffmanCompressionProcessor();

            InitCompressor();
            InitDecompressor();
        }
コード例 #35
0
        protected static Http2Stream SubmitRequest(Http2Session session, Uri uri)
        {
            const string method  = "get";
            string       path    = uri.PathAndQuery;
            string       version = Protocols.Http2;
            string       scheme  = uri.Scheme;
            string       host    = uri.Host;

            var pairs = new HeadersList
            {
                new KeyValuePair <string, string>(":method", method),
                new KeyValuePair <string, string>(":path", path),
                new KeyValuePair <string, string>(":version", version),
                new KeyValuePair <string, string>(":host", host),
                new KeyValuePair <string, string>(":scheme", scheme),
            };

            session.SendRequest(pairs, Priority.None, false);

            return(session.ActiveStreams[1]);
        }
コード例 #36
0
ファイル: HeaderDelta.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Insert to headers table.
        /// </summary>
        /// <param name="header">The header.</param>
        /// <param name="refSet">The refernced header list.</param>
        /// <param name="headersTable">The header list.</param>
        private void InsertToHeadersTable(KeyValuePair <string, string> header, HeadersList refSet,
                                          HeadersList headersTable)
        {
            /* 07 -> 3.3.1
             * The size of an entry is the sum of its name's length in octets (as
             * defined in Section 4.1.2), of its value's length in octets
             * (Section 4.1.2) and of 32 octets. */
            int headerLen = header.Key.Length + header.Value.Length + 32;

            /* 07 -> 3.3.2
             * Whenever a new entry is to be added to the table, any name referenced
             * by the representation of this new entry is cached, and then entries
             * are evicted from the end of the header table until the size of the
             * header table is less than or equal to (maximum size - new entry
             * size), or until the table is empty.
             *
             * If the size of the new entry is less than or equal to the maximum
             * size, that entry is added to the table.  It is not an error to
             * attempt to add an entry that is larger than the maximum size. */

            while (headersTable.StoredHeadersSize + headerLen >= _maxHeaderByteSize && headersTable.Count > 0)
            {
                headersTable.RemoveAt(headersTable.Count - 1);

                /* 07 -> 3.3.2
                 * Whenever an entry is evicted from the header table, any reference to
                 * that entry contained by the reference set is removed. */

                if (refSet.Contains(header))
                {
                    refSet.Remove(header);
                }
            }

            /* 07 -> 3.2.1
             * We should always insert into
             * begin of the headers table. */
            headersTable.Insert(0, header);
        }
コード例 #37
0
        //localPath should be provided only for post and put cmds
        //serverPostAct should be provided only for post cmd
        private void SubmitRequest(Uri request, string method, string localPath = null, string serverPostAct = null)
        {
            var headers = new HeadersList
            {
                new KeyValuePair <string, string>(":method", method),
                new KeyValuePair <string, string>(":path", request.PathAndQuery),
                new KeyValuePair <string, string>(":version", _version),
                new KeyValuePair <string, string>(":host", _host),
                new KeyValuePair <string, string>(":scheme", _scheme),
            };

            if (!String.IsNullOrEmpty(localPath))
            {
                headers.Add(new KeyValuePair <string, string>(":localPath".ToLower(), localPath));
            }

            if (!String.IsNullOrEmpty(serverPostAct))
            {
                headers.Add(new KeyValuePair <string, string>(":serverPostAct".ToLower(), serverPostAct));
            }

            //Sending request with average priority
            _clientSession.SendRequest(headers, Priority.None, false);
        }
コード例 #38
0
        // for outgoing
        public PushPromiseFrame(Int32 streamId, Int32 promisedStreamId, bool hasPadding, bool isEndHeaders,
            HeadersList headers = null)
        {
            Contract.Assert(streamId > 0 && promisedStreamId > 0);

            int preambleLength = Constants.FramePreambleSize + PromisedIdLength;
            if (hasPadding) preambleLength += PadHighLowLength;

            // construct frame without Headers Block and Padding bytes
            Buffer = new byte[preambleLength];

            /* 12 -> 6.6 
            The PUSH_PROMISE frame includes optional padding. Padding fields and
            flags are identical to those defined for DATA frames. */

            if (hasPadding)
            {
                // generate padding
                var padHigh = (byte)1;
                var padLow = (byte)new Random().Next(1, 7);

                HasPadHigh = true;
                HasPadLow = true;
                PadHigh = padHigh;
                PadLow = padLow;
            }

            PayloadLength = Buffer.Length - Constants.FramePreambleSize;
            FrameType = FrameType.PushPromise;
            StreamId = streamId;

            PromisedStreamId = promisedStreamId;
            IsEndHeaders = isEndHeaders;

            if (headers != null) Headers = headers;
        }
コード例 #39
0
ファイル: BasicTests.cs プロジェクト: skoant/http2-katana
        public void CompressionSuccessful()
        {
            var clientHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":method", "get"),
                new KeyValuePair <string, string>(":path", "/test.txt"),
                new KeyValuePair <string, string>(":version", Protocols.Http2),
                new KeyValuePair <string, string>(":host", "localhost"),
                new KeyValuePair <string, string>(":scheme", "http"),
            };
            var clientCompressor   = new CompressionProcessor(ConnectionEnd.Client);
            var serverDecompressor = new CompressionProcessor(ConnectionEnd.Server);

            var serializedHeaders   = clientCompressor.Compress(clientHeaders);
            var decompressedHeaders = new HeadersList(serverDecompressor.Decompress(serializedHeaders));

            foreach (var t in clientHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }

            var serverHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":status", StatusCode.Code200Ok.ToString()),
            };
            var serverCompressor   = new CompressionProcessor(ConnectionEnd.Server);
            var clientDecompressor = new CompressionProcessor(ConnectionEnd.Client);

            serializedHeaders   = serverCompressor.Compress(serverHeaders);
            decompressedHeaders = new HeadersList(clientCompressor.Decompress(serializedHeaders));

            foreach (var t in serverHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }
        }
コード例 #40
0
ファイル: Http2Session.cs プロジェクト: sgrebnov/http2-katana
        /// <summary>
        /// Sends the headers with request headers.
        /// </summary>
        /// <param name="pairs">The header pairs.</param>
        /// <param name="priority">The stream priority.</param>
        /// <param name="isEndStream">True if initial headers+priority is also the final frame from endpoint.</param>
        public void SendRequest(HeadersList pairs, Priority priority, bool isEndStream)
        {
            var stream = CreateStream(priority);

            stream.WriteHeadersFrame(pairs, isEndStream, true);

            if (OnRequestSent != null)
            {
                OnRequestSent(this, new RequestSentEventArgs(stream));
            }
        }
コード例 #41
0
 /// <summary>
 /// Writes the status header to the stream.
 /// </summary>
 /// <param name="final">if set to <c>true</c> then marks headers frame as final.</param>
 private void SendHeaders(bool final)
 {
     var responseHeaders = new HeadersList(_responseHeaders)
         {
             new KeyValuePair<string, string>(CommonHeaders.Status, _owinContext.Response.StatusCode.ToString(CultureInfo.InvariantCulture))
         };
     _protocolStream.WriteHeadersFrame(responseHeaders, final, true);
 }
コード例 #42
0
        //localPath should be provided only for post and put cmds
        //serverPostAct should be provided only for post cmd
        private void SubmitRequest(Uri request, string method, string localPath = null, string serverPostAct = null)
        {
            var headers = new HeadersList
                {
                    new KeyValuePair<string, string>(CommonHeaders.Method, method),
                    new KeyValuePair<string, string>(CommonHeaders.Path, request.PathAndQuery),
                    new KeyValuePair<string, string>(CommonHeaders.Version, _version),
                    new KeyValuePair<string, string>(CommonHeaders.Host, _host),
                    new KeyValuePair<string, string>(CommonHeaders.Scheme, _scheme),
                };

            //Put and post handling
            /*if (!String.IsNullOrEmpty(localPath))
            {
                headers.Add(new KeyValuePair<string, string>(":localPath".ToLower(), localPath));
            }

            if (!String.IsNullOrEmpty(serverPostAct))
            {
                headers.Add(new KeyValuePair<string, string>(":serverPostAct".ToLower(), serverPostAct));
            }*/
                //Sending request with default  priority
            _sessionAdapter.SendRequest(headers, Constants.DefaultStreamPriority, false);
        }
コード例 #43
0
        //localPath should be provided only for post and put cmds
        //serverPostAct should be provided only for post cmd
        private void SubmitRequest(Uri request, string method, string localPath = null, string serverPostAct = null)
        {
            var headers = new HeadersList
                {
                    new KeyValuePair<string, string>(":method", method),
                    new KeyValuePair<string, string>(":path", request.PathAndQuery),
                    new KeyValuePair<string, string>(":version", _version),
                    new KeyValuePair<string, string>(":host", _host),
                    new KeyValuePair<string, string>(":scheme", _scheme),
                };

            if (!String.IsNullOrEmpty(localPath))
            {
                headers.Add(new KeyValuePair<string, string>(":localPath".ToLower(), localPath));
            }

            if (!String.IsNullOrEmpty(serverPostAct))
            {
                headers.Add(new KeyValuePair<string, string>(":serverPostAct".ToLower(), serverPostAct));
            }

            //Sending request with average priority
            _clientSession.SendRequest(headers, Priority.None, false);
        }
コード例 #44
0
        /// <summary>
        /// Write the response status and compressed header.
        /// </summary>
        /// <param name="writeEndOfHeaders">Write the end of the header bytes, carrige return line feed.</param>
        /// <param name="writeResponseStatus">Write the response status (:status = 200).</param>
        /// <param name="compressed">Compress the headers.</param>
        /// <param name="headerFrame">Only header frame types are supported.</param>
        public void WriteResponseHeaders(bool writeEndOfHeaders = true, bool writeResponseStatus         = true,
                                         bool compressed        = true, Protocol.OpCodeFrame headerFrame = Protocol.OpCodeFrame.Headers)
        {
            byte[]      buffer  = null;
            string      data    = "";
            HeadersList headers = new HeadersList();

            // If chunked is used.
            if (SendChunked)
            {
                AddHeader("Transfer-Encoding", "Chunked");
            }

            // If the server has been specified.
            if (!String.IsNullOrEmpty(Server))
            {
                AddHeader("Server", Server);
            }

            // If content length has been specified.
            if (ContentLength > 0)
            {
                AddHeader("Content-Length", ContentLength.ToString());
            }

            // If the allow has been specified.
            if (!String.IsNullOrEmpty(Allow))
            {
                AddHeader("Allow", Allow);
            }

            // If the content type has been specified.
            if (!String.IsNullOrEmpty(ContentType))
            {
                AddHeader("Content-Type", ContentType);
            }

            // If the Upgrade has been specified.
            if (!String.IsNullOrEmpty(Upgrade))
            {
                // If an upgrade is required
                // then set the connection to upgrade
                // and set the upgrade to the protocol (e.g. WebSocket, HTTP/2.0 .. etc).
                AddHeader("Connection", "Upgrade");
                AddHeader("Upgrade", Upgrade);
            }
            else
            {
                // If the connection is open.
                if (KeepAlive)
                {
                    AddHeader("Connection", "Keep-Alive");
                }
            }

            // If the content encoding has been specified.
            if (!String.IsNullOrEmpty(ContentEncoding))
            {
                AddHeader("Content-Encoding", ContentEncoding);
            }

            // If the content lanaguage has been specified.
            if (!String.IsNullOrEmpty(ContentLanguage))
            {
                AddHeader("Content-Language", ContentLanguage);
            }

            // If authenticate type is other than none.
            if (AuthorizationType != Nequeo.Security.AuthenticationType.None)
            {
                AddHeader("WWW-Authenticate", AuthorizationType.ToString());
            }

            // Write response status.
            if (writeResponseStatus)
            {
                // Compress the headers
                if (compressed)
                {
                    // Set the response status.
                    headers.Add(new KeyValuePair <string, string>(":status", StatusCode.ToString() + (StatusSubcode > 0 ? "." + StatusSubcode.ToString() : "")));
                }
                else
                {
                    // Send the http response status.
                    data   = ":status = " + StatusCode.ToString() + (StatusSubcode > 0 ? "." + StatusSubcode.ToString() : "") + _deli;
                    buffer = Encoding.Default.GetBytes(data);
                    Write(buffer, 0, buffer.Length);
                }
            }

            // If headers exists.
            if (Headers != null)
            {
                // For each header found.
                foreach (string header in Headers.AllKeys)
                {
                    // Compress the headers
                    if (compressed)
                    {
                        // Add each header.
                        headers.Add(new KeyValuePair <string, string>(header.ToLower(), Headers[header]));
                    }
                    else
                    {
                        // Add each header.
                        data   = header.ToLower() + " = " + Headers[header] + _deli;
                        buffer = Encoding.Default.GetBytes(data);
                        Write(buffer, 0, buffer.Length);
                    }
                }
            }

            // If cookies exists.
            if (Cookies != null)
            {
                // For each cookie found.
                foreach (Cookie cookie in Cookies)
                {
                    // Make shore the cookie has been set.
                    if (!String.IsNullOrEmpty(cookie.Name) && !String.IsNullOrEmpty(cookie.Value))
                    {
                        // Compress the headers
                        if (compressed)
                        {
                            // Get the cookie details.
                            headers.Add(new KeyValuePair <string, string>("set-cookie",
                                                                          cookie.Name + "=" + cookie.Value +
                                                                          (cookie.Expires != null ? "; Expires=" + cookie.Expires.ToUniversalTime().ToLongDateString() + " " + cookie.Expires.ToUniversalTime().ToLongTimeString() + " GMT" : "") +
                                                                          (!String.IsNullOrEmpty(cookie.Path) ? "; Path=" + cookie.Path : "") +
                                                                          (!String.IsNullOrEmpty(cookie.Domain) ? "; Domain=" + cookie.Domain : "") +
                                                                          (cookie.Version > 0 ? "; Version=" + cookie.Version : "") +
                                                                          (cookie.Secure ? "; Secure" : "") +
                                                                          (cookie.HttpOnly ? "; HttpOnly" : "")
                                                                          ));
                        }
                        else
                        {
                            // Get the cookie details.
                            data = "Set-Cookie" + ": " + cookie.Name + "=" + cookie.Value +
                                   (cookie.Expires != null ? "; Expires=" + cookie.Expires.ToUniversalTime().ToLongDateString() + " " + cookie.Expires.ToUniversalTime().ToLongTimeString() + " GMT" : "") +
                                   (!String.IsNullOrEmpty(cookie.Path) ? "; Path=" + cookie.Path : "") +
                                   (!String.IsNullOrEmpty(cookie.Domain) ? "; Domain=" + cookie.Domain : "") +
                                   (cookie.Version > 0 ? "; Version=" + cookie.Version : "") +
                                   (cookie.Secure ? "; Secure" : "") +
                                   (cookie.HttpOnly ? "; HttpOnly" : "") +
                                   _deli;

                            // Write to the stream.
                            buffer = Encoding.Default.GetBytes(data);
                            Write(buffer, 0, buffer.Length);
                        }
                    }
                }
            }

            // Compress the headers
            if (compressed)
            {
                // Compress the headers.
                buffer = Utility.CompressHeaders(headers);
                Write(buffer, 0, buffer.Length);
            }
            else
            {
                // Write the end of the headers.
                if (writeEndOfHeaders)
                {
                    // Send the header end space.
                    data   = _deli;
                    buffer = Encoding.Default.GetBytes(data);
                    Write(buffer, 0, buffer.Length);
                }
            }
        }
コード例 #45
0
 public SizedHeadersList(HeadersList headers)
     : base(headers)
 {
 }
コード例 #46
0
ファイル: Http2Session.cs プロジェクト: sgrebnov/http2-katana
        public Http2Session(SecureSocket sessionSocket, ConnectionEnd end, 
                            bool usePriorities, bool useFlowControl,
                            IDictionary<string, object> handshakeResult = null)
        {
            _ourEnd = end;
            _usePriorities = usePriorities;
            _useFlowControl = useFlowControl;
            _handshakeHeaders = new Dictionary<string, string>(16);
            ApplyHandshakeResults(handshakeResult);

            if (_ourEnd == ConnectionEnd.Client)
            {
                _remoteEnd = ConnectionEnd.Server;
                _lastId = -1; // Streams opened by client are odd
            }
            else
            {
                _remoteEnd = ConnectionEnd.Client;
                _lastId = 0; // Streams opened by server are even
            }

            _goAwayReceived = false;
            _settingsManager = new SettingsManager();
            _comprProc = new CompressionProcessor(_ourEnd);
            _sessionSocket = sessionSocket;

            _frameReader = new FrameReader(_sessionSocket);

            ActiveStreams = new ActiveStreams();

            _writeQueue = new WriteQueue(_sessionSocket, ActiveStreams, _usePriorities);

            if (_sessionSocket != null && sessionSocket.SecureProtocol == SecureProtocol.None)
            {
                OurMaxConcurrentStreams = int.Parse(_handshakeHeaders[":max_concurrent_streams"]);
                RemoteMaxConcurrentStreams = int.Parse(_handshakeHeaders[":max_concurrent_streams"]);
                InitialWindowSize = int.Parse(_handshakeHeaders[":initial_window_size"]);
            }
            else
            {
                OurMaxConcurrentStreams = 100; //Spec recommends value 100 by default
                RemoteMaxConcurrentStreams = 100;
                InitialWindowSize = 2000000;
            }
            _flowControlManager = new FlowControlManager(this);

            if (!_useFlowControl)
            {
                _flowControlManager.Options = (byte) FlowControlOptions.DontUseFlowControl;
            }

            SessionWindowSize = 0;
            _toBeContinuedHeaders = new HeadersList();
        }
コード例 #47
0
ファイル: Http2Stream.cs プロジェクト: Nangal/http2-katana
        public void WriteHeadersFrame(HeadersList headers, bool isEndStream, bool isEndHeaders)
        {
            if (headers == null)
                throw new ArgumentNullException("headers is null");

            if (Closed)
                return;

            var frame = new HeadersFrame(_id, true)
                {
                    IsEndHeaders = isEndHeaders,
                    IsEndStream = isEndStream,
                    Headers = headers,
                };

            _writeQueue.WriteFrame(frame);

            if (frame.IsEndStream)
            {
                HalfClosedLocal = true;
            }
            else if (ReservedLocal)
            {
                HalfClosedRemote = true;
            }

            if (OnFrameSent != null)
            {
                OnFrameSent(this, new FrameSentEventArgs(frame));
            }
        }
コード例 #48
0
        public void HeadersCompression()
        {
            var clientHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":method", "get"),
                new KeyValuePair <string, string>(":path", "/Y3A9NTcuNjE2NjY1fjM5Ljg2NjY2NSZsdmw9NyZzdHk9ciZxPVlhcm9zbGF2bA=="),
                new KeyValuePair <string, string>(":version", Protocols.Http2),
                new KeyValuePair <string, string>(":host", "localhost"),
                new KeyValuePair <string, string>(":scheme", "https"),
            };
            var clientCompressionProc = new CompressionProcessor();
            var serverCompressionProc = new CompressionProcessor();

            var serializedHeaders   = clientCompressionProc.Compress(clientHeaders);
            var decompressedHeaders = new HeadersList(serverCompressionProc.Decompress(serializedHeaders));

            foreach (var t in clientHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }

            var serverHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":method", "get"),
                new KeyValuePair <string, string>(":path", "/simpleTest.txt"),
                new KeyValuePair <string, string>(":version", Protocols.Http2),
                new KeyValuePair <string, string>(":host", "localhost"),
                new KeyValuePair <string, string>(":scheme", "https"),
            };

            serializedHeaders   = serverCompressionProc.Compress(serverHeaders);
            decompressedHeaders = new HeadersList(clientCompressionProc.Decompress(serializedHeaders));

            foreach (var t in serverHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }

            serverHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":status", StatusCode.Code404NotFound.ToString(CultureInfo.InvariantCulture)),
            };

            serializedHeaders   = serverCompressionProc.Compress(serverHeaders);
            decompressedHeaders = new HeadersList(clientCompressionProc.Decompress(serializedHeaders));

            foreach (var t in serverHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }

            serverHeaders = new HeadersList
            {
                new KeyValuePair <string, string>("content-type", "text/plain"),
                new KeyValuePair <string, string>("last-modified", "Wed, 23 Oct 2013 21:32:06 GMT"),
                new KeyValuePair <string, string>("etag", "1cedo15cb041fc1"),
                new KeyValuePair <string, string>("content-length", "749761"),
                new KeyValuePair <string, string>(":status", StatusCode.Code200Ok.ToString(CultureInfo.InvariantCulture)),
            };

            serializedHeaders   = serverCompressionProc.Compress(serverHeaders);
            decompressedHeaders = new HeadersList(clientCompressionProc.Decompress(serializedHeaders));

            foreach (var t in serverHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }

            clientHeaders = new HeadersList
            {
                new KeyValuePair <string, string>(":method", "get"),
                new KeyValuePair <string, string>(":path", "/index.html"),
                new KeyValuePair <string, string>(":version", Protocols.Http2),
                new KeyValuePair <string, string>(":host", "localhost"),
                new KeyValuePair <string, string>(":scheme", "https"),
            };

            serializedHeaders   = clientCompressionProc.Compress(clientHeaders);
            decompressedHeaders = new HeadersList(serverCompressionProc.Decompress(serializedHeaders));

            foreach (var t in clientHeaders)
            {
                Assert.Equal(decompressedHeaders.GetValue(t.Key), t.Value);
            }
        }
コード例 #49
0
        /// <summary>
        /// Sends the headers with request headers.
        /// </summary>
        /// <param name="pairs">The header pairs.</param>
        /// <param name="priority">The stream priority.</param>
        /// <param name="isEndStream">True if initial headers+priority is also the final frame from endpoint.</param>
        public void SendRequest(HeadersList pairs, int priority, bool isEndStream)
        {
            if (_ourEnd == ConnectionEnd.Server)
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Server should not initiate request");

            if (pairs == null)
                throw new ArgumentNullException("pairs is null");

            if (priority < 0 || priority > Constants.MaxPriority)
                throw new ArgumentOutOfRangeException("priority is not between 0 and MaxPriority");

            var path = pairs.GetValue(CommonHeaders.Path);

            if (path == null)
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Invalid request ex");

            //09 -> 8.2.2.  Push Responses
            //Once a client receives a PUSH_PROMISE frame and chooses to accept the
            //pushed resource, the client SHOULD NOT issue any requests for the
            //promised resource until after the promised stream has closed.
            if (_promisedResources.ContainsValue(path))
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Resource has been promised. Client should not request it.");

            var stream = CreateStream(priority);

            stream.WriteHeadersFrame(pairs, isEndStream, true);

            var streamSequence = _headersSequences.Find(stream.Id);
            streamSequence.AddHeaders(new HeadersFrame(stream.Id, stream.Priority) { Headers = pairs });

            if (OnRequestSent != null)
            {
                OnRequestSent(this, new RequestSentEventArgs(stream));
            }
        }
コード例 #50
0
        /// <summary>
        /// Creates stream.
        /// </summary>
        /// <param name="headers"></param>
        /// <param name="streamId"></param>
        /// <param name="priority"></param>
        /// <returns></returns>
        public Http2Stream CreateStream(HeadersList headers, int streamId, int priority = -1)
        {

            if (headers == null)
                throw new ArgumentNullException("pairs is null");

            if (priority == -1)
                priority = Constants.DefaultStreamPriority;

            if (priority < 0 || priority > Constants.MaxPriority)
                throw new ArgumentOutOfRangeException("priority is not between 0 and MaxPriority");

            if (ActiveStreams.GetOpenedStreamsBy(_remoteEnd) + 1 > OurMaxConcurrentStreams)
            {
                throw new MaxConcurrentStreamsLimitException();
            }

            var stream = new Http2Stream(headers, streamId,
                                         _writeQueue, _flowControlManager, priority);

            var streamSequence = new HeadersSequence(streamId, (new HeadersFrame(streamId, priority){Headers = headers}));
            _headersSequences.Add(streamSequence);

            ActiveStreams[stream.Id] = stream;

            stream.OnFrameSent += (o, args) =>
                {
                    if (!(args.Frame is IHeadersFrame))
                        return;

                    var streamSeq = _headersSequences.Find(stream.Id);
                    streamSeq.AddHeaders(args.Frame as IHeadersFrame);
                };

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

                    var streamSeq = _headersSequences.Find(stream.Id);

                    if (streamSeq != null)
                        _headersSequences.Remove(streamSeq);
                };

            return stream;
        }
コード例 #51
0
        private void HandleHeaders(HeadersFrame headersFrame, out Http2Stream stream)
        {
            Http2Logger.LogDebug("New headers with id = " + headersFrame.StreamId);

            //spec 06:
            //If a HEADERS frame
            //is received whose stream identifier field is 0x0, the recipient MUST
            //respond with a connection error (Section 5.4.1) of type
            //PROTOCOL_ERROR [PROTOCOL_ERROR].
            if (headersFrame.StreamId == 0)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Incoming headers frame with id = 0");
            }

            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);
            foreach (var header in headers)
            {
                Http2Logger.LogDebug("Stream {0} header: {1}={2}", headersFrame.StreamId, header.Key, header.Value);
            }
            headersFrame.Headers.AddRange(headers);

            var sequence = _headersSequences.Find(seq => seq.StreamId == headersFrame.StreamId);
            if (sequence == null)
            {
                sequence = new HeadersSequence(headersFrame.StreamId, headersFrame);
                _headersSequences.Add(sequence);
            }
            else
            {
                sequence.AddHeaders(headersFrame);
            }

            if (headersFrame.HasPriority)
            {
                sequence.Priority = headersFrame.Priority;
            }

            if (!sequence.IsComplete)
            {
                stream = null;
                return;
            }

            stream = GetStream(headersFrame.StreamId);
            if (stream == null)
            {
                stream = CreateStream(sequence.Headers, headersFrame.StreamId, sequence.Priority);
            }
            else
            {
                stream.Headers.AddRange(sequence.Headers);
            }
        }
コード例 #52
0
ファイル: Utility.cs プロジェクト: waffle-iron/nequeo
        /// <summary>
        /// Process a continuation frame request.
        /// </summary>
        /// <param name="httpContext">The current http context.</param>
        /// <param name="continuationFrame">The continuation frame.</param>
        /// <param name="stream">The selected stream context.</param>
        /// <param name="canPassContext">Can the data be sent to the client context.</param>
        private static void ProcessContinuationFrameRequest(Nequeo.Net.Http2.HttpContext httpContext,
                                                            ContinuationFrame continuationFrame, out ContextStream stream, out bool canPassContext)
        {
            // The data can be sent to the client
            // through the http context session.
            canPassContext = false;

            /*  CONTINUATION frames MUST be associated with a stream. If a CONTINUATION
             *  frame is received whose stream identifier field is 0x0, the recipient MUST
             *  respond with a connection error of type PROTOCOL_ERROR. */
            if (continuationFrame.StreamId == 0)
            {
                throw new ProtocolError(ErrorCodeRegistry.Protocol_Error, "Incoming continuation frame with stream id is equal to 0.");
            }

            // Attempt to get the sepcific stream.
            stream = httpContext.GetStream(continuationFrame.StreamId);
            if (stream == null)
            {
                throw new MaxConcurrentStreamsLimitException();
            }

            // Get the number of compressed headers.
            var serializedHeaders = new byte[continuationFrame.CompressedHeaders.Count];

            // Copy the compressed frame.
            Buffer.BlockCopy(continuationFrame.CompressedHeaders.Array, continuationFrame.CompressedHeaders.Offset, serializedHeaders, 0, serializedHeaders.Length);

            // Decompress the compressed headers.
            HeadersList decompressedHeaders = new HeaderCompression().Decompress(serializedHeaders);
            HeadersList headers             = new HeadersList(decompressedHeaders);

            // Add the list of headers.
            foreach (KeyValuePair <string, string> header in headers)
            {
                stream.HttpRequest.OriginalHeaders.Add(new NameValue()
                {
                    Name = header.Key, Value = header.Value
                });
            }

            // Determine if all headers have been found.
            if (continuationFrame.IsEndHeaders)
            {
                // The end of the headers has been found.
                stream.HttpRequest.HeadersFound = true;
            }

            bool wasValidated = false;

            // Check the current stream state.
            if (stream.Idle || stream.ReservedRemote)
            {
                // Validate all the headers.
                httpContext.ValidateHeaders(stream);
                wasValidated = true;
            }
            else if (stream.Opened || stream.HalfClosedLocal)
            {
                // Validate all the headers.
                httpContext.ValidateHeaders(stream);
                wasValidated = true;
            }
            else if (stream.HalfClosedRemote)
            {
                // Half closed remote stream.
                throw new ProtocolError(ErrorCodeRegistry.Protocol_Error, "Continuation for half closed remote stream.");
            }
            else
            {
                // Stream has no state error.
                throw new StreamNotFoundException(continuationFrame.StreamId);
            }

            // If the headers where validated.
            if (wasValidated)
            {
                // If headers have been found.
                if (stream.HttpRequest.HeadersFound)
                {
                    // Set the current stream id
                    httpContext.StreamId           = stream.StreamId;
                    stream.HttpRequest.IsEndOfData = continuationFrame.IsEndStream;

                    // Get the request resources.
                    RequestResource resource = Nequeo.Net.Http2.Utility.GetRequestResource(stream.HttpRequest.OriginalHeaders);

                    // Assign the http request content.
                    stream.HttpRequest.ReadRequestHeaders(stream.HttpRequest.OriginalHeaders, resource);

                    // If this is the last bit of data
                    // that has been sent then sent
                    // the data to the client context.
                    if (continuationFrame.IsEndStream)
                    {
                        canPassContext = true;
                    }
                }
            }
        }
コード例 #53
0
ファイル: Http2Session.cs プロジェクト: sgrebnov/http2-katana
        /// <summary>
        /// Creates stream.
        /// </summary>
        /// <param name="headers"></param>
        /// <param name="streamId"></param>
        /// <returns></returns>
        private Http2Stream CreateStream(HeadersList headers, int streamId)
        {
            if (ActiveStreams.GetOpenedStreamsBy(_remoteEnd) + 1 > OurMaxConcurrentStreams)
            {
                //Remote side tries to open more streams than allowed
                Dispose();
                throw new InvalidOperationException("Trying to create more streams than allowed!");
            }

            var stream = new Http2Stream(headers, 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");
                }
            };

            return stream;
        }
コード例 #54
0
ファイル: Http2Stream.cs プロジェクト: Nangal/http2-katana
        //TODO Think about: writing push_promise is available in any time now. Need to handle it.
        public void WritePushPromise(IDictionary<string, string[]> pairs, Int32 promisedId)
        {
            if (Id % 2 != 0 && promisedId % 2 != 0)
                throw new InvalidOperationException("Client cant send push_promise frames");

            if (Closed)
                return;

            var headers = new HeadersList(pairs);
            var frame = new PushPromiseFrame(Id, promisedId, true, true, headers);

            ReservedLocal = true;

            _writeQueue.WriteFrame(frame);

            if (OnFrameSent != null)
            {
                OnFrameSent(this, new FrameSentEventArgs(frame));
            }
        }
コード例 #55
0
ファイル: Http2Session.cs プロジェクト: sgrebnov/http2-katana
        /// <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.Count != 0)
            {
                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.AddRange(decompressedHeaders);
                            _toBeContinuedFrame = headersFrame;
                            break;
                        }

                        headers.AddRange(_toBeContinuedHeaders);
                        _toBeContinuedHeaders.Clear();
                        _toBeContinuedFrame = null;
                        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)
                        {
                            if (_ourEnd == ConnectionEnd.Server)
                            {
                                string path = headers.GetValue(":path");
                                if (path == null)
                                {
                                    path = _handshakeHeaders.ContainsKey(":path")
                                               ? _handshakeHeaders[":path"]
                                               : @"\index.html";
                                    headers.Add(new KeyValuePair<string, string>(":path", path));
                                }
                            }
                            else
                            {
                                headers.AddRange(_handshakeHeaders);
                            }
                            stream = CreateStream(headers, frame.StreamId);
                        }

                        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 != null && stream.IsFlowControlEnabled)
                        {
                            stream.WriteWindowUpdate(InitialWindowSize);
                        }
                        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);

                        if (_ourEnd == ConnectionEnd.Server && _sessionSocket.SecureProtocol == SecureProtocol.None)
                        {
                            //The HTTP/1.1 request that is sent prior to upgrade is associated with
                            //stream 1 and is assigned the highest possible priority.  Stream 1 is
                            //implicitly half closed from the client toward the server, since the
                            //request is completed as an HTTP/1.1 request.  After commencing the
                            //HTTP/2.0 connection, stream 1 is used for the response.
                            stream = CreateStream(Priority.Pri0);
                            stream.EndStreamReceived = true;
                            stream.Headers.Add(new KeyValuePair<string, string>(":method", _handshakeHeaders[":method"]));
                            stream.Headers.Add(new KeyValuePair<string, string>(":path", _handshakeHeaders[":path"]));
                            OnFrameReceived(this, new FrameReceivedEventArgs(stream, new HeadersFrame(stream.Id, false)));
                        }

                        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 occurred: " + ex.Message);
                Close(ResetStatusCode.CompressionError);
            }
            catch (ProtocolError pEx)
            {
                Http2Logger.LogError("Protocol error occurred: " + pEx.Message);
                Close(pEx.Code);
            }
        }
コード例 #56
0
ファイル: Http2Stream.cs プロジェクト: Nangal/http2-katana
 //Incoming
 internal Http2Stream(HeadersList headers, int id,
                    WriteQueue writeQueue, FlowControlManager flowCrtlManager, int priority = Constants.DefaultStreamPriority)
     : this(id, writeQueue, flowCrtlManager, priority)
 {
     Headers = headers;
 }
コード例 #57
0
        /// <summary>
        /// Modifies the table.
        /// </summary>
        /// <param name="headerName">Name of the header.</param>
        /// <param name="headerValue">The header value.</param>
        /// <param name="headerType">Type of the header.</param>
        /// <param name="useHeadersTable">The use headers table.</param>
        /// <param name="index">The index.</param>
        private void ModifyTable(string headerName, string headerValue, IndexationType headerType,
                                        HeadersList useHeadersTable, int index)
        {
            int headerLen = headerName.Length + headerValue.Length + sizeof(Int32);

            //spec 04: 3.2.3.  Header Table Management
            //   The header table can be modified by either adding a new entry to it
            //or by replacing an existing one.  Before doing such a modification,
            //it has to be ensured that the header table size will stay lower than
            //or equal to the SETTINGS_MAX_BUFFER_SIZE limit (see Section 5).  To
            //achieve this, repeatedly, the first entry of the header table is
            //removed, until enough space is available for the modification.

            //A consequence of removing one or more entries at the beginning of the
            //header table is that the remaining entries are renumbered.  The first
            //entry of the header table is always associated to the index 0.

            //When the modification of the header table is the replacement of an
            //existing entry, the replaced entry is the one indicated in the
            //literal representation before any entry is removed from the header
            //table.  If the entry to be replaced is removed from the header table
            //when performing the size adjustment, the replacement entry is
            //inserted at the beginning of the header table.

            //The addition of a new entry with a size greater than the
            //SETTINGS_MAX_BUFFER_SIZE limit causes all the entries from the header
            //table to be dropped and the new entry not to be added to the header
            //table.  The replacement of an existing entry with a new entry with a
            //size greater than the SETTINGS_MAX_BUFFER_SIZE has the same
            //consequences.

            switch (headerType)
            {
                case IndexationType.Incremental:
                    while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize && useHeadersTable.Count > 0)
                    {
                            useHeadersTable.RemoveAt(0);
                    }
                    useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue));
                    break;
                case IndexationType.Substitution:
                    if (index != -1)
                    {
                        var header = useHeadersTable[index];
                        int substHeaderLen = header.Key.Length + header.Value.Length + sizeof(Int32);
                        int deletedHeadersCounter = 0;

                        while (useHeadersTable.StoredHeadersSize + headerLen - substHeaderLen > MaxHeaderByteSize)
                        {
                            if (useHeadersTable.Count > 0)
                            {
                                useHeadersTable.RemoveAt(0);
                                deletedHeadersCounter++;
                            }
                        }

                        if (index >= deletedHeadersCounter)
                        {
                            useHeadersTable[index - deletedHeadersCounter] =
                                            new KeyValuePair<string, string>(headerName, headerValue);
                        }
                        else
                        {
                            useHeadersTable.Insert(0, new KeyValuePair<string, string>(headerName, headerValue));
                        }
                    }
                    //If header wasn't found then add it to the table
                    else
                    {
                        while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize && useHeadersTable.Count > 0)
                        {
                            useHeadersTable.RemoveAt(0);
                        }
                        useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue));
                    }
                    break;
                default:
                    return;
            }
        }
コード例 #58
0
        /// <summary>
        /// Overrides request processing logic.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="frame">The request header frame.</param>
        /// <returns></returns>
        protected override void ProcessRequest(Http2Stream stream, Frame frame)
        {
            /* 12 -> 8.1.3.1
             * All HTTP/2 requests MUST include exactly one valid value for the
             * ":method", ":scheme", and ":path" header fields, unless this is a
             * CONNECT request (Section 8.3).  An HTTP request that omits mandatory
             * header fields is malformed (Section 8.1.3.5). */

            if (stream.Headers.GetValue(CommonHeaders.Method) == null ||
                stream.Headers.GetValue(CommonHeaders.Path) == null ||
                stream.Headers.GetValue(CommonHeaders.Scheme) == null)
            {
                stream.WriteRst(ResetStatusCode.ProtocolError);
                stream.Close(ResetStatusCode.ProtocolError);
                return;
            }

            Task.Factory.StartNew(async() =>
            {
                try
                {
                    var context    = new Http2OwinMessageContext(stream);
                    var contextEnv = context.OwinContext.Environment;

                    PushFunc pushDelegate = null;
                    pushDelegate          = async pairs =>
                    {
                        var promisedStream = CreateStream();
                        //assume that we have already received endStream
                        promisedStream.HalfClosedLocal = true;
                        stream.WritePushPromise(pairs, promisedStream.Id);

                        var headers = new HeadersList(pairs);
                        promisedStream.Headers.AddRange(headers);

                        var http2MsgCtx  = new Http2OwinMessageContext(promisedStream);
                        var http2PushCtx = http2MsgCtx.OwinContext;

                        http2PushCtx.Set(CommonOwinKeys.ServerPushFunc, pushDelegate);

                        //pass add info from parent to child context. This info can store
                        //reference table for example or something els that should be passed from
                        //client request into child push requests.
                        if (contextEnv.ContainsKey(CommonOwinKeys.AdditionalInfo))
                        {
                            http2PushCtx.Set(CommonOwinKeys.AdditionalInfo, contextEnv[CommonOwinKeys.AdditionalInfo]);
                        }

                        await _next(http2PushCtx);

                        http2MsgCtx.FinishResponse();
                    };

                    context.OwinContext.Set(CommonOwinKeys.ServerPushFunc, pushDelegate);
                    context.OwinContext.Set(CommonOwinKeys.EnableServerPush, _isPushEnabled);

                    await _next(context.OwinContext);
                    context.FinishResponse();
                }
                catch (Exception ex)
                {
                    EndResponse(stream, ex);
                }
            });
        }