* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
- * $Id$
***************************************************************************/
-#include "setup.h"
+
+#include "curl_setup.h"
#ifndef CURL_DISABLE_HTTP
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
#include "urldata.h" /* it includes http_chunks.h */
#include "sendf.h" /* for the client write stuff */
#include "content_encoding.h"
#include "http.h"
#include "curl_memory.h"
-#include "easyif.h" /* for Curl_convert_to_network prototype */
+#include "non-ascii.h" /* for Curl_convert_to_network prototype */
+#include "strtoofft.h"
+#include "warnless.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
We avoid the use of isxdigit to accommodate non-ASCII hosts. */
static bool Curl_isxdigit(char digit)
{
- return (bool)( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
- || (digit >= 0x41 && digit <= 0x46) /* A-F */
- || (digit >= 0x61 && digit <= 0x66) ); /* a-f */
+ return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
+ || (digit >= 0x41 && digit <= 0x46) /* A-F */
+ || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE;
}
void Curl_httpchunk_init(struct connectdata *conn)
{
struct Curl_chunker *chunk = &conn->chunk;
- chunk->hexindex=0; /* start at 0 */
- chunk->dataleft=0; /* no data left yet! */
+ chunk->hexindex=0; /* start at 0 */
+ chunk->dataleft=0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */
}
struct Curl_chunker *ch = &conn->chunk;
struct SingleRequest *k = &data->req;
size_t piece;
- size_t length = (size_t)datalen;
+ curl_off_t length = (curl_off_t)datalen;
size_t *wrote = (size_t *)wrotep;
*wrote = 0; /* nothing's written yet */
}
}
else {
- if(0 == ch->hexindex) {
+ char *endptr;
+ if(0 == ch->hexindex)
/* This is illegal data, we received junk where we expected
a hexadecimal digit. */
return CHUNKE_ILLEGAL_HEX;
- }
+
/* length and datap are unmodified */
ch->hexbuffer[ch->hexindex]=0;
-#ifdef CURL_DOES_CONVERSIONS
+
/* convert to host encoding before calling strtoul */
- result = Curl_convert_from_network(conn->data,
- ch->hexbuffer,
+ result = Curl_convert_from_network(conn->data, ch->hexbuffer,
ch->hexindex);
- if(result != CURLE_OK) {
+ if(result) {
/* Curl_convert_from_network calls failf if unsuccessful */
/* Treat it as a bad hex character */
- return(CHUNKE_ILLEGAL_HEX);
+ return CHUNKE_ILLEGAL_HEX ;
}
-#endif /* CURL_DOES_CONVERSIONS */
- ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
- ch->state = CHUNK_POSTHEX;
- }
- break;
- case CHUNK_POSTHEX:
- /* In this state, we're waiting for CRLF to arrive. We support
- this to allow so called chunk-extensions to show up here
- before the CRLF comes. */
- if(*datap == 0x0d)
- ch->state = CHUNK_CR;
- length--;
- datap++;
+ ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16);
+ if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE))
+ /* overflow is an error */
+ return CHUNKE_ILLEGAL_HEX;
+ ch->state = CHUNK_LF; /* now wait for the CRLF */
+ }
break;
- case CHUNK_CR:
- /* waiting for the LF */
+ case CHUNK_LF:
+ /* waiting for the LF after a chunk size */
if(*datap == 0x0a) {
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
- if(k->trailerhdrpresent!=TRUE) {
- /* No Trailer: header found - revert to original Curl processing */
- ch->state = CHUNK_STOPCR;
-
- /* We need to increment the datap here since we bypass the
- increment below with the immediate break */
- length--;
- datap++;
-
- /* This is the final byte, continue to read the final CRLF */
- break;
- }
- else {
- ch->state = CHUNK_TRAILER; /* attempt to read trailers */
- conn->trlPos=0;
- }
+ ch->state = CHUNK_TRAILER; /* now check for trailers */
+ conn->trlPos=0;
}
- else {
+ else
ch->state = CHUNK_DATA;
- }
}
- else
- /* previously we got a fake CR, go back to CR waiting! */
- ch->state = CHUNK_CR;
+
datap++;
length--;
break;
case CHUNK_DATA:
- /* we get pure and fine data
-
- We expect another 'datasize' of data. We have 'length' right now,
- it can be more or less than 'datasize'. Get the smallest piece.
+ /* We expect 'datasize' of data. We have 'length' right now, it can be
+ more or less than 'datasize'. Get the smallest piece.
*/
- piece = (ch->datasize >= length)?length:ch->datasize;
+ piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
/* Write the data portion available */
#ifdef HAVE_LIBZ
switch (conn->data->set.http_ce_skip?
- IDENTITY : data->req.content_encoding) {
+ IDENTITY : data->req.auto_decoding) {
case IDENTITY:
#endif
if(!k->ignorebody) {
- if( !data->set.http_te_skip )
+ if(!data->set.http_te_skip)
result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
piece);
else
if(0 == ch->datasize)
/* end of data this round, we now expect a trailing CRLF */
- ch->state = CHUNK_POSTCR;
- break;
-
- case CHUNK_POSTCR:
- if(*datap == 0x0d) {
ch->state = CHUNK_POSTLF;
- datap++;
- length--;
- }
- else {
- return CHUNKE_BAD_CHUNK;
- }
break;
case CHUNK_POSTLF:
if(*datap == 0x0a) {
- /*
- * The last one before we go back to hex state and start all
- * over.
- */
- Curl_httpchunk_init(conn);
- datap++;
- length--;
+ /* The last one before we go back to hex state and start all over. */
+ Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */
}
- else {
+ else if(*datap != 0x0d)
return CHUNKE_BAD_CHUNK;
- }
-
+ datap++;
+ length--;
break;
case CHUNK_TRAILER:
- /* conn->trailer is assumed to be freed in url.c on a
- connection basis */
- if(conn->trlPos >= conn->trlMax) {
- char *ptr;
- if(conn->trlMax) {
- conn->trlMax *= 2;
- ptr = realloc(conn->trailer,conn->trlMax);
- }
- else {
- conn->trlMax=128;
- ptr = malloc(conn->trlMax);
- }
- if(!ptr)
- return CHUNKE_OUT_OF_MEMORY;
- conn->trailer = ptr;
- }
- conn->trailer[conn->trlPos++]=*datap;
+ if((*datap == 0x0d) || (*datap == 0x0a)) {
+ /* this is the end of a trailer, but if the trailer was zero bytes
+ there was no trailer and we move on */
- if(*datap == 0x0d)
- ch->state = CHUNK_TRAILER_CR;
- else {
- datap++;
- length--;
- }
- break;
+ if(conn->trlPos) {
+ /* we allocate trailer with 3 bytes extra room to fit this */
+ conn->trailer[conn->trlPos++]=0x0d;
+ conn->trailer[conn->trlPos++]=0x0a;
+ conn->trailer[conn->trlPos]=0;
- case CHUNK_TRAILER_CR:
- if(*datap == 0x0d) {
- ch->state = CHUNK_TRAILER_POSTCR;
- datap++;
- length--;
- }
- else
- return CHUNKE_BAD_CHUNK;
- break;
-
- case CHUNK_TRAILER_POSTCR:
- if(*datap == 0x0a) {
- conn->trailer[conn->trlPos++]=0x0a;
- conn->trailer[conn->trlPos]=0;
- if(conn->trlPos==2) {
- ch->state = CHUNK_STOP;
- length--;
-
- /*
- * Note that this case skips over the final STOP states since we've
- * already read the final CRLF and need to return
- */
-
- ch->dataleft = length;
-
- return CHUNKE_STOP; /* return stop */
- }
- else {
-#ifdef CURL_DOES_CONVERSIONS
/* Convert to host encoding before calling Curl_client_write */
- result = Curl_convert_from_network(conn->data,
- conn->trailer,
+ result = Curl_convert_from_network(conn->data, conn->trailer,
conn->trlPos);
- if(result != CURLE_OK) {
+ if(result)
/* Curl_convert_from_network calls failf if unsuccessful */
/* Treat it as a bad chunk */
- return(CHUNKE_BAD_CHUNK);
- }
-#endif /* CURL_DOES_CONVERSIONS */
+ return CHUNKE_BAD_CHUNK;
+
if(!data->set.http_te_skip) {
result = Curl_client_write(conn, CLIENTWRITE_HEADER,
conn->trailer, conn->trlPos);
if(result)
return CHUNKE_WRITE_ERROR;
}
+ conn->trlPos=0;
+ ch->state = CHUNK_TRAILER_CR;
+ if(*datap == 0x0a)
+ /* already on the LF */
+ break;
}
- ch->state = CHUNK_TRAILER;
- conn->trlPos=0;
+ else {
+ /* no trailer, we're on the final CRLF pair */
+ ch->state = CHUNK_TRAILER_POSTCR;
+ break; /* don't advance the pointer */
+ }
+ }
+ else {
+ /* conn->trailer is assumed to be freed in url.c on a
+ connection basis */
+ if(conn->trlPos >= conn->trlMax) {
+ /* we always allocate three extra bytes, just because when the full
+ header has been received we append CRLF\0 */
+ char *ptr;
+ if(conn->trlMax) {
+ conn->trlMax *= 2;
+ ptr = realloc(conn->trailer, conn->trlMax + 3);
+ }
+ else {
+ conn->trlMax=128;
+ ptr = malloc(conn->trlMax + 3);
+ }
+ if(!ptr)
+ return CHUNKE_OUT_OF_MEMORY;
+ conn->trailer = ptr;
+ }
+ conn->trailer[conn->trlPos++]=*datap;
+ }
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_TRAILER_CR:
+ if(*datap == 0x0a) {
+ ch->state = CHUNK_TRAILER_POSTCR;
datap++;
length--;
}
return CHUNKE_BAD_CHUNK;
break;
- case CHUNK_STOPCR:
- /* Read the final CRLF that ends all chunk bodies */
-
+ case CHUNK_TRAILER_POSTCR:
+ /* We enter this state when a CR should arrive so we expect to
+ have to first pass a CR before we wait for LF */
+ if((*datap != 0x0d) && (*datap != 0x0a)) {
+ /* not a CR then it must be another header in the trailer */
+ ch->state = CHUNK_TRAILER;
+ break;
+ }
if(*datap == 0x0d) {
- ch->state = CHUNK_STOP;
+ /* skip if CR */
datap++;
length--;
}
- else {
- return CHUNKE_BAD_CHUNK;
- }
+ /* now wait for the final LF */
+ ch->state = CHUNK_STOP;
break;
case CHUNK_STOP:
/* Record the length of any data left in the end of the buffer
even if there's no more chunks to read */
+ ch->dataleft = curlx_sotouz(length);
- ch->dataleft = length;
return CHUNKE_STOP; /* return stop */
}
- else {
+ else
return CHUNKE_BAD_CHUNK;
- }
-
- default:
- return CHUNKE_STATE_ERROR;
}
}
return CHUNKE_OK;
}
+
+const char *Curl_chunked_strerror(CHUNKcode code)
+{
+ switch (code) {
+ default:
+ return "OK";
+ case CHUNKE_TOO_LONG_HEX:
+ return "Too long hexadecimal number";
+ case CHUNKE_ILLEGAL_HEX:
+ return "Illegal or missing hexadecimal sequence";
+ case CHUNKE_BAD_CHUNK:
+ return "Malformed encoding found";
+ case CHUNKE_WRITE_ERROR:
+ return "Write error";
+ case CHUNKE_BAD_ENCODING:
+ return "Bad content-encoding found";
+ case CHUNKE_OUT_OF_MEMORY:
+ return "Out of memory";
+ }
+}
+
#endif /* CURL_DISABLE_HTTP */