netwerk/protocol/http/nsHttpChunkedDecoder.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // HttpLog.h should generally be included first
     7 #include "HttpLog.h"
     8 #include <errno.h>
     9 #include "nsHttpChunkedDecoder.h"
    10 #include <algorithm>
    12 namespace mozilla {
    13 namespace net {
    15 //-----------------------------------------------------------------------------
    16 // nsHttpChunkedDecoder <public>
    17 //-----------------------------------------------------------------------------
    19 nsresult
    20 nsHttpChunkedDecoder::HandleChunkedContent(char *buf,
    21                                            uint32_t count,
    22                                            uint32_t *contentRead,
    23                                            uint32_t *contentRemaining)
    24 {
    25     LOG(("nsHttpChunkedDecoder::HandleChunkedContent [count=%u]\n", count));
    27     *contentRead = 0;
    29     // from RFC2617 section 3.6.1, the chunked transfer coding is defined as:
    30     //
    31     //   Chunked-Body    = *chunk
    32     //                     last-chunk
    33     //                     trailer
    34     //                     CRLF
    35     //   chunk           = chunk-size [ chunk-extension ] CRLF
    36     //                     chunk-data CRLF
    37     //   chunk-size      = 1*HEX
    38     //   last-chunk      = 1*("0") [ chunk-extension ] CRLF
    39     //
    40     //   chunk-extension = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
    41     //   chunk-ext-name  = token
    42     //   chunk-ext-val   = token | quoted-string
    43     //   chunk-data      = chunk-size(OCTET)
    44     //   trailer         = *(entity-header CRLF)
    45     //
    46     // the chunk-size field is a string of hex digits indicating the size of the
    47     // chunk.  the chunked encoding is ended by any chunk whose size is zero,
    48     // followed by the trailer, which is terminated by an empty line.
    50     while (count) {
    51         if (mChunkRemaining) {
    52             uint32_t amt = std::min(mChunkRemaining, count);
    54             count -= amt;
    55             mChunkRemaining -= amt;
    57             *contentRead += amt;
    58             buf += amt;
    59         }
    60         else if (mReachedEOF)
    61             break; // done
    62         else {
    63             uint32_t bytesConsumed = 0;
    65             nsresult rv = ParseChunkRemaining(buf, count, &bytesConsumed);
    66             if (NS_FAILED(rv)) return rv;
    68             count -= bytesConsumed;
    70             if (count) {
    71                 // shift buf by bytesConsumed
    72                 memmove(buf, buf + bytesConsumed, count);
    73             }
    74         }
    75     }
    77     *contentRemaining = count;
    78     return NS_OK;
    79 }
    81 //-----------------------------------------------------------------------------
    82 // nsHttpChunkedDecoder <private>
    83 //-----------------------------------------------------------------------------
    85 nsresult
    86 nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
    87                                           uint32_t count,
    88                                           uint32_t *bytesConsumed)
    89 {
    90     NS_PRECONDITION(mChunkRemaining == 0, "chunk remaining should be zero");
    91     NS_PRECONDITION(count, "unexpected");
    93     *bytesConsumed = 0;
    95     char *p = static_cast<char *>(memchr(buf, '\n', count));
    96     if (p) {
    97         *p = 0;
    98         if ((p > buf) && (*(p-1) == '\r')) // eliminate a preceding CR
    99             *(p-1) = 0;
   100         *bytesConsumed = p - buf + 1;
   102         // make buf point to the full line buffer to parse
   103         if (!mLineBuf.IsEmpty()) {
   104             mLineBuf.Append(buf);
   105             buf = (char *) mLineBuf.get();
   106         }
   108         if (mWaitEOF) {
   109             if (*buf) {
   110                 LOG(("got trailer: %s\n", buf));
   111                 // allocate a header array for the trailers on demand
   112                 if (!mTrailers) {
   113                     mTrailers = new nsHttpHeaderArray();
   114                 }
   115                 mTrailers->ParseHeaderLine(buf);
   116             }
   117             else {
   118                 mWaitEOF = false;
   119                 mReachedEOF = true;
   120                 LOG(("reached end of chunked-body\n"));
   121             }
   122         }
   123         else if (*buf) {
   124             char *endptr;
   125             unsigned long parsedval; // could be 64 bit, could be 32
   127             // ignore any chunk-extensions
   128             if ((p = PL_strchr(buf, ';')) != nullptr)
   129                 *p = 0;
   131             // mChunkRemaining is an uint32_t!
   132             parsedval = strtoul(buf, &endptr, 16);
   133             mChunkRemaining = (uint32_t) parsedval;
   135             if ((endptr == buf) ||
   136                 ((errno == ERANGE) && (parsedval == ULONG_MAX))  ||
   137                 (parsedval != mChunkRemaining) ) {
   138                 LOG(("failed parsing hex on string [%s]\n", buf));
   139                 return NS_ERROR_UNEXPECTED;
   140             }
   142             // we've discovered the last chunk
   143             if (mChunkRemaining == 0)
   144                 mWaitEOF = true;
   145         }
   147         // ensure that the line buffer is clear
   148         mLineBuf.Truncate();
   149     }
   150     else {
   151         // save the partial line; wait for more data
   152         *bytesConsumed = count;
   153         // ignore a trailing CR
   154         if (buf[count-1] == '\r')
   155             count--;
   156         mLineBuf.Append(buf, count);
   157     }
   159     return NS_OK;
   160 }
   162 } // namespace mozilla::net
   163 } // namespace mozilla

mercurial