summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/http_chunks.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/http_chunks.c')
-rw-r--r--Utilities/cmcurl/http_chunks.c154
1 files changed, 125 insertions, 29 deletions
diff --git a/Utilities/cmcurl/http_chunks.c b/Utilities/cmcurl/http_chunks.c
index 02fdfc5..1b03a55 100644
--- a/Utilities/cmcurl/http_chunks.c
+++ b/Utilities/cmcurl/http_chunks.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2007, 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
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -35,7 +35,8 @@
#include "content_encoding.h"
#include "http.h"
-#include "curl_memory.h"
+#include "memory.h"
+#include "easyif.h" /* for Curl_convert_to_network prototype */
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -43,7 +44,7 @@
/* The last #include file should be: */
#include "memdebug.h"
-/*
+/*
* Chunk format (simplified):
*
* <HEX SIZE>[ chunk extension ] CRLF
@@ -83,7 +84,7 @@
void Curl_httpchunk_init(struct connectdata *conn)
{
- struct Curl_chunker *chunk = &conn->proto.http->chunk;
+ struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk;
chunk->hexindex=0; /* start at 0 */
chunk->dataleft=0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */
@@ -96,6 +97,9 @@ void Curl_httpchunk_init(struct connectdata *conn)
* client (for byte-counting and whatever).
*
* The states and the state-machine is further explained in the header file.
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
*/
CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
char *datap,
@@ -103,8 +107,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
ssize_t *wrotep)
{
CURLcode result=CURLE_OK;
- struct Curl_chunker *ch = &conn->proto.http->chunk;
- struct Curl_transfer_keeper *k = &conn->keep;
+ struct SessionHandle *data = conn->data;
+ struct Curl_chunker *ch = &data->reqdata.proto.http->chunk;
+ struct Curl_transfer_keeper *k = &data->reqdata.keep;
size_t piece;
size_t length = (size_t)datalen;
size_t *wrote = (size_t *)wrotep;
@@ -114,7 +119,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
while(length) {
switch(ch->state) {
case CHUNK_HEX:
- if(isxdigit((int)*datap)) {
+ /* Check for an ASCII hex digit.
+ We avoid the use of isxdigit to accommodate non-ASCII hosts. */
+ if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */
+ || (*datap >= 0x41 && *datap <= 0x46) /* A-F */
+ || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */
if(ch->hexindex < MAXNUM_SIZE) {
ch->hexbuffer[ch->hexindex] = *datap;
datap++;
@@ -133,6 +142,17 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
}
/* 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,
+ ch->hexindex);
+ if(result != CURLE_OK) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad hex character */
+ return(CHUNKE_ILLEGAL_HEX);
+ }
+#endif /* CURL_DOES_CONVERSIONS */
ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
ch->state = CHUNK_POSTHEX;
}
@@ -142,7 +162,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
/* 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 == '\r')
+ if(*datap == 0x0d)
ch->state = CHUNK_CR;
length--;
datap++;
@@ -150,13 +170,20 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
case CHUNK_CR:
/* waiting for the LF */
- if(*datap == '\n') {
+ if(*datap == 0x0a) {
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
- ch->state = CHUNK_STOP; /* stop reading! */
- if(1 == length) {
- /* This was the final byte, return right now */
- return CHUNKE_STOP;
+ if (conn->bits.trailerHdrPresent!=TRUE) {
+ /* No Trailer: header found - revert to original Curl processing */
+ ch->state = CHUNK_STOP;
+ if (1 == length) {
+ /* This is the final byte, return right now */
+ return CHUNKE_STOP;
+ }
+ }
+ else {
+ ch->state = CHUNK_TRAILER; /* attempt to read trailers */
+ conn->trlPos=0;
}
}
else
@@ -179,26 +206,26 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
/* Write the data portion available */
#ifdef HAVE_LIBZ
- switch (conn->keep.content_encoding) {
+ switch (data->reqdata.keep.content_encoding) {
case IDENTITY:
#endif
if(!k->ignorebody)
- result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
piece);
#ifdef HAVE_LIBZ
break;
- case DEFLATE:
- /* update conn->keep.str to point to the chunk data. */
- conn->keep.str = datap;
- result = Curl_unencode_deflate_write(conn->data, &conn->keep,
+ case DEFLATE:
+ /* update data->reqdata.keep.str to point to the chunk data. */
+ data->reqdata.keep.str = datap;
+ result = Curl_unencode_deflate_write(conn, &data->reqdata.keep,
(ssize_t)piece);
break;
case GZIP:
- /* update conn->keep.str to point to the chunk data. */
- conn->keep.str = datap;
- result = Curl_unencode_gzip_write(conn->data, &conn->keep,
+ /* update data->reqdata.keep.str to point to the chunk data. */
+ data->reqdata.keep.str = datap;
+ result = Curl_unencode_gzip_write(conn, &data->reqdata.keep,
(ssize_t)piece);
break;
@@ -227,7 +254,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
break;
case CHUNK_POSTCR:
- if(*datap == '\r') {
+ if(*datap == 0x0d) {
ch->state = CHUNK_POSTLF;
datap++;
length--;
@@ -237,7 +264,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
break;
case CHUNK_POSTLF:
- if(*datap == '\n') {
+ if(*datap == 0x0a) {
/*
* The last one before we go back to hex state and start all
* over.
@@ -250,6 +277,75 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
return CHUNKE_BAD_CHUNK;
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 = (char*)realloc(conn->trailer,conn->trlMax);
+ }
+ else {
+ conn->trlMax=128;
+ ptr = (char*)malloc(conn->trlMax);
+ }
+ if(!ptr)
+ return CHUNKE_OUT_OF_MEMORY;
+ conn->trailer = ptr;
+ }
+ conn->trailer[conn->trlPos++]=*datap;
+
+ if(*datap == 0x0d)
+ ch->state = CHUNK_TRAILER_CR;
+ else {
+ datap++;
+ length--;
+ }
+ break;
+
+ 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;
+ return CHUNKE_STOP;
+ }
+ else {
+#ifdef CURL_DOES_CONVERSIONS
+ /* Convert to host encoding before calling Curl_client_write */
+ result = Curl_convert_from_network(conn->data,
+ conn->trailer,
+ conn->trlPos);
+ if(result != CURLE_OK) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad chunk */
+ return(CHUNKE_BAD_CHUNK);
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+ Curl_client_write(conn, CLIENTWRITE_HEADER,
+ conn->trailer, conn->trlPos);
+ }
+ ch->state = CHUNK_TRAILER;
+ conn->trlPos=0;
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ break;
+
case CHUNK_STOP:
/* If we arrive here, there is data left in the end of the buffer
even if there's no more chunks to read */