1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications.
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Darin Fisher <darin@netscape.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsHttpChunkedDecoder.h"
40 : #include "nsHttp.h"
41 :
42 : //-----------------------------------------------------------------------------
43 : // nsHttpChunkedDecoder <public>
44 : //-----------------------------------------------------------------------------
45 :
46 : nsresult
47 8 : nsHttpChunkedDecoder::HandleChunkedContent(char *buf,
48 : PRUint32 count,
49 : PRUint32 *contentRead,
50 : PRUint32 *contentRemaining)
51 : {
52 8 : LOG(("nsHttpChunkedDecoder::HandleChunkedContent [count=%u]\n", count));
53 :
54 8 : *contentRead = 0;
55 :
56 : // from RFC2617 section 3.6.1, the chunked transfer coding is defined as:
57 : //
58 : // Chunked-Body = *chunk
59 : // last-chunk
60 : // trailer
61 : // CRLF
62 : // chunk = chunk-size [ chunk-extension ] CRLF
63 : // chunk-data CRLF
64 : // chunk-size = 1*HEX
65 : // last-chunk = 1*("0") [ chunk-extension ] CRLF
66 : //
67 : // chunk-extension = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
68 : // chunk-ext-name = token
69 : // chunk-ext-val = token | quoted-string
70 : // chunk-data = chunk-size(OCTET)
71 : // trailer = *(entity-header CRLF)
72 : //
73 : // the chunk-size field is a string of hex digits indicating the size of the
74 : // chunk. the chunked encoding is ended by any chunk whose size is zero,
75 : // followed by the trailer, which is terminated by an empty line.
76 :
77 36 : while (count) {
78 20 : if (mChunkRemaining) {
79 4 : PRUint32 amt = NS_MIN(mChunkRemaining, count);
80 :
81 4 : count -= amt;
82 4 : mChunkRemaining -= amt;
83 :
84 4 : *contentRead += amt;
85 4 : buf += amt;
86 : }
87 16 : else if (mReachedEOF)
88 0 : break; // done
89 : else {
90 16 : PRUint32 bytesConsumed = 0;
91 :
92 16 : nsresult rv = ParseChunkRemaining(buf, count, &bytesConsumed);
93 16 : if (NS_FAILED(rv)) return rv;
94 :
95 16 : count -= bytesConsumed;
96 :
97 16 : if (count) {
98 : // shift buf by bytesConsumed
99 12 : memmove(buf, buf + bytesConsumed, count);
100 : }
101 : }
102 : }
103 :
104 8 : *contentRemaining = count;
105 8 : return NS_OK;
106 : }
107 :
108 : //-----------------------------------------------------------------------------
109 : // nsHttpChunkedDecoder <private>
110 : //-----------------------------------------------------------------------------
111 :
112 : nsresult
113 16 : nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
114 : PRUint32 count,
115 : PRUint32 *bytesConsumed)
116 : {
117 16 : NS_PRECONDITION(mChunkRemaining == 0, "chunk remaining should be zero");
118 16 : NS_PRECONDITION(count, "unexpected");
119 :
120 16 : *bytesConsumed = 0;
121 :
122 16 : char *p = static_cast<char *>(memchr(buf, '\n', count));
123 16 : if (p) {
124 16 : *p = 0;
125 16 : if ((p > buf) && (*(p-1) == '\r')) // eliminate a preceding CR
126 16 : *(p-1) = 0;
127 16 : *bytesConsumed = p - buf + 1;
128 :
129 : // make buf point to the full line buffer to parse
130 16 : if (!mLineBuf.IsEmpty()) {
131 0 : mLineBuf.Append(buf);
132 0 : buf = (char *) mLineBuf.get();
133 : }
134 :
135 16 : if (mWaitEOF) {
136 4 : if (*buf) {
137 0 : LOG(("got trailer: %s\n", buf));
138 : // allocate a header array for the trailers on demand
139 0 : if (!mTrailers) {
140 0 : mTrailers = new nsHttpHeaderArray();
141 : }
142 0 : mTrailers->ParseHeaderLine(buf);
143 : }
144 : else {
145 4 : mWaitEOF = false;
146 4 : mReachedEOF = true;
147 4 : LOG(("reached end of chunked-body\n"));
148 : }
149 : }
150 12 : else if (*buf) {
151 : // ignore any chunk-extensions
152 8 : if ((p = PL_strchr(buf, ';')) != nsnull)
153 0 : *p = 0;
154 :
155 8 : if (!sscanf(buf, "%x", &mChunkRemaining)) {
156 0 : LOG(("sscanf failed parsing hex on string [%s]\n", buf));
157 0 : return NS_ERROR_UNEXPECTED;
158 : }
159 :
160 : // we've discovered the last chunk
161 8 : if (mChunkRemaining == 0)
162 4 : mWaitEOF = true;
163 : }
164 :
165 : // ensure that the line buffer is clear
166 16 : mLineBuf.Truncate();
167 : }
168 : else {
169 : // save the partial line; wait for more data
170 0 : *bytesConsumed = count;
171 : // ignore a trailing CR
172 0 : if (buf[count-1] == '\r')
173 0 : count--;
174 0 : mLineBuf.Append(buf, count);
175 : }
176 :
177 16 : return NS_OK;
178 : }
|