Main Page
Related Pages
Namespaces
Classes
Files
File List
File Members
opt
cpr
opt
curl
lib
http_chunks.c
Go to the documentation of this file.
1
/***************************************************************************
2
* _ _ ____ _
3
* Project ___| | | | _ \| |
4
* / __| | | | |_) | |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
7
*
8
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
9
*
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at https://curl.haxx.se/docs/copyright.html.
13
*
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
* copies of the Software, and permit persons to whom the Software is
16
* furnished to do so, under the terms of the COPYING file.
17
*
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
* KIND, either express or implied.
20
*
21
***************************************************************************/
22
23
#include "
curl_setup.h
"
24
25
#ifndef CURL_DISABLE_HTTP
26
27
#include "
urldata.h
"
/* it includes http_chunks.h */
28
#include "
sendf.h
"
/* for the client write stuff */
29
30
#include "
content_encoding.h
"
31
#include "
http.h
"
32
#include "
non-ascii.h
"
/* for Curl_convert_to_network prototype */
33
#include "
strtoofft.h
"
34
#include "
warnless.h
"
35
36
/* The last #include files should be: */
37
#include "
curl_memory.h
"
38
#include "
memdebug.h
"
39
40
/*
41
* Chunk format (simplified):
42
*
43
* <HEX SIZE>[ chunk extension ] CRLF
44
* <DATA> CRLF
45
*
46
* Highlights from RFC2616 section 3.6 say:
47
48
The chunked encoding modifies the body of a message in order to
49
transfer it as a series of chunks, each with its own size indicator,
50
followed by an OPTIONAL trailer containing entity-header fields. This
51
allows dynamically produced content to be transferred along with the
52
information necessary for the recipient to verify that it has
53
received the full message.
54
55
Chunked-Body = *chunk
56
last-chunk
57
trailer
58
CRLF
59
60
chunk = chunk-size [ chunk-extension ] CRLF
61
chunk-data CRLF
62
chunk-size = 1*HEX
63
last-chunk = 1*("0") [ chunk-extension ] CRLF
64
65
chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
66
chunk-ext-name = token
67
chunk-ext-val = token | quoted-string
68
chunk-data = chunk-size(OCTET)
69
trailer = *(entity-header CRLF)
70
71
The chunk-size field is a string of hex digits indicating the size of
72
the chunk. The chunked encoding is ended by any chunk whose size is
73
zero, followed by the trailer, which is terminated by an empty line.
74
75
*/
76
77
/* Check for an ASCII hex digit.
78
We avoid the use of isxdigit to accommodate non-ASCII hosts. */
79
static
bool
Curl_isxdigit
(
char
digit)
80
{
81
return
( (digit >= 0x30 && digit <= 0x39)
/* 0-9 */
82
|| (digit >= 0x41 && digit <= 0x46)
/* A-F */
83
|| (digit >= 0x61 && digit <= 0x66)
/* a-f */
) ?
TRUE
:
FALSE
;
84
}
85
86
void
Curl_httpchunk_init
(
struct
connectdata
*conn)
87
{
88
struct
Curl_chunker
*chunk = &conn->
chunk
;
89
chunk->
hexindex
= 0;
/* start at 0 */
90
chunk->
dataleft
= 0;
/* no data left yet! */
91
chunk->
state
=
CHUNK_HEX
;
/* we get hex first! */
92
}
93
94
/*
95
* chunk_read() returns a OK for normal operations, or a positive return code
96
* for errors. STOP means this sequence of chunks is complete. The 'wrote'
97
* argument is set to tell the caller how many bytes we actually passed to the
98
* client (for byte-counting and whatever).
99
*
100
* The states and the state-machine is further explained in the header file.
101
*
102
* This function always uses ASCII hex values to accommodate non-ASCII hosts.
103
* For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
104
*/
105
CHUNKcode
Curl_httpchunk_read
(
struct
connectdata
*conn,
106
char
*datap,
107
ssize_t
datalen,
108
ssize_t
*wrotep)
109
{
110
CURLcode
result
=
CURLE_OK
;
111
struct
Curl_easy
*
data
= conn->
data
;
112
struct
Curl_chunker
*ch = &conn->
chunk
;
113
struct
SingleRequest
*k = &data->
req
;
114
size_t
piece;
115
curl_off_t
length
= (
curl_off_t
)datalen;
116
size_t
*wrote = (
size_t
*)wrotep;
117
118
*wrote = 0;
/* nothing's written yet */
119
120
/* the original data is written to the client, but we go on with the
121
chunk read process, to properly calculate the content length*/
122
if
(data->
set
.
http_te_skip
&& !k->
ignorebody
) {
123
result =
Curl_client_write
(conn,
CLIENTWRITE_BODY
, datap, datalen);
124
if
(result)
125
return
CHUNKE_WRITE_ERROR
;
126
}
127
128
while
(length) {
129
switch
(ch->
state
) {
130
case
CHUNK_HEX
:
131
if
(
Curl_isxdigit
(*datap)) {
132
if
(ch->
hexindex
<
MAXNUM_SIZE
) {
133
ch->
hexbuffer
[ch->
hexindex
] = *datap;
134
datap++;
135
length--;
136
ch->
hexindex
++;
137
}
138
else
{
139
return
CHUNKE_TOO_LONG_HEX
;
/* longer hex than we support */
140
}
141
}
142
else
{
143
char
*endptr;
144
if
(0 == ch->
hexindex
)
145
/* This is illegal data, we received junk where we expected
146
a hexadecimal digit. */
147
return
CHUNKE_ILLEGAL_HEX
;
148
149
/* length and datap are unmodified */
150
ch->
hexbuffer
[ch->
hexindex
] = 0;
151
152
/* convert to host encoding before calling strtoul */
153
result =
Curl_convert_from_network
(conn->
data
, ch->
hexbuffer
,
154
ch->
hexindex
);
155
if
(result) {
156
/* Curl_convert_from_network calls failf if unsuccessful */
157
/* Treat it as a bad hex character */
158
return
CHUNKE_ILLEGAL_HEX
;
159
}
160
161
if
(
curlx_strtoofft
(ch->
hexbuffer
, &endptr, 16, &ch->
datasize
))
162
return
CHUNKE_ILLEGAL_HEX
;
163
ch->
state
=
CHUNK_LF
;
/* now wait for the CRLF */
164
}
165
break
;
166
167
case
CHUNK_LF
:
168
/* waiting for the LF after a chunk size */
169
if
(*datap == 0x0a) {
170
/* we're now expecting data to come, unless size was zero! */
171
if
(0 == ch->
datasize
) {
172
ch->
state
=
CHUNK_TRAILER
;
/* now check for trailers */
173
conn->
trlPos
= 0;
174
}
175
else
176
ch->
state
=
CHUNK_DATA
;
177
}
178
179
datap++;
180
length--;
181
break
;
182
183
case
CHUNK_DATA
:
184
/* We expect 'datasize' of data. We have 'length' right now, it can be
185
more or less than 'datasize'. Get the smallest piece.
186
*/
187
piece =
curlx_sotouz
((ch->
datasize
>= length)?length:ch->
datasize
);
188
189
/* Write the data portion available */
190
#ifdef HAVE_LIBZ
191
switch
(conn->
data
->
set
.
http_ce_skip
?
192
IDENTITY
: data->
req
.
auto_decoding
) {
193
case
IDENTITY
:
194
#endif
195
if
(!k->
ignorebody
) {
196
if
(!data->
set
.
http_te_skip
)
197
result =
Curl_client_write
(conn,
CLIENTWRITE_BODY
, datap,
198
piece);
199
else
200
result =
CURLE_OK
;
201
}
202
#ifdef HAVE_LIBZ
203
break
;
204
205
case
DEFLATE
:
206
/* update data->req.keep.str to point to the chunk data. */
207
data->
req
.
str
= datap;
208
result =
Curl_unencode_deflate_write
(conn, &data->
req
,
209
(
ssize_t
)piece);
210
break
;
211
212
case
GZIP
:
213
/* update data->req.keep.str to point to the chunk data. */
214
data->
req
.
str
= datap;
215
result =
Curl_unencode_gzip_write
(conn, &data->
req
,
216
(
ssize_t
)piece);
217
break
;
218
219
default
:
220
failf
(conn->
data
,
221
"Unrecognized content encoding type. "
222
"libcurl understands `identity', `deflate' and `gzip' "
223
"content encodings."
);
224
return
CHUNKE_BAD_ENCODING
;
225
}
226
#endif
227
228
if
(result)
229
return
CHUNKE_WRITE_ERROR
;
230
231
*wrote += piece;
232
233
ch->
datasize
-= piece;
/* decrease amount left to expect */
234
datap += piece;
/* move read pointer forward */
235
length -= piece;
/* decrease space left in this round */
236
237
if
(0 == ch->
datasize
)
238
/* end of data this round, we now expect a trailing CRLF */
239
ch->
state
=
CHUNK_POSTLF
;
240
break
;
241
242
case
CHUNK_POSTLF
:
243
if
(*datap == 0x0a) {
244
/* The last one before we go back to hex state and start all over. */
245
Curl_httpchunk_init
(conn);
/* sets state back to CHUNK_HEX */
246
}
247
else
if
(*datap != 0x0d)
248
return
CHUNKE_BAD_CHUNK
;
249
datap++;
250
length--;
251
break
;
252
253
case
CHUNK_TRAILER
:
254
if
((*datap == 0x0d) || (*datap == 0x0a)) {
255
/* this is the end of a trailer, but if the trailer was zero bytes
256
there was no trailer and we move on */
257
258
if
(conn->
trlPos
) {
259
/* we allocate trailer with 3 bytes extra room to fit this */
260
conn->
trailer
[conn->
trlPos
++] = 0x0d;
261
conn->
trailer
[conn->
trlPos
++] = 0x0a;
262
conn->
trailer
[conn->
trlPos
] = 0;
263
264
/* Convert to host encoding before calling Curl_client_write */
265
result =
Curl_convert_from_network
(conn->
data
, conn->
trailer
,
266
conn->
trlPos
);
267
if
(result)
268
/* Curl_convert_from_network calls failf if unsuccessful */
269
/* Treat it as a bad chunk */
270
return
CHUNKE_BAD_CHUNK
;
271
272
if
(!data->
set
.
http_te_skip
) {
273
result =
Curl_client_write
(conn,
CLIENTWRITE_HEADER
,
274
conn->
trailer
, conn->
trlPos
);
275
if
(result)
276
return
CHUNKE_WRITE_ERROR
;
277
}
278
conn->
trlPos
= 0;
279
ch->
state
=
CHUNK_TRAILER_CR
;
280
if
(*datap == 0x0a)
281
/* already on the LF */
282
break
;
283
}
284
else
{
285
/* no trailer, we're on the final CRLF pair */
286
ch->
state
=
CHUNK_TRAILER_POSTCR
;
287
break
;
/* don't advance the pointer */
288
}
289
}
290
else
{
291
/* conn->trailer is assumed to be freed in url.c on a
292
connection basis */
293
if
(conn->
trlPos
>= conn->
trlMax
) {
294
/* we always allocate three extra bytes, just because when the full
295
header has been received we append CRLF\0 */
296
char
*
ptr
;
297
if
(conn->
trlMax
) {
298
conn->
trlMax
*= 2;
299
ptr =
realloc
(conn->
trailer
, conn->
trlMax
+ 3);
300
}
301
else
{
302
conn->
trlMax
= 128;
303
ptr =
malloc
(conn->
trlMax
+ 3);
304
}
305
if
(!ptr)
306
return
CHUNKE_OUT_OF_MEMORY
;
307
conn->
trailer
=
ptr
;
308
}
309
conn->
trailer
[conn->
trlPos
++]=*datap;
310
}
311
datap++;
312
length--;
313
break
;
314
315
case
CHUNK_TRAILER_CR
:
316
if
(*datap == 0x0a) {
317
ch->
state
=
CHUNK_TRAILER_POSTCR
;
318
datap++;
319
length--;
320
}
321
else
322
return
CHUNKE_BAD_CHUNK
;
323
break
;
324
325
case
CHUNK_TRAILER_POSTCR
:
326
/* We enter this state when a CR should arrive so we expect to
327
have to first pass a CR before we wait for LF */
328
if
((*datap != 0x0d) && (*datap != 0x0a)) {
329
/* not a CR then it must be another header in the trailer */
330
ch->
state
=
CHUNK_TRAILER
;
331
break
;
332
}
333
if
(*datap == 0x0d) {
334
/* skip if CR */
335
datap++;
336
length--;
337
}
338
/* now wait for the final LF */
339
ch->
state
=
CHUNK_STOP
;
340
break
;
341
342
case
CHUNK_STOP
:
343
if
(*datap == 0x0a) {
344
length--;
345
346
/* Record the length of any data left in the end of the buffer
347
even if there's no more chunks to read */
348
ch->
dataleft
=
curlx_sotouz
(length);
349
350
return
CHUNKE_STOP
;
/* return stop */
351
}
352
else
353
return
CHUNKE_BAD_CHUNK
;
354
}
355
}
356
return
CHUNKE_OK
;
357
}
358
359
const
char
*
Curl_chunked_strerror
(
CHUNKcode
code)
360
{
361
switch
(code) {
362
default
:
363
return
"OK"
;
364
case
CHUNKE_TOO_LONG_HEX
:
365
return
"Too long hexadecimal number"
;
366
case
CHUNKE_ILLEGAL_HEX
:
367
return
"Illegal or missing hexadecimal sequence"
;
368
case
CHUNKE_BAD_CHUNK
:
369
return
"Malformed encoding found"
;
370
case
CHUNKE_WRITE_ERROR
:
371
return
"Write error"
;
372
case
CHUNKE_BAD_ENCODING
:
373
return
"Bad content-encoding found"
;
374
case
CHUNKE_OUT_OF_MEMORY
:
375
return
"Out of memory"
;
376
}
377
}
378
379
#endif
/* CURL_DISABLE_HTTP */
DEFLATE
#define DEFLATE
Definition:
urldata.h:566
CLIENTWRITE_BODY
#define CLIENTWRITE_BODY
Definition:
sendf.h:50
Curl_chunker::state
ChunkyState state
Definition:
http_chunks.h:85
connectdata::trlMax
int trlMax
Definition:
urldata.h:994
Curl_easy::set
struct UserDefined set
Definition:
urldata.h:1762
CHUNKE_OUT_OF_MEMORY
Definition:
http_chunks.h:76
Curl_httpchunk_init
void Curl_httpchunk_init(struct connectdata *conn)
Definition:
http_chunks.c:86
Curl_chunker
Definition:
http_chunks.h:82
GZIP
#define GZIP
Definition:
urldata.h:567
failf
#define failf
Definition:
sendf.h:48
CHUNKE_OK
Definition:
http_chunks.h:70
sendf.h
CHUNKE_ILLEGAL_HEX
Definition:
http_chunks.h:72
Curl_chunker::hexbuffer
char hexbuffer[MAXNUM_SIZE+1]
Definition:
http_chunks.h:83
ptr
UNITTEST_START char * ptr
Definition:
unit1330.c:38
CURLcode
CURLcode
Definition:
curl.h:454
CHUNK_DATA
Definition:
http_chunks.h:41
Curl_isxdigit
static bool Curl_isxdigit(char digit)
Definition:
http_chunks.c:79
connectdata::chunk
struct Curl_chunker chunk
Definition:
urldata.h:798
realloc
#define realloc(ptr, size)
Definition:
curl_memory.h:128
UserDefined::http_te_skip
bool http_te_skip
Definition:
urldata.h:1655
CHUNK_TRAILER_CR
Definition:
http_chunks.h:59
malloc
#define malloc(size)
Definition:
curl_memory.h:124
result
UNITTEST_START int result
Definition:
unit1304.c:49
CHUNK_STOP
Definition:
http_chunks.h:51
CHUNKE_STOP
Definition:
http_chunks.h:69
content_encoding.h
CHUNKE_BAD_ENCODING
Definition:
http_chunks.h:75
http.h
CHUNKE_TOO_LONG_HEX
Definition:
http_chunks.h:71
CHUNK_TRAILER
Definition:
http_chunks.h:55
Curl_httpchunk_read
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t datalen, ssize_t *wrotep)
Definition:
http_chunks.c:105
FALSE
#define FALSE
Definition:
curl_setup_once.h:347
Curl_easy::req
struct SingleRequest req
Definition:
urldata.h:1761
SingleRequest::ignorebody
bool ignorebody
Definition:
urldata.h:586
CHUNK_HEX
Definition:
http_chunks.h:34
CHUNKE_BAD_CHUNK
Definition:
http_chunks.h:73
curlx_strtoofft
CURLofft curlx_strtoofft(const char *str, char **endp, int base, curl_off_t *num)
Definition:
strtoofft.c:215
Curl_chunker::dataleft
size_t dataleft
Definition:
http_chunks.h:87
CHUNKE_WRITE_ERROR
Definition:
http_chunks.h:74
CHUNKcode
CHUNKcode
Definition:
http_chunks.h:68
Curl_convert_from_network
#define Curl_convert_from_network(a, b, c)
Definition:
non-ascii.h:57
strtoofft.h
curl_off_t
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition:
system.h:420
CLIENTWRITE_HEADER
#define CLIENTWRITE_HEADER
Definition:
sendf.h:51
curl_memory.h
Curl_unencode_gzip_write
CURLcode Curl_unencode_gzip_write(struct connectdata *conn, struct SingleRequest *k, ssize_t nread)
CURLE_OK
Definition:
curl.h:455
connectdata::trlPos
int trlPos
Definition:
urldata.h:995
Curl_client_write
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len)
Definition:
sendf.c:624
curl_setup.h
Curl_easy
Definition:
urldata.h:1732
non-ascii.h
ssize_t
#define ssize_t
Definition:
config-win32.h:382
SingleRequest::auto_decoding
int auto_decoding
Definition:
urldata.h:563
CHUNK_LF
Definition:
http_chunks.h:37
connectdata::trailer
char * trailer
Definition:
urldata.h:993
CHUNK_POSTLF
Definition:
http_chunks.h:46
length
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
Curl_chunked_strerror
const char * Curl_chunked_strerror(CHUNKcode code)
Definition:
http_chunks.c:359
SingleRequest::str
char * str
Definition:
urldata.h:550
warnless.h
CHUNK_TRAILER_POSTCR
Definition:
http_chunks.h:65
urldata.h
TRUE
#define TRUE
Definition:
multi-debugcallback.c:38
IDENTITY
#define IDENTITY
Definition:
urldata.h:565
MAXNUM_SIZE
#define MAXNUM_SIZE
Definition:
http_chunks.h:29
UserDefined::http_ce_skip
bool http_ce_skip
Definition:
urldata.h:1657
memdebug.h
SingleRequest
Definition:
urldata.h:518
curlx_sotouz
size_t curlx_sotouz(curl_off_t sonum)
Definition:
warnless.c:347
Curl_chunker::hexindex
int hexindex
Definition:
http_chunks.h:84
Curl_unencode_deflate_write
CURLcode Curl_unencode_deflate_write(struct connectdata *conn, struct SingleRequest *req, ssize_t nread)
connectdata
Definition:
urldata.h:787
Curl_chunker::datasize
curl_off_t datasize
Definition:
http_chunks.h:86
data
Definition:
debug.c:29
connectdata::data
struct Curl_easy * data
Definition:
urldata.h:791
rc_tagdetect_client
Author(s): Monika Florek-Jasinska
, Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15