コード例 #1
0
            static string GetOrAddCachedValue([NotNull] ref string?cache, HeaderDescriptor descriptor, ReadOnlySpan <byte> value)
            {
                string?lastValue = cache;

                if (lastValue is null || !ByteArrayHelpers.EqualsOrdinalAscii(lastValue, value))
                {
                    cache = lastValue = descriptor.GetHeaderValue(value);
                }
                return(lastValue);
            }
コード例 #2
0
            public void OnHeader(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                {
                    throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_header_name, Encoding.ASCII.GetString(name)));
                }

                string headerValue = descriptor.GetHeaderValue(value);

                _headers.TryAddWithoutValidation(descriptor, headerValue.Split(',').Select(x => x.Trim()));
            }
コード例 #3
0
        internal static string GetSingleHeaderString(string name, IEnumerable <string> values)
        {
            string separator = HttpHeaderParser.DefaultSeparator;

            if (HeaderDescriptor.TryGet(name, out var descriptor) &&
                (descriptor.Parser != null) && (descriptor.Parser.SupportsMultipleValues))
            {
                separator = descriptor.Parser.Separator;
            }

            return(string.Join(separator, values));
        }
コード例 #4
0
ファイル: Http2Stream.cs プロジェクト: wuran-github/corefx
            public void OnResponseHeader(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                // TODO: ISSUE 31309: Optimize HPACK static table decoding

                lock (SyncObject)
                {
                    if (_state != StreamState.ExpectingHeaders)
                    {
                        throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError);
                    }

                    if (name.SequenceEqual(s_statusHeaderName))
                    {
                        if (value.Length != 3)
                        {
                            throw new Exception("Invalid status code");
                        }

                        // Copied from HttpConnection
                        byte status1 = value[0], status2 = value[1], status3 = value[2];
                        if (!IsDigit(status1) || !IsDigit(status2) || !IsDigit(status3))
                        {
                            throw new HttpRequestException(SR.net_http_invalid_response);
                        }

                        _response.SetStatusCodeWithoutValidation((HttpStatusCode)(100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0')));
                    }
                    else
                    {
                        if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                        {
                            // Invalid header name
                            throw new HttpRequestException(SR.net_http_invalid_response);
                        }

                        string headerValue = descriptor.GetHeaderValue(value);

                        // Note we ignore the return value from TryAddWithoutValidation;
                        // if the header can't be added, we silently drop it.
                        if (descriptor.HeaderType == HttpHeaderType.Content)
                        {
                            _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else
                        {
                            _response.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                    }
                }
            }
コード例 #5
0
        public void RoundTripsUtf8(string input)
        {
            byte[] encoded = Encoding.UTF8.GetBytes(input);

            Assert.True(HeaderDescriptor.TryGet("custom-header", out HeaderDescriptor descriptor));
            Assert.Null(descriptor.KnownHeader);
            string roundtrip = descriptor.GetHeaderValue(encoded, Encoding.UTF8);

            Assert.Equal(input, roundtrip);

            Assert.True(HeaderDescriptor.TryGet("Cache-Control", out descriptor));
            Assert.NotNull(descriptor.KnownHeader);
            roundtrip = descriptor.GetHeaderValue(encoded, Encoding.UTF8);
            Assert.Equal(input, roundtrip);
        }
コード例 #6
0
        // adapted from header deserialization code in Http2Connection.cs
        private static HttpHeaders HPackDecode(Memory <byte> memory)
        {
            var header       = new HttpRequestHeaders();
            var hpackDecoder = new HPackDecoder(maxDynamicTableSize: 0, maxResponseHeadersLength: HttpHandlerDefaults.DefaultMaxResponseHeadersLength * 1024);

            hpackDecoder.Decode(memory.Span, true, ((_, name, value) => HeaderHandler(name, value)), null);

            return(header);

            void HeaderHandler(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                {
                    throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_header_name, Encoding.ASCII.GetString(name)));
                }

                string headerValue = descriptor.GetHeaderValue(value);

                header.TryAddWithoutValidation(descriptor, headerValue.Split(',').Select(x => x.Trim()));
            }
        }
コード例 #7
0
        public DiagnosticsHandler(HttpMessageHandler innerHandler, DistributedContextPropagator propagator, bool autoRedirect = false)
        {
            Debug.Assert(IsGloballyEnabled());
            Debug.Assert(innerHandler is not null && propagator is not null);

            _innerHandler = innerHandler;
            _propagator   = propagator;

            // Prepare HeaderDescriptors for fields we need to clear when following redirects
            if (autoRedirect && _propagator.Fields is IReadOnlyCollection <string> fields && fields.Count > 0)
            {
                var fieldDescriptors = new List <HeaderDescriptor>(fields.Count);
                foreach (string field in fields)
                {
                    if (field is not null && HeaderDescriptor.TryGet(field, out HeaderDescriptor descriptor))
                    {
                        fieldDescriptors.Add(descriptor);
                    }
                }
                _propagatorFields = fieldDescriptors.ToArray();
            }
        }
コード例 #8
0
            public void OnResponseHeader(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                // TODO: ISSUE 31309: Optimize HPACK static table decoding

                lock (SyncObject)
                {
                    if (_state != StreamState.ExpectingHeaders && _state != StreamState.ExpectingTrailingHeaders)
                    {
                        throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError);
                    }

                    if (name.SequenceEqual(s_statusHeaderName))
                    {
                        if (_state == StreamState.ExpectingTrailingHeaders)
                        {
                            // Pseudo-headers not allowed in trailers.
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace("Pseudo-header in trailer headers.");
                            }
                            throw new HttpRequestException(SR.net_http_invalid_response_pseudo_header_in_trailer);
                        }

                        byte status1, status2, status3;
                        if (value.Length != 3 ||
                            !IsDigit(status1 = value[0]) ||
                            !IsDigit(status2 = value[1]) ||
                            !IsDigit(status3 = value[2]))
                        {
                            throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_status_code, Encoding.ASCII.GetString(value)));
                        }

                        _response.SetStatusCodeWithoutValidation((HttpStatusCode)(100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0')));
                    }
                    else
                    {
                        if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                        {
                            // Invalid header name
                            throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_header_name, Encoding.ASCII.GetString(name)));
                        }

                        string headerValue = descriptor.GetHeaderValue(value);

                        // Note we ignore the return value from TryAddWithoutValidation;
                        // if the header can't be added, we silently drop it.
                        if (_state == StreamState.ExpectingTrailingHeaders)
                        {
                            _response.TrailingHeaders.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else if (descriptor.HeaderType == HttpHeaderType.Content)
                        {
                            _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else
                        {
                            _response.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                    }
                }
            }
