Пример #1
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Get the buffer
            var buffer = context.Buffer;

            if (buffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Check if it looks like an http request but only with a single byte
            var pBuffer = buffer.AsBytePointer();
            var length  = context.Buffer.Length;
            var first   = (char)*pBuffer;

            if (length == 1 &&
                (first == 'P' ||
                 first == 'G' ||
                 first == 'H' ||
                 first == 'D' ||
                 first == 'O' ||
                 first == 'T' ||
                 first == 'C'))
            {
                return(ProcessingState.InsufficientData);
            }

            // Check if we can handle it
            if (!CanHandle(buffer))
            {
                return(ProcessingState.Failure);
            }

            // Acquire a HTTP context and save it in the session
            HttpContext httpContext = HttpContextPool.Default.Acquire(channel);

            context.Session = httpContext;

            // Make sure we have HTTP timeout set
            if (channel.Timeout != httpContext.ScriptTimeout)
            {
                channel.Timeout = httpContext.ScriptTimeout;
            }

            // Check if we have a http request
            if (buffer.Length < 14) // "GET / HTTP/1.1".Length;
            {
                return(ProcessingState.InsufficientData);
            }

            // Parse http request
            var errorOccured     = false;
            var insufficientData = false;
            var bytesParsed      = httpContext.ParseRequest(context.Buffer.AsBytePointer(), length,
                                                            out errorOccured, out insufficientData);

            // If there was en error during the parse, fail it
            if (errorOccured)
            {
                return(ProcessingState.Failure);
            }

            // Parsing of http headers was not complete, need to read more bytes
            if (insufficientData)
            {
                return(ProcessingState.InsufficientData);
            }

            // Trace HTTP request
            var request = httpContext.Request;

            NetTrace.WriteLine(request.HttpVerb.ToString().ToUpper() + " " + request.Path, channel, NetTraceCategory.Http);

            // Attempt to read the body
            if (buffer.Length < bytesParsed + request.ContentLength)
            {
                return(ProcessingState.InsufficientData);
            }

            // We got enough data, map the read data to the request
            if (request.ContentLength > 0)
            {
                // Switch to the current buffer, release the old one
                context.Throttle(bytesParsed + request.ContentLength);
                context.SwitchBuffer(
                    buffer.Split(bytesParsed)
                    );

                // Parse the body to the request
                request.Body = context.Buffer.AsArray();
            }
            else
            {
                // Make a special case for draft websockets, as they send a body with a
                // GET request. Bastards!
                if (bytesParsed + 8 <= buffer.Length &&
                    request.ContainsHeader("Sec-WebSocket-Key1"))
                {
                    // Get the 8 bytes of websocket challenge
                    context.Throttle(bytesParsed + 8);
                    context.SwitchBuffer(
                        buffer.Split(bytesParsed)
                        );

                    // Parse the body to the request
                    request.Body = context.Buffer.AsArray();
                }
                else
                {
                    // Switch to the current buffer, release the old one
                    context.Throttle(bytesParsed);
                    context.SwitchBuffer(null);
                }
            }

            // Redirect to the various built-in handlers
            context.Redirect(
                Handle.WebSocketUpgrade,
                Handle.Http
                );

            return(ProcessingState.Success);
        }