doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
http_chunks.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, 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 http://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  * $Id: http_chunks.c,v 1.23 2004/03/04 15:25:06 bagder Exp $
22  ***************************************************************************/
23 #include "setup.h"
24 
25 #ifndef CURL_DISABLE_HTTP
26 /* -- WIN32 approved -- */
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 
33 #include "urldata.h" /* it includes http_chunks.h */
34 #include "sendf.h" /* for the client write stuff */
35 
36 #include "content_encoding.h" /* 08/29/02 jhrg */
37 #include "http.h"
38 
39 #define _MPRINTF_REPLACE /* use our functions only */
40 #include <curl/mprintf.h>
41 
42 /* The last #include file should be: */
43 #ifdef CURLDEBUG
44 #include "memdebug.h"
45 #endif
46 
47 /*
48  * Chunk format (simplified):
49  *
50  * <HEX SIZE>[ chunk extension ] CRLF
51  * <DATA> CRLF
52  *
53  * Highlights from RFC2616 section 3.6 say:
54 
55  The chunked encoding modifies the body of a message in order to
56  transfer it as a series of chunks, each with its own size indicator,
57  followed by an OPTIONAL trailer containing entity-header fields. This
58  allows dynamically produced content to be transferred along with the
59  information necessary for the recipient to verify that it has
60  received the full message.
61 
62  Chunked-Body = *chunk
63  last-chunk
64  trailer
65  CRLF
66 
67  chunk = chunk-size [ chunk-extension ] CRLF
68  chunk-data CRLF
69  chunk-size = 1*HEX
70  last-chunk = 1*("0") [ chunk-extension ] CRLF
71 
72  chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
73  chunk-ext-name = token
74  chunk-ext-val = token | quoted-string
75  chunk-data = chunk-size(OCTET)
76  trailer = *(entity-header CRLF)
77 
78  The chunk-size field is a string of hex digits indicating the size of
79  the chunk. The chunked encoding is ended by any chunk whose size is
80  zero, followed by the trailer, which is terminated by an empty line.
81 
82  */
83 
84 
85 void Curl_httpchunk_init(struct connectdata *conn)
86 {
87  struct Curl_chunker *chunk = &conn->proto.http->chunk;
88  chunk->hexindex=0; /* start at 0 */
89  chunk->dataleft=0; /* no data left yet! */
90  chunk->state = CHUNK_HEX; /* we get hex first! */
91 }
92 
93 /*
94  * chunk_read() returns a OK for normal operations, or a positive return code
95  * for errors. STOP means this sequence of chunks is complete. The 'wrote'
96  * argument is set to tell the caller how many bytes we actually passed to the
97  * client (for byte-counting and whatever).
98  *
99  * The states and the state-machine is further explained in the header file.
100  */
102  char *datap,
103  ssize_t datalen,
104  ssize_t *wrotep)
105 {
107  struct Curl_chunker *ch = &conn->proto.http->chunk;
108  struct Curl_transfer_keeper *k = &conn->keep;
109  size_t piece;
110  size_t length = (size_t)datalen;
111  size_t *wrote = (size_t *)wrotep;
112 
113  *wrote = 0; /* nothing's written yet */
114 
115  while(length) {
116  switch(ch->state) {
117  case CHUNK_HEX:
118  if(isxdigit((int)*datap)) {
119  if(ch->hexindex < MAXNUM_SIZE) {
120  ch->hexbuffer[ch->hexindex] = *datap;
121  datap++;
122  length--;
123  ch->hexindex++;
124  }
125  else {
126  return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
127  }
128  }
129  else {
130  if(0 == ch->hexindex) {
131  /* This is illegal data, we received junk where we expected
132  a hexadecimal digit. */
133  return CHUNKE_ILLEGAL_HEX;
134  }
135  /* length and datap are unmodified */
136  ch->hexbuffer[ch->hexindex]=0;
137  ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
138  ch->state = CHUNK_POSTHEX;
139  }
140  break;
141 
142  case CHUNK_POSTHEX:
143  /* In this state, we're waiting for CRLF to arrive. We support
144  this to allow so called chunk-extensions to show up here
145  before the CRLF comes. */
146  if(*datap == '\r')
147  ch->state = CHUNK_CR;
148  length--;
149  datap++;
150  break;
151 
152  case CHUNK_CR:
153  /* waiting for the LF */
154  if(*datap == '\n') {
155  /* we're now expecting data to come, unless size was zero! */
156  if(0 == ch->datasize) {
157  ch->state = CHUNK_STOP; /* stop reading! */
158  if(1 == length) {
159  /* This was the final byte, return right now */
160  return CHUNKE_STOP;
161  }
162  }
163  else
164  ch->state = CHUNK_DATA;
165  }
166  else
167  /* previously we got a fake CR, go back to CR waiting! */
168  ch->state = CHUNK_CR;
169  datap++;
170  length--;
171  break;
172 
173  case CHUNK_DATA:
174  /* we get pure and fine data
175 
176  We expect another 'datasize' of data. We have 'length' right now,
177  it can be more or less than 'datasize'. Get the smallest piece.
178  */
179  piece = (ch->datasize >= length)?length:ch->datasize;
180 
181  /* Write the data portion available */
182  /* Added content-encoding here; untested but almost identical to the
183  tested code in transfer.c. 08/29/02 jhrg */
184 #ifdef HAVE_LIBZ
185  switch (conn->keep.content_encoding) {
186  case IDENTITY:
187 #endif
188  if(!k->ignorebody)
189  result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
190  piece);
191 #ifdef HAVE_LIBZ
192  break;
193 
194  case DEFLATE:
195  /* update conn->keep.str to point to the chunk data. */
196  conn->keep.str = datap;
197  result = Curl_unencode_deflate_write(conn->data, &conn->keep, piece);
198  break;
199 
200  case GZIP:
201  /* update conn->keep.str to point to the chunk data. */
202  conn->keep.str = datap;
203  result = Curl_unencode_gzip_write(conn->data, &conn->keep, piece);
204  break;
205 
206  case COMPRESS:
207  default:
208  failf (conn->data,
209  "Unrecognized content encoding type. "
210  "libcurl understands `identity', `deflate' and `gzip' "
211  "content encodings.");
212  return CHUNKE_BAD_ENCODING;
213  }
214 #endif
215 
216  if(result)
217  return CHUNKE_WRITE_ERROR;
218 
219  *wrote += piece;
220 
221  ch->datasize -= piece; /* decrease amount left to expect */
222  datap += piece; /* move read pointer forward */
223  length -= piece; /* decrease space left in this round */
224 
225  if(0 == ch->datasize)
226  /* end of data this round, we now expect a trailing CRLF */
227  ch->state = CHUNK_POSTCR;
228  break;
229 
230  case CHUNK_POSTCR:
231  if(*datap == '\r') {
232  ch->state = CHUNK_POSTLF;
233  datap++;
234  length--;
235  }
236  else
237  return CHUNKE_BAD_CHUNK;
238  break;
239 
240  case CHUNK_POSTLF:
241  if(*datap == '\n') {
242  /*
243  * The last one before we go back to hex state and start all
244  * over.
245  */
246  Curl_httpchunk_init(conn);
247  datap++;
248  length--;
249  }
250  else
251  return CHUNKE_BAD_CHUNK;
252  break;
253 
254  case CHUNK_STOP:
255  /* If we arrive here, there is data left in the end of the buffer
256  even if there's no more chunks to read */
257  ch->dataleft = length;
258  return CHUNKE_STOP; /* return stop */
259  default:
260  return CHUNKE_STATE_ERROR;
261  }
262  }
263  return CHUNKE_OK;
264 }
265 #endif /* CURL_DISABLE_HTTP */
CURLcode Curl_unencode_gzip_write(struct SessionHandle *data, struct Curl_transfer_keeper *k, ssize_t nread)
#define DEFLATE
Definition: urldata.h:348
#define CLIENTWRITE_BODY
Definition: sendf.h:34
struct Curl_transfer_keeper keep
Definition: urldata.h:553
union connectdata::@11 proto
CURLcode Curl_unencode_deflate_write(struct SessionHandle *data, struct Curl_transfer_keeper *k, ssize_t nread)
void Curl_httpchunk_init(struct connectdata *conn)
Definition: http_chunks.c:85
#define COMPRESS
Definition: urldata.h:350
#define GZIP
Definition: urldata.h:349
#define HAVE_LIBZ
#define failf
Definition: sendf.h:32
CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr, size_t len)
Definition: sendf.c:319
CURLcode
Definition: curl.h:209
size_t dataleft
Definition: http_chunks.h:85
Boolean result
#define ssize_t
Definition: config-win32.h:27
struct HTTP * http
Definition: urldata.h:539
char hexbuffer[MAXNUM_SIZE+1]
Definition: http_chunks.h:81
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t datalen, ssize_t *wrotep)
Definition: http_chunks.c:101
#define NULL
Definition: Lib.h:88
CHUNKcode
Definition: http_chunks.h:68
Definition: curl.h:210
struct SessionHandle * data
Definition: urldata.h:403
ChunkyState state
Definition: http_chunks.h:83
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
size_t datasize
Definition: http_chunks.h:84
struct Curl_chunker chunk
Definition: urldata.h:218
#define IDENTITY
Definition: urldata.h:347
#define MAXNUM_SIZE
Definition: http_chunks.h:30