Ejemplo n.º 1
0
        internal static HttpVersion ValueOf(AsciiString text)
        {
            if (text is null)
            {
                ThrowHelper.ThrowArgumentException_NullText();
            }

            // ReSharper disable once PossibleNullReferenceException
            HttpVersion version = ValueOfInline(text.Array);

            if (version is object)
            {
                return(version);
            }

            // Fall back to slow path
            text = text.Trim();

            if (0u >= (uint)text.Count)
            {
                ThrowHelper.ThrowArgumentException_EmptyText();
            }

            // Try to match without convert to uppercase first as this is what 99% of all clients
            // will send anyway. Also there is a change to the RFC to make it clear that it is
            // expected to be case-sensitive
            //
            // See:
            // * http://trac.tools.ietf.org/wg/httpbis/trac/ticket/1
            // * http://trac.tools.ietf.org/wg/httpbis/trac/wiki
            //
            return(Version0(text) ?? new HttpVersion(text.ToString(), true));
        }
Ejemplo n.º 2
0
        private static int GetChunkSize(AsciiString hex)
        {
            hex = hex.Trim();
            for (int i = hex.Offset; i < hex.Count; i++)
            {
                byte c = hex.Array[i];
                if (IsWhiteSpaceOrSemicolonOrISOControl(c))
                {
                    hex = (AsciiString)hex.SubSequence(0, i);
                    break;
                }
            }

            return(hex.ParseInt(16));
        }
