Esempio n. 1
0
        private void ValidateNonOriginHostHeader(string hostText)
        {
            if (_requestTargetForm == ProtoRequestTarget.AuthorityForm)
            {
                if (hostText != RawTarget)
                {
                    BadProtoRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
                }
            }
            else if (_requestTargetForm == ProtoRequestTarget.AbsoluteForm)
            {
                // If the target URI includes an authority component, then a
                // client MUST send a field - value for Host that is identical to that
                // authority component, excluding any userinfo subcomponent and its "@"
                // delimiter.

                // System.Uri doesn't not tell us if the port was in the original string or not.
                // When IsDefaultPort = true, we will allow Host: with or without the default port
                if (hostText != _absoluteRequestTarget.Authority)
                {
                    if (!_absoluteRequestTarget.IsDefaultPort ||
                        hostText != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture))
                    {
                        BadProtoRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
                    }
                }
            }

            if (!ProtoUtilities.IsHostHeaderValid(hostText))
            {
                BadProtoRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
            }
        }
Esempio n. 2
0
        internal void EnsureHostHeaderExists()
        {
            // https://tools.ietf.org/html/rfc7230#section-5.4
            // A server MUST respond with a 400 (Bad Request) status code to any
            // HTTP/1.1 request message that lacks a Host header field and to any
            // request message that contains more than one Host header field or a
            // Host header field with an invalid field-value.

            var hostCount = ProtoRequestHeaders.HostCount;
            var hostText  = ProtoRequestHeaders.HeaderHost.ToString();

            if (hostCount <= 0)
            {
                if (_httpVersion == Proto.ProtoVersion.Proto10)
                {
                    return;
                }
                BadProtoRequestException.Throw(RequestRejectionReason.MissingHostHeader);
            }
            else if (hostCount > 1)
            {
                BadProtoRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
            }
            else if (_requestTargetForm != ProtoRequestTarget.OriginForm)
            {
                // Tail call
                ValidateNonOriginHostHeader(hostText);
            }
            else if (!ProtoUtilities.IsHostHeaderValid(hostText))
            {
                BadProtoRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
            }
        }
        private BadProtoRequestException(string message, int statusCode, RequestRejectionReason reason, ProtoMethod?requiredMethod)
            : base(message)
        {
            StatusCode = statusCode;
            Reason     = reason;

            if (requiredMethod.HasValue)
            {
                AllowedHeader = ProtoUtilities.MethodToString(requiredMethod.Value);
            }
        }
Esempio n. 4
0
        private bool TryValidateAuthorityAndHost(out string hostText)
        {
            // :authority (optional)
            // Prefer this over Host

            var authority = RequestHeaders[HeaderNames.Authority];
            var host      = ProtoRequestHeaders.HeaderHost;

            if (!StringValues.IsNullOrEmpty(authority))
            {
                // https://tools.ietf.org/html/rfc7540#section-8.1.2.3
                // Clients that generate HTTP/2 requests directly SHOULD use the ":authority"
                // pseudo - header field instead of the Host header field.
                // An intermediary that converts an HTTP/2 request to HTTP/1.1 MUST
                // create a Host header field if one is not present in a request by
                // copying the value of the ":authority" pseudo - header field.

                // We take this one step further, we don't want mismatched :authority
                // and Host headers, replace Host if :authority is defined. The application
                // will operate on the Host header.
                ProtoRequestHeaders.HeaderHost = authority;
                host = authority;
            }

            // https://tools.ietf.org/html/rfc7230#section-5.4
            // A server MUST respond with a 400 (Bad Request) status code to any
            // HTTP/1.1 request message that lacks a Host header field and to any
            // request message that contains more than one Host header field or a
            // Host header field with an invalid field-value.
            hostText = host.ToString();
            if (host.Count > 1 || !ProtoUtilities.IsHostHeaderValid(hostText))
            {
                // RST replaces 400
                ResetAndAbort(new ConnectionAbortedException(CoreStrings.FormatBadRequest_InvalidHostHeader_Detail(hostText)), Proto2ErrorCode.PROTOCOL_ERROR);
                return(false);
            }

            return(true);
        }
Esempio n. 5
0
        private bool TryValidateMethod()
        {
            // :method
            _methodText = RequestHeaders[HeaderNames.Method].ToString();
            Method      = ProtoUtilities.GetKnownMethod(_methodText);

            if (Method == ProtoMethod.None)
            {
                ResetAndAbort(new ConnectionAbortedException(CoreStrings.FormatProto2ErrorMethodInvalid(_methodText)), Proto2ErrorCode.PROTOCOL_ERROR);
                return(false);
            }

            if (Method == ProtoMethod.Custom)
            {
                if (ProtoCharacters.IndexOfInvalidTokenChar(_methodText) >= 0)
                {
                    ResetAndAbort(new ConnectionAbortedException(CoreStrings.FormatProto2ErrorMethodInvalid(_methodText)), Proto2ErrorCode.PROTOCOL_ERROR);
                    return(false);
                }
            }

            return(true);
        }