コード例 #9
0
 /// <summary>Uses <see cref="HeaderDescriptor.GetHeaderValue"/>, but first special-cases several known headers for which we can use caching.</summary>
 public string GetResponseHeaderValueWithCaching(HeaderDescriptor descriptor, ReadOnlySpan <byte> value)
 {
     return
         (ReferenceEquals(descriptor.KnownHeader, KnownHeaders.Date) ? GetOrAddCachedValue(ref _lastDateHeaderValue, descriptor, value) :
          ReferenceEquals(descriptor.KnownHeader, KnownHeaders.Server) ? GetOrAddCachedValue(ref _lastServerHeaderValue, descriptor, value) :
          descriptor.GetHeaderValue(value));
コード例 #10
0
            public void OnResponseHeader(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                Debug.Assert(name != null && name.Length > 0);
                // TODO: ISSUE 31309: Optimize HPACK static table decoding

                lock (SyncObject)
                {
                    if (name[0] == (byte)':')
                    {
                        if (_state != StreamState.ExpectingHeaders && _state != StreamState.ExpectingStatus)
                        {
                            // Pseudo-headers are allowed only in header block
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace($"Pseudo-header in {_state} state.");
                            }
                            throw new Http2ProtocolException(SR.net_http_invalid_response_pseudo_header_in_trailer);
                        }

                        if (name.SequenceEqual(s_statusHeaderName))
                        {
                            if (_state != StreamState.ExpectingStatus)
                            {
                                if (NetEventSource.IsEnabled)
                                {
                                    _connection.Trace("Received duplicate status headers.");
                                }
                                throw new Http2ProtocolException(SR.Format(SR.net_http_invalid_response_status_code, "duplicate status"));
                            }

                            byte status1, status2, status3;
                            if (value.Length != 3 ||
                                !IsDigit(status1 = value[0]) ||
                                !IsDigit(status2 = value[1]) ||
                                !IsDigit(status3 = value[2]))
                            {
                                throw new Http2ProtocolException(SR.Format(SR.net_http_invalid_response_status_code, Encoding.ASCII.GetString(value)));
                            }

                            int statusValue = (100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0'));
                            _response = new HttpResponseMessage()
                            {
                                Version        = HttpVersion.Version20,
                                RequestMessage = _request,
                                Content        = new HttpConnectionResponseContent(),
                                StatusCode     = (HttpStatusCode)statusValue
                            };

                            TaskCompletionSource <bool> shouldSendRequestBodyWaiter = _shouldSendRequestBodyWaiter;
                            if (statusValue < 200)
                            {
                                if (_response.StatusCode == HttpStatusCode.Continue && shouldSendRequestBodyWaiter != null)
                                {
                                    if (NetEventSource.IsEnabled)
                                    {
                                        _connection.Trace("Received 100Continue status.");
                                    }
                                    shouldSendRequestBodyWaiter.TrySetResult(true);
                                    _shouldSendRequestBodyWaiter = null;
                                }
                                // We do not process headers from 1xx responses.
                                _state = StreamState.ExpectingIgnoredHeaders;
                            }
                            else
                            {
                                _state = StreamState.ExpectingHeaders;
                                // If we tried 100-Continue and got rejected signal that we should not send request body.
                                _shouldSendRequestBody = (int)Response.StatusCode < 300;
                                shouldSendRequestBodyWaiter?.TrySetResult(_shouldSendRequestBody);
                            }
                        }
                        else
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace("Invalid response pseudo-header '{System.Text.Encoding.ASCII.GetString(name)}'.");
                            }
                            throw new Http2ProtocolException(SR.net_http_invalid_response);
                        }
                    }
                    else
                    {
                        if (_state == StreamState.ExpectingIgnoredHeaders)
                        {
                            // for 1xx response we ignore all headers.
                            return;
                        }

                        if (_state != StreamState.ExpectingHeaders && _state != StreamState.ExpectingTrailingHeaders)
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace($"Received header before status.");
                            }
                            throw new Http2ProtocolException(SR.net_http_invalid_response);
                        }

                        if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                        {
                            // Invalid header name
                            throw new Http2ProtocolException(SR.Format(SR.net_http_invalid_response_header_name, Encoding.ASCII.GetString(name)));
                        }

                        string headerValue = descriptor.GetHeaderValue(value);

                        // Note we ignore the return value from TryAddWithoutValidation;
                        // if the header can't be added, we silently drop it.
                        if (_state == StreamState.ExpectingTrailingHeaders)
                        {
                            _response.TrailingHeaders.TryAddWithoutValidation(descriptor.HeaderType == HttpHeaderType.Request ? descriptor.AsCustomHeader() : descriptor, headerValue);
                        }
                        else if (descriptor.HeaderType == HttpHeaderType.Content)
                        {
                            _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else
                        {
                            _response.Headers.TryAddWithoutValidation(descriptor.HeaderType == HttpHeaderType.Request ? descriptor.AsCustomHeader() : descriptor, headerValue);
                        }
                    }
                }
            }