Ejemplo n.º 3
0
        static int GetChunkSize(AsciiString hex)
        {
            hex = hex.Trim();
            for (int i = hex.Offset; i < hex.Count; i++)
            {
                byte c = hex.Array[i];
                if (c == ';' || IsWhiteSpace(c) || CharUtil.IsISOControl(c))
                {
                    hex = (AsciiString)hex.SubSequence(0, i);
                    break;
                }
            }

            return(hex.ParseInt(16));
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Filter the <see cref="HttpHeaderNames.Te"/> header according to the
 /// <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.2">special rules in the HTTP/2 RFC</a>.
 /// </summary>
 /// <param name="entry">An entry whose name is <see cref="HttpHeaderNames.Te"/>.</param>
 /// <param name="output">the resulting HTTP/2 headers.</param>
 private static void ToHttp2HeadersFilterTE(HeaderEntry <AsciiString, ICharSequence> entry, IHttp2Headers output)
 {
     if (AsciiString.IndexOf(entry.Value, ',', 0) == -1)
     {
         if (AsciiString.ContentEqualsIgnoreCase(AsciiString.Trim(entry.Value), HttpHeaderValues.Trailers))
         {
             _ = output.Add(HttpHeaderNames.Te, HttpHeaderValues.Trailers);
         }
     }
     else
     {
         var teValues = StringUtil.UnescapeCsvFields(entry.Value);
         foreach (var teValue in teValues)
         {
             if (AsciiString.ContentEqualsIgnoreCase(AsciiString.Trim(teValue), HttpHeaderValues.Trailers))
             {
                 _ = output.Add(HttpHeaderNames.Te, HttpHeaderValues.Trailers);
                 break;
             }
         }
     }
 }
Ejemplo n.º 5
0
        private static CharSequenceMap <AsciiString> ToLowercaseMap(IEnumerable <ICharSequence> values, int arraySizeHint)
        {
            var valueConverter = UnsupportedValueConverter <AsciiString> .Instance;
            var result         = new CharSequenceMap <AsciiString>(true, valueConverter, arraySizeHint);

            foreach (var item in values)
            {
                AsciiString lowerCased = AsciiString.Of(item).ToLowerCase();
                try
                {
                    int index = lowerCased.ForEachByte(ByteProcessor.FindComma);
                    if (index != -1)
                    {
                        int start = 0;
                        do
                        {
                            _     = result.Add(lowerCased.SubSequence(start, index, false).Trim(), AsciiString.Empty);
                            start = index + 1;
                        } while (start < lowerCased.Count &&
                                 (index = lowerCased.ForEachByte(start, lowerCased.Count - start, ByteProcessor.FindComma)) != -1);
                        _ = result.Add(lowerCased.SubSequence(start, lowerCased.Count, false).Trim(), AsciiString.Empty);
                    }
                    else
                    {
                        _ = result.Add(lowerCased.Trim(), AsciiString.Empty);
                    }
                }
                catch (Exception)
                {
                    // This is not expect to happen because FIND_COMMA never throws but must be caught
                    // because of the ByteProcessor interface.
                    ThrowHelper.ThrowInvalidOperationException();
                }
            }

            return(result);
        }
Ejemplo n.º 6
0
        protected override void Decode(IChannelHandlerContext context, IHttpObject message, List <object> output)
        {
            try
            {
                if (message is IHttpResponse response && response.Status.Code == StatusCodes.Status100Continue)
                {
                    if (!(response is ILastHttpContent))
                    {
                        _continueResponse = true;
                    }
                    // 100-continue response must be passed through.
                    output.Add(ReferenceCountUtil.Retain(message));
                    return;
                }

                if (_continueResponse)
                {
                    if (message is ILastHttpContent)
                    {
                        _continueResponse = false;
                    }
                    // 100-continue response must be passed through.
                    output.Add(ReferenceCountUtil.Retain(message));
                    return;
                }

                var httpContent = message as IHttpContent;
                if (message is IHttpMessage httpMessage)
                {
                    Cleanup();
                    HttpHeaders headers = httpMessage.Headers;

                    // Determine the content encoding.
                    if (headers.TryGet(HttpHeaderNames.ContentEncoding, out ICharSequence contentEncoding))
                    {
                        contentEncoding = AsciiString.Trim(contentEncoding);
                    }
                    else
                    {
                        if (headers.TryGet(HttpHeaderNames.TransferEncoding, out var transferEncoding))
                        {
                            int idx = transferEncoding.IndexOf(HttpConstants.CommaChar);
                            if (SharedConstants.TooBigOrNegative >= (uint)idx) // != -1
                            {
                                contentEncoding = AsciiString.Trim(transferEncoding.SubSequence(0, idx));
                            }
                            else
                            {
                                contentEncoding = AsciiString.Trim(transferEncoding);
                            }
                        }
                        else
                        {
                            contentEncoding = Identity;
                        }
                        //contentEncoding = Identity;
                    }
                    _decoder = NewContentDecoder(contentEncoding);

                    if (_decoder is null)
                    {
                        if (httpContent is object)
                        {
                            _ = httpContent.Retain();
                        }
                        output.Add(httpMessage);
                        return;
                    }

                    // Remove content-length header:
                    // the correct value can be set only after all chunks are processed/decoded.
                    // If buffering is not an issue, add HttpObjectAggregator down the chain, it will set the header.
                    // Otherwise, rely on LastHttpContent message.
                    if (headers.Contains(HttpHeaderNames.ContentLength))
                    {
                        _ = headers.Remove(HttpHeaderNames.ContentLength);
                        _ = headers.Set(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked);
                    }
                    // Either it is already chunked or EOF terminated.
                    // See https://github.com/netty/netty/issues/5892

                    // set new content encoding,
                    ICharSequence targetContentEncoding = GetTargetContentEncoding(contentEncoding);
                    if (HttpHeaderValues.Identity.ContentEquals(targetContentEncoding))
                    {
                        // Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
                        // as per: http://tools.ietf.org/html/rfc2616#section-14.11
                        _ = headers.Remove(HttpHeaderNames.ContentEncoding);
                    }
                    else
                    {
                        _ = headers.Set(HttpHeaderNames.ContentEncoding, targetContentEncoding);
                    }

                    if (httpContent is object)
                    {
                        // If message is a full request or response object (headers + data), don't copy data part into out.
                        // Output headers only; data part will be decoded below.
                        // Note: "copy" object must not be an instance of LastHttpContent class,
                        // as this would (erroneously) indicate the end of the HttpMessage to other handlers.
                        IHttpMessage copy = null;
                        switch (httpMessage)
                        {
                        case IHttpRequest req:
                            // HttpRequest or FullHttpRequest
                            copy = new DefaultHttpRequest(req.ProtocolVersion, req.Method, req.Uri);
                            break;

                        case IHttpResponse res:
                            // HttpResponse or FullHttpResponse
                            copy = new DefaultHttpResponse(res.ProtocolVersion, res.Status);
                            break;

                        default:
                            ThrowHelper.ThrowCodecException_InvalidHttpMsg(httpMessage);
                            break;
                        }
                        _           = copy.Headers.Set(httpMessage.Headers);
                        copy.Result = httpMessage.Result;
                        output.Add(copy);
                    }
                    else
                    {
                        output.Add(httpMessage);
                    }
                }

                if (httpContent is object)
                {
                    if (_decoder is null)
                    {
                        output.Add(httpContent.Retain());
                    }
                    else
                    {
                        DecodeContent(httpContent, output);
                    }
                }
            }
            finally
            {
                _needRead = 0u >= (uint)output.Count;
            }
        }
        public override void Decode(IChannelHandlerContext context, IHttpObject message, List <object> output)
        {
            if (message is IHttpResponse response && response.Status.Code == 100)
            {
                if (!(response is ILastHttpContent))
                {
                    this.continueResponse = true;
                }
                // 100-continue response must be passed through.
                output.Add(ReferenceCountUtil.Retain(message));
                return;
            }

            if (this.continueResponse)
            {
                if (message is ILastHttpContent)
                {
                    this.continueResponse = false;
                }
                // 100-continue response must be passed through.
                output.Add(ReferenceCountUtil.Retain(message));
                return;
            }

            if (message is IHttpMessage httpMessage)
            {
                this.Cleanup();
                HttpHeaders headers = httpMessage.Headers;

                // Determine the content encoding.
                if (headers.TryGet(HttpHeaderNames.ContentEncoding, out ICharSequence contentEncoding))
                {
                    contentEncoding = AsciiString.Trim(contentEncoding);
                }
                else
                {
                    contentEncoding = Identity;
                }
                this.decoder = this.NewContentDecoder(contentEncoding);

                if (this.decoder == null)
                {
                    if (httpMessage is IHttpContent httpContent)
                    {
                        httpContent.Retain();
                    }
                    output.Add(httpMessage);
                    return;
                }

                // Remove content-length header:
                // the correct value can be set only after all chunks are processed/decoded.
                // If buffering is not an issue, add HttpObjectAggregator down the chain, it will set the header.
                // Otherwise, rely on LastHttpContent message.
                if (headers.Contains(HttpHeaderNames.ContentLength))
                {
                    headers.Remove(HttpHeaderNames.ContentLength);
                    headers.Set(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked);
                }
                // Either it is already chunked or EOF terminated.
                // See https://github.com/netty/netty/issues/5892

                // set new content encoding,
                ICharSequence targetContentEncoding = this.GetTargetContentEncoding(contentEncoding);
                if (HttpHeaderValues.Identity.ContentEquals(targetContentEncoding))
                {
                    // Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
                    // as per: http://tools.ietf.org/html/rfc2616#section-14.11
                    headers.Remove(HttpHeaderNames.ContentEncoding);
                }
                else
                {
                    headers.Set(HttpHeaderNames.ContentEncoding, targetContentEncoding);
                }

                if (httpMessage is IHttpContent)
                {
                    // If message is a full request or response object (headers + data), don't copy data part into out.
                    // Output headers only; data part will be decoded below.
                    // Note: "copy" object must not be an instance of LastHttpContent class,
                    // as this would (erroneously) indicate the end of the HttpMessage to other handlers.
                    IHttpMessage copy;
                    if (httpMessage is IHttpRequest req)
                    {
                        // HttpRequest or FullHttpRequest
                        copy = new DefaultHttpRequest(req.ProtocolVersion, req.Method, req.Uri);
                    }
                    else if (httpMessage is IHttpResponse res)
                    {
                        // HttpResponse or FullHttpResponse
                        copy = new DefaultHttpResponse(res.ProtocolVersion, res.Status);
                    }
                    else
                    {
                        throw new CodecException($"Object of class {StringUtil.SimpleClassName(httpMessage.GetType())} is not a HttpRequest or HttpResponse");
                    }
                    copy.Headers.Set(httpMessage.Headers);
                    copy.Result = httpMessage.Result;
                    output.Add(copy);
                }
                else
                {
                    output.Add(httpMessage);
                }
            }

            if (message is IHttpContent c)
            {
                if (this.decoder == null)
                {
                    output.Add(c.Retain());
                }
                else
                {
                    this.DecodeContent(c, output);
                }
            }
        }