private void SaveDataFrame(Http2Stream stream, DataFrame dataFrame)
        {
            string originalPath = stream.Headers.GetValue(CommonHeaders.Path.ToLower());
            //If user sets the empty file in get command we return notFound webpage
            string fileName = string.IsNullOrEmpty(Path.GetFileName(originalPath)) ? Index : Path.GetFileName(originalPath);
            string path = Path.Combine(AssemblyPath, fileName);

            try
            {
               _fileHelper.SaveToFile(dataFrame.Data.Array, dataFrame.Data.Offset, dataFrame.Data.Count,
                                    path, stream.ReceivedDataAmount != 0);
            }
            catch (IOException)
            {
                Http2Logger.LogError("File is still downloading. Repeat request later");
               
                stream.Close(ResetStatusCode.InternalError);
                return;
            }

            stream.ReceivedDataAmount += dataFrame.Data.Count;

            if (dataFrame.IsEndStream)
            {
                if (stream.HalfClosedRemote)
                {
                    //send terminator
                    stream.WriteDataFrame(new ArraySegment<byte>(new byte[0]), true);
                    Http2Logger.LogConsole("Terminator was sent");
                }
                _fileHelper.RemoveStream(path);
                Http2Logger.LogConsole("Bytes received: " + stream.ReceivedDataAmount);
            }
        }
예제 #2
0
        private void HandleRstFrame(RstStreamFrame resetFrame, out Http2Stream stream)
        {
            Http2Logger.LogDebug("RST_STREAM frame: stream id={0}, status code={1}",
                                 resetFrame.StreamId, resetFrame.StatusCode);

            /* 12 -> 6.4
             * RST_STREAM frames MUST be associated with a stream.  If a RST_STREAM
             * frame is received with a stream identifier of 0x0, the recipient MUST
             * treat this as a connection error of type PROTOCOL_ERROR. */
            if (resetFrame.StreamId == 0)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst frame with stream id=0");
            }

            stream = GetStream(resetFrame.StreamId);

            if (stream.Closed)
            {
                /* 12 -> 5.4.2
                 * An endpoint MUST NOT send a RST_STREAM in response to an RST_STREAM
                 * frame, to avoid looping. */
                if (!stream.WasRstSent)
                {
                    throw new Http2StreamNotFoundException(resetFrame.StreamId);
                }
                return;
            }

            if (!(stream.ReservedRemote || stream.Opened || stream.HalfClosedLocal))
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst for non opened or reserved stream");
            }

            stream.Close(ResetStatusCode.None);
        }
예제 #3
0
 private void ValidateHeaders(Http2Stream stream)
 {
     /* 12 -> 8.1.3
      * Header field names MUST be converted to lowercase prior to their
      * encoding in HTTP/2.0. A request or response containing uppercase
      * header field names MUST be treated as malformed. */
     foreach (var header in stream.Headers)
     {
         string key = header.Key;
         if (!_matcher.IsMatch(key) || key == ":")
         {
             stream.WriteRst(ResetStatusCode.RefusedStream);
             stream.Close(ResetStatusCode.RefusedStream);
             break;
         }
     }
 }
 private void ValidateHeaders(Http2Stream stream)
 {
     /* 12 -> 8.1.3
     Header field names MUST be converted to lowercase prior to their 
     encoding in HTTP/2.0. A request or response containing uppercase 
     header field names MUST be treated as malformed. */
     foreach (var header in stream.Headers)
     {
         string key = header.Key;
         if (!_matcher.IsMatch(key) || key == ":")
         {                    
             stream.WriteRst(ResetStatusCode.RefusedStream);
             stream.Close(ResetStatusCode.RefusedStream);
             break;
         }
     }
 }
        protected override void ProcessRequest(Http2Stream stream, Frame frame)
        {
            //spec 09 -> 8.1.3.2.  Response Header Fields
            //A single ":status" header field is defined that carries the HTTP
            //status code field (see [HTTP-p2], Section 6).  This header field MUST
            //be included in all responses, otherwise the response is malformed
            if (stream.Headers.GetValue(CommonHeaders.Status) == null)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError,
                                        "no status header in response. StreamId = " + stream.Id);
            }

            int code;
            if (!int.TryParse(stream.Headers.GetValue(CommonHeaders.Status), out code))
            {
                stream.WriteRst(ResetStatusCode.ProtocolError);  //Got something strange in the status field
                stream.Close(ResetStatusCode.ProtocolError);
            }

            //got some king of error
            if (code != StatusCode.Code200Ok)
            {
                //Close server's stream
                stream.Close(ResetStatusCode.Cancel); //will dispose client's stream and close server's one.
            }
            //Do nothing. Client may not process requests for now
        }
        private void HandleRstFrame(RstStreamFrame resetFrame, out Http2Stream stream)
        {
            Http2Logger.LogDebug("RST_STREAM frame: stream id={0}, status code={1}",
               resetFrame.StreamId, resetFrame.StatusCode);

            /* 12 -> 6.4
            RST_STREAM frames MUST be associated with a stream.  If a RST_STREAM
            frame is received with a stream identifier of 0x0, the recipient MUST
            treat this as a connection error of type PROTOCOL_ERROR. */
            if (resetFrame.StreamId == 0)
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst frame with stream id=0");

            stream = GetStream(resetFrame.StreamId);
            
            if (stream.Closed)
            {
                /* 12 -> 5.4.2
                An endpoint MUST NOT send a RST_STREAM in response to an RST_STREAM
                frame, to avoid looping. */
                if (!stream.WasRstSent)
                {
                    throw new Http2StreamNotFoundException(resetFrame.StreamId);
                }
                return;
            }

            if (!(stream.ReservedRemote || stream.Opened || stream.HalfClosedLocal))
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst for non opened or reserved stream");

            stream.Close(ResetStatusCode.None);
        }
        /// <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);
                }
            });
            
        }