Example #1
0
            private void WriteHeader(ref HeaderEncodingState state, string name, string value)
            {
                // TODO: ISSUE 31307: Use static table for known headers

                int bytesWritten;

                while (!HPackEncoder.EncodeHeader(name, value, _requestBuffer.AvailableSpan, out bytesWritten))
                {
                    GrowWriteBuffer();
                }

                _requestBuffer.Commit(bytesWritten);

                while (_requestBuffer.ActiveSpan.Slice(state.CurrentFrameOffset).Length > FrameHeader.Size + FrameHeader.MaxLength)
                {
                    // We've exceeded the frame size limit.

                    // Fill in the current frame header.
                    WriteCurrentFrameHeader(ref state, FrameHeader.MaxLength, false);

                    state.IsFirstFrame        = false;
                    state.CurrentFrameOffset += FrameHeader.Size + FrameHeader.MaxLength;

                    // Reserve space for new frame header
                    _requestBuffer.Commit(FrameHeader.Size);

                    Span <byte> currentFrameSpan = _requestBuffer.ActiveSpan.Slice(state.CurrentFrameOffset);

                    // Shift the remainder down to make room for the new frame header.
                    // We'll fill this in when the frame is complete.
                    currentFrameSpan.Slice(0, currentFrameSpan.Length - FrameHeader.Size).CopyTo(currentFrameSpan.Slice(FrameHeader.Size));
                }
            }
Example #2
0
            private void WriteCurrentFrameHeader(ref HeaderEncodingState state, int frameLength, bool isLastFrame)
            {
                Debug.Assert(frameLength > 0);

                FrameHeader frameHeader = new FrameHeader();

                frameHeader.Length   = frameLength;
                frameHeader.StreamId = _streamId;

                if (state.IsFirstFrame)
                {
                    frameHeader.Type  = FrameType.Headers;
                    frameHeader.Flags = (state.IsEmptyResponse ? FrameFlags.EndStream : FrameFlags.None);
                }
                else
                {
                    frameHeader.Type  = FrameType.Continuation;
                    frameHeader.Flags = FrameFlags.None;
                }

                if (isLastFrame)
                {
                    frameHeader.Flags |= FrameFlags.EndHeaders;
                }

                // Update the curent HEADERS or CONTINUATION frame with length, and write it to the buffer.
                frameHeader.WriteTo(_requestBuffer.ActiveSpan.Slice(state.CurrentFrameOffset));
            }
Example #3
0
            private void WriteHeaders(ref HeaderEncodingState state, HttpHeaders headers)
            {
                foreach (KeyValuePair <HeaderDescriptor, string[]> header in headers.GetHeaderDescriptorsAndValues())
                {
                    if (header.Key.KnownHeader == KnownHeaders.Host)
                    {
                        continue;
                    }

                    Debug.Assert(header.Value.Length > 0, "No values for header??");
                    for (int i = 0; i < header.Value.Length; i++)
                    {
                        WriteHeader(ref state, header.Key.Name, header.Value[i]);
                    }
                }
            }
Example #4
0
            private void WriteHeaders(HttpRequestMessage request)
            {
                // TODO: ISSUE 31305: Disallow sending Connection: and Transfer-Encoding: chunked

                HeaderEncodingState state = new HeaderEncodingState()
                {
                    IsFirstFrame = true, IsEmptyResponse = (request.Content == null), CurrentFrameOffset = 0
                };

                // Initialize the HEADERS frame header.
                // We will write it to the buffer later, when the frame is complete.
                FrameHeader currentFrameHeader = new FrameHeader(0, FrameType.Headers, (request.Content == null ? FrameFlags.EndStream : FrameFlags.None), _streamId);

                // Reserve space for the frame header.
                // We will fill it in later, when the frame is complete.
                _requestBuffer.EnsureAvailableSpace(FrameHeader.Size);
                _requestBuffer.Commit(FrameHeader.Size);

                HttpMethod normalizedMethod = HttpMethod.Normalize(request.Method);

                // TODO: ISSUE 31307: Use static table for pseudo-headers
                WriteHeader(ref state, ":method", normalizedMethod.Method);
                WriteHeader(ref state, ":scheme", "https");

                string authority;

                if (request.HasHeaders && request.Headers.Host != null)
                {
                    authority = request.Headers.Host;
                }
                else
                {
                    authority = request.RequestUri.IdnHost;
                    if (!request.RequestUri.IsDefaultPort)
                    {
                        // TODO: Avoid allocation here by caching this on the connection or pool
                        authority += ":" + request.RequestUri.Port;
                    }
                }

                WriteHeader(ref state, ":authority", authority);
                WriteHeader(ref state, ":path", request.RequestUri.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.UriEscaped));

                if (request.HasHeaders)
                {
                    WriteHeaders(ref state, request.Headers);
                }

                // Determine cookies to send.
                if (_connection._pool.Settings._useCookies)
                {
                    string cookiesFromContainer = _connection._pool.Settings._cookieContainer.GetCookieHeader(request.RequestUri);
                    if (cookiesFromContainer != string.Empty)
                    {
                        WriteHeader(ref state, HttpKnownHeaderNames.Cookie, cookiesFromContainer);
                    }
                }

                if (request.Content == null)
                {
                    // Write out Content-Length: 0 header to indicate no body,
                    // unless this is a method that never has a body.
                    if (normalizedMethod.MustHaveRequestBody)
                    {
                        // TODO: ISSUE 31307: Use static table for Content-Length
                        WriteHeader(ref state, "Content-Length", "0");
                    }
                }
                else
                {
                    WriteHeaders(ref state, request.Content.Headers);
                }

                // Update the last frame header and write it to the buffer.
                WriteCurrentFrameHeader(ref state, _requestBuffer.ActiveSpan.Slice(state.CurrentFrameOffset).Length - FrameHeader.Size, true);
            }