コード例 #11
0
        void HandleHasBytesAvailableEvent(object sender, CFStream.StreamEventArgs e)
        {
            var stream = (CFHTTPStream)sender;

            StreamBucket bucket;

            if (!streamBuckets.TryGetValue(stream.Handle, out bucket))
            {
                return;
            }

            if (bucket.Response.Task.IsCompleted)
            {
                bucket.ContentStream.ReadStreamData();
                return;
            }

            var header = stream.GetResponseHeader();

            // Is this possible?
            if (!header.IsHeaderComplete)
            {
                throw new NotImplementedException();
            }

            bucket.ContentStream = new CFContentStream(stream);

            var response_msg = new HttpResponseMessage(header.ResponseStatusCode);

            response_msg.RequestMessage = bucket.Request;
            response_msg.ReasonPhrase   = header.ResponseStatusLine;
            response_msg.Content        = bucket.ContentStream;

            var fields = header.GetAllHeaderFields();

            if (fields != null)
            {
                foreach (var entry in fields)
                {
                    if (entry.Key == null)
                    {
                        continue;
                    }

                    var         key   = entry.Key.ToString();
                    var         value = entry.Value == null ? string.Empty : entry.Value.ToString();
                    HttpHeaders item_headers;
                    if (HeaderDescriptor.TryGet(key, out var descriptor) && descriptor.HeaderType == HttpHeaderType.Content)
                    {
                        item_headers = response_msg.Content.Headers;
                    }
                    else
                    {
                        item_headers = response_msg.Headers;

                        if (cookies != null && (key == "Set-Cookie" || key == "Set-Cookie2"))
                        {
                            AddCookie(value, bucket.Request.RequestUri, key);
                        }
                    }

                    item_headers.TryAddWithoutValidation(key, value);
                }
            }

            // cancellation (CancellationTokenRegistration) can happen in parallel
            if (!bucket.Response.Task.IsCanceled)
            {
                bucket.Response.TrySetResult(response_msg);

                bucket.ContentStream.ReadStreamData();
            }
        }
