/// <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)
        {
            //spec 09
            //8.1.3.1.  Request Header Fields

            //HTTP/2.0 defines a number of header fields starting with a colon ':'
            //character that carry information about the request target:

            //o  The ":method" header field includes the HTTP method ([HTTP-p2],
            //Section 4).

            //o  The ":scheme" header field includes the scheme portion of the
            //target URI ([RFC3986], Section 3.1).

            //o  The ":authority" header field includes the authority portion of
            //the target URI ([RFC3986], Section 3.2).

            //To ensure that the HTTP/1.1 request line can be reproduced
            //accurately, this header field MUST be omitted when translating
            //from an HTTP/1.1 request that has a request target in origin or
            //asterisk form (see [HTTP-p1], Section 5.3).  Clients that generate
            //HTTP/2.0 requests directly SHOULD instead omit the "Host" header
            //field.  An intermediary that converts a 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" header field.

            //o  The ":path" header field includes the path and query parts of the
            //target URI (the "path-absolute" production from [RFC3986] and
            //optionally a '?' character followed by the "query" production, see
            //[RFC3986], Section 3.3 and [RFC3986], Section 3.4).  This field
            //MUST NOT be empty; URIs that do not contain a path component MUST
            //include a value of '/', unless the request is an OPTIONS in
            //asterisk form, in which case the ":path" header field MUST include
            //'*'.

            //All HTTP/2.0 requests MUST include exactly one valid value for all of
            //these 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).

            //Header field names that contain a colon are only valid in the
            //HTTP/2.0 context.  These are not HTTP header fields.  Implementations
            //MUST NOT generate header fields that start with a colon, but they
            //MUST ignore any header field that starts with a colon.  In
            //particular, header fields with names starting with a colon MUST NOT
            //be exposed as HTTP header fields.

            if (stream.Headers.GetValue(CommonHeaders.Method) == null
                || stream.Headers.GetValue(CommonHeaders.Path) == null
                || stream.Headers.GetValue(CommonHeaders.Scheme) == null
                || stream.Headers.GetValue(CommonHeaders.Authority) == null)
            {
                stream.WriteRst(ResetStatusCode.ProtocolError);
                stream.Dispose(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.EndStreamReceived = 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);
                }
            });
        }
Ejemplo n.º 2
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);
                }
            });
            
        }