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.)

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

mercurial