コード例 #12
0
 internal static bool IsContentHeader(string name)
 {
     return(HeaderDescriptor.TryGet(name, out var descriptor) && descriptor.HeaderType == HttpHeaderType.Content);
 }
コード例 #13
0
ファイル: Http2Stream.cs プロジェクト: shandan1/CollectionRef
            public void OnResponseHeader(ReadOnlySpan <byte> name, ReadOnlySpan <byte> value)
            {
                Debug.Assert(name != null && name.Length > 0);
                // TODO: ISSUE 31309: Optimize HPACK static table decoding

                lock (SyncObject)
                {
                    if (_state != StreamState.ExpectingHeaders && _state != StreamState.ExpectingTrailingHeaders)
                    {
                        throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError);
                    }

                    if (name[0] == (byte)':')
                    {
                        if (_state == StreamState.ExpectingTrailingHeaders)
                        {
                            // Pseudo-headers not allowed in trailers.
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace("Pseudo-header in trailer headers.");
                            }
                            throw new HttpRequestException(SR.net_http_invalid_response_pseudo_header_in_trailer);
                        }

                        if (name.SequenceEqual(s_statusHeaderName))
                        {
                            if (_response != null)
                            {
                                if (NetEventSource.IsEnabled)
                                {
                                    _connection.Trace("Received duplicate status headers.");
                                }
                                throw new Http2ProtocolException(Http2ProtocolErrorCode.ProtocolError);
                            }

                            byte status1, status2, status3;
                            if (value.Length != 3 ||
                                !IsDigit(status1 = value[0]) ||
                                !IsDigit(status2 = value[1]) ||
                                !IsDigit(status3 = value[2]))
                            {
                                throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_status_code, Encoding.ASCII.GetString(value)));
                            }

                            int statusValue = (100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0'));
                            _response = new HttpResponseMessage()
                            {
                                Version        = HttpVersion.Version20,
                                RequestMessage = _request,
                                Content        = new HttpConnectionResponseContent(),
                                StatusCode     = (HttpStatusCode)statusValue
                            };
                        }
                        else
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace("Invalid response pseudo-header '{System.Text.Encoding.ASCII.GetString(name)}'.");
                            }
                            throw new HttpRequestException(SR.net_http_invalid_response);
                        }
                    }
                    else
                    {
                        if (_response == null)
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                _connection.Trace($"Received header before status pseudo-header.");
                            }
                            throw new HttpRequestException(SR.net_http_invalid_response);
                        }

                        if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
                        {
                            // Invalid header name
                            throw new HttpRequestException(SR.Format(SR.net_http_invalid_response_header_name, Encoding.ASCII.GetString(name)));
                        }

                        string headerValue = descriptor.GetHeaderValue(value);

                        // Note we ignore the return value from TryAddWithoutValidation;
                        // if the header can't be added, we silently drop it.
                        if (_state == StreamState.ExpectingTrailingHeaders)
                        {
                            _response.TrailingHeaders.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else if (descriptor.HeaderType == HttpHeaderType.Content)
                        {
                            _response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                        else
                        {
                            _response.Headers.TryAddWithoutValidation(descriptor, headerValue);
                        }
                    }
                }
            }
コード例 #14
0
ファイル: HttpConnectionBase.cs プロジェクト: z77ma/runtime
 /// <summary>Uses <see cref="HeaderDescriptor.GetHeaderValue"/>, but first special-cases several known headers for which we can use caching.</summary>
 public string GetResponseHeaderValueWithCaching(HeaderDescriptor descriptor, ReadOnlySpan <byte> value, Encoding?valueEncoding)
 {
     return
         (descriptor.Equals(KnownHeaders.Date) ? GetOrAddCachedValue(ref _lastDateHeaderValue, descriptor, value, valueEncoding) :
          descriptor.Equals(KnownHeaders.Server) ? GetOrAddCachedValue(ref _lastServerHeaderValue, descriptor, value, valueEncoding) :
          descriptor.GetHeaderValue(value, valueEncoding));