00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "setup.h"
00024
00025 #ifndef CURL_DISABLE_HTTP
00026
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdarg.h>
00030 #include <stdlib.h>
00031 #include <ctype.h>
00032
00033 #include "urldata.h"
00034 #include "sendf.h"
00035
00036 #include "content_encoding.h"
00037 #include "http.h"
00038 #include "memory.h"
00039 #include "easyif.h"
00040
00041 #define _MPRINTF_REPLACE
00042 #include <curl/mprintf.h>
00043
00044
00045 #include "memdebug.h"
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 void Curl_httpchunk_init(struct connectdata *conn)
00086 {
00087 struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk;
00088 chunk->hexindex=0;
00089 chunk->dataleft=0;
00090 chunk->state = CHUNK_HEX;
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
00105 char *datap,
00106 ssize_t datalen,
00107 ssize_t *wrotep)
00108 {
00109 CURLcode result=CURLE_OK;
00110 struct SessionHandle *data = conn->data;
00111 struct Curl_chunker *ch = &data->reqdata.proto.http->chunk;
00112 struct Curl_transfer_keeper *k = &data->reqdata.keep;
00113 size_t piece;
00114 size_t length = (size_t)datalen;
00115 size_t *wrote = (size_t *)wrotep;
00116
00117 *wrote = 0;
00118
00119
00120
00121 if ( data->set.http_te_skip )
00122 Curl_client_write(conn, CLIENTWRITE_BODY, datap,datalen);
00123
00124
00125 while(length) {
00126 switch(ch->state) {
00127 case CHUNK_HEX:
00128
00129
00130 if((*datap >= 0x30 && *datap <= 0x39)
00131 || (*datap >= 0x41 && *datap <= 0x46)
00132 || (*datap >= 0x61 && *datap <= 0x66)) {
00133 if(ch->hexindex < MAXNUM_SIZE) {
00134 ch->hexbuffer[ch->hexindex] = *datap;
00135 datap++;
00136 length--;
00137 ch->hexindex++;
00138 }
00139 else {
00140 return CHUNKE_TOO_LONG_HEX;
00141 }
00142 }
00143 else {
00144 if(0 == ch->hexindex) {
00145
00146
00147 return CHUNKE_ILLEGAL_HEX;
00148 }
00149
00150 ch->hexbuffer[ch->hexindex]=0;
00151 #ifdef CURL_DOES_CONVERSIONS
00152
00153 result = Curl_convert_from_network(conn->data,
00154 ch->hexbuffer,
00155 ch->hexindex);
00156 if(result != CURLE_OK) {
00157
00158
00159 return(CHUNKE_ILLEGAL_HEX);
00160 }
00161 #endif
00162 ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
00163 ch->state = CHUNK_POSTHEX;
00164 }
00165 break;
00166
00167 case CHUNK_POSTHEX:
00168
00169
00170
00171 if(*datap == 0x0d)
00172 ch->state = CHUNK_CR;
00173 length--;
00174 datap++;
00175 break;
00176
00177 case CHUNK_CR:
00178
00179 if(*datap == 0x0a) {
00180
00181 if(0 == ch->datasize) {
00182 if (conn->bits.trailerHdrPresent!=TRUE) {
00183
00184 ch->state = CHUNK_STOPCR;
00185
00186
00187
00188 length--;
00189 datap++;
00190
00191
00192 break;
00193 }
00194 else {
00195 ch->state = CHUNK_TRAILER;
00196 conn->trlPos=0;
00197 }
00198 }
00199 else {
00200 ch->state = CHUNK_DATA;
00201 }
00202 }
00203 else
00204
00205 ch->state = CHUNK_CR;
00206 datap++;
00207 length--;
00208 break;
00209
00210 case CHUNK_DATA:
00211
00212
00213
00214
00215
00216 piece = (ch->datasize >= length)?length:ch->datasize;
00217
00218
00219 #ifdef HAVE_LIBZ
00220 switch (conn->data->set.http_ce_skip?
00221 IDENTITY : data->reqdata.keep.content_encoding) {
00222 case IDENTITY:
00223 #endif
00224 if(!k->ignorebody) {
00225 if ( !data->set.http_te_skip )
00226 result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
00227 piece);
00228 else
00229 result = CURLE_OK;
00230 }
00231 #ifdef HAVE_LIBZ
00232 break;
00233
00234 case DEFLATE:
00235
00236 data->reqdata.keep.str = datap;
00237 result = Curl_unencode_deflate_write(conn, &data->reqdata.keep,
00238 (ssize_t)piece);
00239 break;
00240
00241 case GZIP:
00242
00243 data->reqdata.keep.str = datap;
00244 result = Curl_unencode_gzip_write(conn, &data->reqdata.keep,
00245 (ssize_t)piece);
00246 break;
00247
00248 case COMPRESS:
00249 default:
00250 failf (conn->data,
00251 "Unrecognized content encoding type. "
00252 "libcurl understands `identity', `deflate' and `gzip' "
00253 "content encodings.");
00254 return CHUNKE_BAD_ENCODING;
00255 }
00256 #endif
00257
00258 if(result)
00259 return CHUNKE_WRITE_ERROR;
00260
00261 *wrote += piece;
00262
00263 ch->datasize -= piece;
00264 datap += piece;
00265 length -= piece;
00266
00267 if(0 == ch->datasize)
00268
00269 ch->state = CHUNK_POSTCR;
00270 break;
00271
00272 case CHUNK_POSTCR:
00273 if(*datap == 0x0d) {
00274 ch->state = CHUNK_POSTLF;
00275 datap++;
00276 length--;
00277 }
00278 else {
00279 return CHUNKE_BAD_CHUNK;
00280 }
00281 break;
00282
00283 case CHUNK_POSTLF:
00284 if(*datap == 0x0a) {
00285
00286
00287
00288
00289 Curl_httpchunk_init(conn);
00290 datap++;
00291 length--;
00292 }
00293 else {
00294 return CHUNKE_BAD_CHUNK;
00295 }
00296
00297 break;
00298
00299 case CHUNK_TRAILER:
00300
00301
00302 if (conn->trlPos >= conn->trlMax) {
00303 char *ptr;
00304 if(conn->trlMax) {
00305 conn->trlMax *= 2;
00306 ptr = (char*)realloc(conn->trailer,conn->trlMax);
00307 }
00308 else {
00309 conn->trlMax=128;
00310 ptr = (char*)malloc(conn->trlMax);
00311 }
00312 if(!ptr)
00313 return CHUNKE_OUT_OF_MEMORY;
00314 conn->trailer = ptr;
00315 }
00316 conn->trailer[conn->trlPos++]=*datap;
00317
00318 if(*datap == 0x0d)
00319 ch->state = CHUNK_TRAILER_CR;
00320 else {
00321 datap++;
00322 length--;
00323 }
00324 break;
00325
00326 case CHUNK_TRAILER_CR:
00327 if(*datap == 0x0d) {
00328 ch->state = CHUNK_TRAILER_POSTCR;
00329 datap++;
00330 length--;
00331 }
00332 else
00333 return CHUNKE_BAD_CHUNK;
00334 break;
00335
00336 case CHUNK_TRAILER_POSTCR:
00337 if (*datap == 0x0a) {
00338 conn->trailer[conn->trlPos++]=0x0a;
00339 conn->trailer[conn->trlPos]=0;
00340 if (conn->trlPos==2) {
00341 ch->state = CHUNK_STOP;
00342 datap++;
00343 length--;
00344
00345
00346
00347
00348
00349
00350 ch->dataleft = length;
00351
00352 return CHUNKE_STOP;
00353 }
00354 else {
00355 #ifdef CURL_DOES_CONVERSIONS
00356
00357 result = Curl_convert_from_network(conn->data,
00358 conn->trailer,
00359 conn->trlPos);
00360 if(result != CURLE_OK) {
00361
00362
00363 return(CHUNKE_BAD_CHUNK);
00364 }
00365 #endif
00366 if ( !data->set.http_te_skip )
00367 Curl_client_write(conn, CLIENTWRITE_HEADER,
00368 conn->trailer, conn->trlPos);
00369 }
00370 ch->state = CHUNK_TRAILER;
00371 conn->trlPos=0;
00372 datap++;
00373 length--;
00374 }
00375 else
00376 return CHUNKE_BAD_CHUNK;
00377 break;
00378
00379 case CHUNK_STOPCR:
00380
00381
00382 if(*datap == 0x0d) {
00383 ch->state = CHUNK_STOP;
00384 datap++;
00385 length--;
00386 }
00387 else {
00388 return CHUNKE_BAD_CHUNK;
00389 }
00390 break;
00391
00392 case CHUNK_STOP:
00393 if (*datap == 0x0a) {
00394 datap++;
00395 length--;
00396
00397
00398
00399
00400 ch->dataleft = length;
00401 return CHUNKE_STOP;
00402 }
00403 else {
00404 return CHUNKE_BAD_CHUNK;
00405 }
00406
00407
00408 default:
00409 return CHUNKE_STATE_ERROR;
00410 }
00411 }
00412 return CHUNKE_OK;
00413 }
00414 #endif