Esempio n. 1
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);
        }
Esempio n. 2
0
        /// <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)));
            }
        }
Esempio n. 3
0
        /// <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);
        }
        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 (_remoteHeaderTable.Contains(header))
                {
                    CompressIndexed(header);
                }
                else
                {
                    CompressHeader(header, new Indexation(IndexationType.Incremental));
                }
                _remoteRefSet.Add(header); //Update our copy
            }

            _serializerStream.Flush();
            var result = new byte[_serializerStream.Position];
            var streamBuffer = _serializerStream.GetBuffer();
            Buffer.BlockCopy(streamBuffer, 0, result, 0, (int)_serializerStream.Position);
            return result;
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        /// <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);
            }
        }
Esempio n. 7
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.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);
            }
        }
Esempio n. 8
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);
        }
        /// <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;
            }
        }
        public HeadersList Decompress(byte[] serializedHeaders)
        {
            try
            {
                var workingSet = new HeadersList(_localRefSet);
                var unindexedHeadersList = new HeadersList();
                _currentOffset = 0;

                while (_currentOffset != serializedHeaders.Length)
                {
                    var entry = ParseHeader(serializedHeaders);
                    var header = new KeyValuePair<string, string>(entry.Item1, entry.Item2);

                    if (entry.Item3 == IndexationType.Indexed)
                    {
                        if (workingSet.Contains(header))
                            workingSet.RemoveAll(h => h.Equals(header));
                        else
                            workingSet.Add(header);
                    }
                    else if (entry.Item3 == IndexationType.WithoutIndexation)
                    {
                        unindexedHeadersList.Add(header);
                    }
                    else
                    {
                        workingSet.Add(header);
                    }
                }

                _localRefSet = new HeadersList(workingSet);

                for (int i = _localRefSet.Count - 1; i >= 0; --i)
                {
                    var header = _localRefSet[i];
                    if (!_localHeaderTable.Contains(header))
                        _localRefSet.RemoveAll(h => h.Equals(header));
                }

                workingSet.AddRange(unindexedHeadersList);
                return workingSet;
            }
            catch (Exception e)
            {
                throw new CompressionError(e);
            }
        }
Esempio n. 11
0
        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 CompressionError(e.Message);
            }
        }
Esempio n. 12
0
        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)));
            }
        }
        //09 -> 8.1.3.4.  Compressing the Cookie Header Field
        private void ProcessCookie(HeadersList toProcess)
        {
            //The Cookie header field [COOKIE] can carry a significant amount of
            //redundant data.

            //The Cookie header field uses a semi-colon (";") to delimit cookie-
            //pairs (or "crumbs").  This header field doesn't follow the list
            //construction rules in HTTP (see [HTTP-p1], Section 3.2.2), which
            //prevents cookie-pairs from being separated into different name-value
            //pairs.  This can significantly reduce compression efficiency as
            //individual cookie-pairs are updated.

            //To allow for better compression efficiency, the Cookie header field
            //MAY be split into separate header fields, each with one or more
            //cookie-pairs.  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)));
            }
        }
        /// <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;
                switch (headerType)
                {
                    case IndexationType.Incremental:
                        if (useHeadersTable.Count > HeadersLimit - 1)
                        {
                            useHeadersTable.RemoveAt(0);
                        }

                        while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize)
                        {
                            useHeadersTable.RemoveAt(0);
                        }
                        useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue));
                        break;
                    case IndexationType.Substitution:
                        if (index != -1)
                        {
                            useHeadersTable[index] = new KeyValuePair<string, string>(headerName, headerValue);
                        }
                        else
                        {
                            if (useHeadersTable.Count > HeadersLimit - 1)
                            {
                                useHeadersTable.RemoveAt(0);
                            }

                            while (useHeadersTable.StoredHeadersSize + headerLen > MaxHeaderByteSize)
                            {
                                useHeadersTable.RemoveAt(0);
                            }
                            //If header wasn't found then add it to the table
                            useHeadersTable.Add(new KeyValuePair<string, string>(headerName, headerValue));
                        }
                        break;
                    default:
                        return;
                }
        }
Esempio n. 15
0
        /// <summary>
        /// Process indexed.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns>The indexation.</returns>
        private Tuple <string, string, IndexationType> ProcessIndexed(int index)
        {
            /* 07 -> 4.2
             * The index value of 0 is not used. It MUST be treated as a decoding
             * error if found in an indexed header field representation. */
            if (index == 0)
            {
                throw new Exception("indexed representation with zero value");
            }

            var  header      = default(KeyValuePair <string, string>);
            bool isInStatic  = index > _localHeadersTable.Count & index <= _localHeadersTable.Count + Constants.StaticTable.Count;
            bool isInHeaders = index <= _localHeadersTable.Count;

            if (isInStatic)
            {
                header = Constants.StaticTable[index - _localHeadersTable.Count - 1];
            }
            else if (isInHeaders)
            {
                header = _localHeadersTable[index - 1];
            }
            else
            {
                throw new IndexOutOfRangeException("no such index nor in static neither in headers tables");
            }

            /* 07 -> 3.2.1
             * An _indexed representation_ corresponding to an entry _present_ in
             * the reference set entails the following actions:
             *
             * o  The entry is removed from the reference set. */
            if (_localRefSet.Contains(header))
            {
                _localRefSet.Remove(header);
                return(null);
            }

            /* 07 -> 3.2.1
             * An _indexed representation_ corresponding to an entry _not present_
             * in the reference set entails the following actions:
             *
             * o  If referencing an element of the static table:
             *
             *  The header field corresponding to the referenced entry is
             *      emitted.
             *
             *  The referenced static entry is inserted at the beginning of the
             *      header table.
             *
             *  A reference to this new header table entry is added to the
             *      reference set, except if this new entry didn't fit in the
             *      header table.
             *
             * o  If referencing an element of the header table:
             *
             *  The header field corresponding to the referenced entry is
             *      emitted.
             *
             *  The referenced header table entry is added to the reference
             *      set.
             */
            if (isInStatic)
            {
                _localHeadersTable.Insert(0, header);
            }

            _localRefSet.Add(header);

            return(new Tuple <string, string, IndexationType>(header.Key, header.Value, IndexationType.Indexed));
        }
Esempio n. 16
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);
                }
            }
        }