1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Mozilla.
15
* The Initial Developer of the Original Code is Netscape
16
* Communications. Portions created by Netscape Communications are
17
* Copyright (C) 2001 by Netscape Communications. All
21
* Darin Fisher <darin@netscape.com> (original author)
24
#include "nsHttpChunkedDecoder.h"
27
//-----------------------------------------------------------------------------
28
// nsHttpChunkedDecoder <public>
29
//-----------------------------------------------------------------------------
32
nsHttpChunkedDecoder::HandleChunkedContent(char *buf,
34
PRUint32 *contentRead,
35
PRUint32 *contentRemaining)
37
LOG(("nsHttpChunkedDecoder::HandleChunkedContent [count=%u]\n", count));
41
// from RFC2617 section 3.6.1, the chunked transfer coding is defined as:
43
// Chunked-Body = *chunk
47
// chunk = chunk-size [ chunk-extension ] CRLF
50
// last-chunk = 1*("0") [ chunk-extension ] CRLF
52
// chunk-extension = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
53
// chunk-ext-name = token
54
// chunk-ext-val = token | quoted-string
55
// chunk-data = chunk-size(OCTET)
56
// trailer = *(entity-header CRLF)
58
// the chunk-size field is a string of hex digits indicating the size of the
59
// chunk. the chunked encoding is ended by any chunk whose size is zero,
60
// followed by the trailer, which is terminated by an empty line.
63
if (mChunkRemaining) {
64
PRUint32 amt = PR_MIN(mChunkRemaining, count);
67
mChunkRemaining -= amt;
75
PRUint32 bytesConsumed = 0;
77
nsresult rv = ParseChunkRemaining(buf, count, &bytesConsumed);
78
if (NS_FAILED(rv)) return rv;
80
count -= bytesConsumed;
83
// shift buf by bytesConsumed
84
memmove(buf, buf + bytesConsumed, count);
89
*contentRemaining = count;
93
//-----------------------------------------------------------------------------
94
// nsHttpChunkedDecoder <private>
95
//-----------------------------------------------------------------------------
98
nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
100
PRUint32 *bytesConsumed)
102
NS_PRECONDITION(mChunkRemaining == 0, "chunk remaining should be zero");
103
NS_PRECONDITION(count, "unexpected");
107
char *p = NS_STATIC_CAST(char *, memchr(buf, '\n', count));
110
if ((p > buf) && (*(p-1) == '\r')) // eliminate a preceding CR
112
*bytesConsumed = p - buf + 1;
114
// make buf point to the full line buffer to parse
115
if (!mLineBuf.IsEmpty()) {
116
mLineBuf.Append(buf);
117
buf = (char *) mLineBuf.get();
122
LOG(("got trailer: %s\n", buf));
123
// allocate a header array for the trailers on demand
125
mTrailers = new nsHttpHeaderArray();
127
return NS_ERROR_OUT_OF_MEMORY;
129
mTrailers->ParseHeaderLine(buf);
133
mReachedEOF = PR_TRUE;
134
LOG(("reached end of chunked-body\n"));
138
// ignore any chunk-extensions
139
if ((p = PL_strchr(buf, ';')) != nsnull)
142
if (!sscanf(buf, "%x", &mChunkRemaining)) {
143
LOG(("sscanf failed parsing hex on string [%s]\n", buf));
144
return NS_ERROR_UNEXPECTED;
147
// we've discovered the last chunk
148
if (mChunkRemaining == 0)
152
// ensure that the line buffer is clear
156
// save the partial line; wait for more data
157
*bytesConsumed = count;
158
// ignore a trailing CR
159
if (buf[count-1] == '\r')
161
mLineBuf.Append(buf, count);