diff options
author | Alex Graveley <alex@ximian.com> | 2001-10-18 20:52:29 +0000 |
---|---|---|
committer | Alex Graveley <orph@src.gnome.org> | 2001-10-18 20:52:29 +0000 |
commit | 33e048884df2fd69202688f8e0a97c78f1aef786 (patch) | |
tree | 7f5403642825faac8f0c67e259448bbc351c1bda | |
parent | 3c964d7328d2620eb41b9494800c3b0453e4407a (diff) | |
download | libsoup-33e048884df2fd69202688f8e0a97c78f1aef786.tar.gz |
Set encoding out param appropriately. Ditto.
2001-10-18 Alex Graveley <alex@ximian.com>
* src/libsoup/soup-queue.c (soup_queue_read_headers_cb): Set
encoding out param appropriately.
* src/libsoup/soup-server.c (soup_httpd_read_headers_cb): Ditto.
* src/libsoup/soup-transfer.h: Add SoupTransferEncoding enum.
* src/libsoup/soup-transfer.c (soup_transfer_read_error_cb):
Handle unknown encoding by issuing the read_done callback when the
connection is closed.
(issue_chunk_callback): Pass in a cancelled arg to simplify code.
(read_unknown): Impl. Same as read_content_length () except never
return TRUE.
(soup_transfer_read_cb): Make headers_done_cb take an encoding out
parameter to avoid magic values in content_length. Switch on
encoding to see if read completed. Use issue_final_callback ().
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | libsoup/soup-queue.c | 15 | ||||
-rw-r--r-- | libsoup/soup-server.c | 12 | ||||
-rw-r--r-- | libsoup/soup-transfer.c | 204 | ||||
-rw-r--r-- | libsoup/soup-transfer.h | 16 |
5 files changed, 165 insertions, 100 deletions
@@ -1,3 +1,21 @@ +2001-10-18 Alex Graveley <alex@ximian.com> + + * src/libsoup/soup-queue.c (soup_queue_read_headers_cb): Set + encoding out param appropriately. + * src/libsoup/soup-server.c (soup_httpd_read_headers_cb): Ditto. + + * src/libsoup/soup-transfer.h: Add SoupTransferEncoding enum. + + * src/libsoup/soup-transfer.c (soup_transfer_read_error_cb): + Handle unknown encoding by issuing the read_done callback when the + connection is closed. + (issue_chunk_callback): Pass in a cancelled arg to simplify code. + (read_unknown): Impl. Same as read_content_length () except never + return TRUE. + (soup_transfer_read_cb): Make headers_done_cb take an encoding out + parameter to avoid magic values in content_length. Switch on + encoding to see if read completed. Use issue_final_callback (). + 2001-10-18 JP Rosevear <jpr@ximian.com> * src/libsoup/soup-transfer.c (remove_block_at_index): the array diff --git a/libsoup/soup-queue.c b/libsoup/soup-queue.c index b26f71ba..6cd8a60b 100644 --- a/libsoup/soup-queue.c +++ b/libsoup/soup-queue.c @@ -117,9 +117,10 @@ soup_parse_headers (const GString *headers, } static SoupTransferDone -soup_queue_read_headers_cb (const GString *headers, - guint *content_len, - gpointer user_data) +soup_queue_read_headers_cb (const GString *headers, + SoupTransferEncoding *encoding, + gint *content_len, + gpointer user_data) { SoupMessage *req = user_data; @@ -139,8 +140,11 @@ soup_queue_read_headers_cb (const GString *headers, (!connection && version == SOUP_HTTP_1_0)) soup_connection_set_keep_alive (req->connection, FALSE); - if (!g_strcasecmp (req->method, "HEAD")) + if (!g_strcasecmp (req->method, "HEAD")) { + *encoding = SOUP_TRANSFER_CONTENT_LENGTH; + *content_len = 0; goto RUN_HANDLERS; + } /* * Handle Content-Length or Chunked encoding @@ -151,6 +155,7 @@ soup_queue_read_headers_cb (const GString *headers, "Transfer-Encoding"); if (length) { + *encoding = SOUP_TRANSFER_CONTENT_LENGTH; *content_len = atoi (length); if (*content_len < 0) { soup_message_set_error_full (req, @@ -161,7 +166,7 @@ soup_queue_read_headers_cb (const GString *headers, } else if (enc) { if (g_strcasecmp (enc, "chunked") == 0) - *content_len = SOUP_TRANSFER_CHUNKED; + *encoding = SOUP_TRANSFER_CHUNKED; else { soup_message_set_error_full ( req, diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c index 90f330fc..04fb22f8 100644 --- a/libsoup/soup-server.c +++ b/libsoup/soup-server.c @@ -78,7 +78,7 @@ soup_server_free (SoupServer *serv) soup_socket_unref (serv->sock); g_hash_table_foreach_remove (serv->handlers, - (GHFunc) free_handler, + (GHRFunc) free_handler, NULL); g_hash_table_destroy (serv->handlers); @@ -130,9 +130,10 @@ write_done_cb (gpointer user_data) } static SoupTransferDone -read_headers_cb (const GString *headers, - guint *content_len, - gpointer user_data) +read_headers_cb (const GString *headers, + SoupTransferEncoding *encoding, + gint *content_len, + gpointer user_data) { SoupMessage *msg = user_data; SoupContext *ctx; @@ -163,12 +164,13 @@ read_headers_cb (const GString *headers, "Transfer-Encoding"); if (length) { + *encoding = SOUP_TRANSFER_CONTENT_LENGTH; *content_len = atoi (length); if (*content_len < 0) goto THROW_MALFORMED_HEADER; } else if (enc) { if (g_strcasecmp (enc, "chunked") == 0) - *content_len = SOUP_TRANSFER_CHUNKED; + *encoding = SOUP_TRANSFER_CHUNKED; else { g_warning ("Unknown encoding type in HTTP request."); goto THROW_MALFORMED_HEADER; diff --git a/libsoup/soup-transfer.c b/libsoup/soup-transfer.c index e622531e..cd1b479a 100644 --- a/libsoup/soup-transfer.c +++ b/libsoup/soup-transfer.c @@ -53,12 +53,9 @@ typedef struct { guint header_len; gboolean overwrite_chunks; - guint content_length; - /* - * True if this is a chunked transfer - */ - gboolean is_chunked; + SoupTransferEncoding encoding; + gint content_length; SoupTransferChunkState chunk_state; SoupReadHeadersDoneFn headers_done_cb; @@ -105,6 +102,29 @@ soup_transfer_read_cancel (guint tag) g_free (r); } +static void +issue_final_callback (SoupReader *r) +{ + if (r->read_done_cb) { + SoupDataBuffer buf = { + SOUP_BUFFER_SYSTEM_OWNED, + r->recv_buf->data, + r->recv_buf->len + }; + + /* + * Null terminate + */ + g_byte_array_append (r->recv_buf, "\0", 1); + + r->callback_issued = TRUE; + + IGNORE_CANCEL (r); + (*r->read_done_cb) (&buf, r->user_data); + UNIGNORE_CANCEL (r); + } +} + static gboolean soup_transfer_read_error_cb (GIOChannel* iochannel, GIOCondition condition, @@ -112,16 +132,20 @@ soup_transfer_read_error_cb (GIOChannel* iochannel, { gboolean body_started = r->recv_buf->len > r->header_len; - /* - * Some URIs signal end-of-file by closing the connection + /* + * Closing the connection to signify EOF is valid if content length is + * unknown. */ - if (body_started && !r->content_length && !r->is_chunked) - return TRUE; + if (r->encoding == SOUP_TRANSFER_UNKNOWN) { + issue_final_callback (r); + goto CANCELLED; + } IGNORE_CANCEL (r); if (r->error_cb) (*r->error_cb) (body_started, r->user_data); UNIGNORE_CANCEL (r); + CANCELLED: soup_transfer_read_cancel (GPOINTER_TO_INT (r)); return FALSE; @@ -144,41 +168,6 @@ remove_block_at_index (GByteArray *arr, gint offset, gint length) g_byte_array_set_size (arr, arr->len - length); } -static SoupTransferDone -issue_chunk_callback (SoupReader *r, gchar *data, gint len) -{ - SoupTransferDone cont = SOUP_TRANSFER_CONTINUE; - - /* - * Null terminate - */ - g_byte_array_append (r->recv_buf, "\0", 1); - - /* - * Call chunk callback. Pass len worth of data. - */ - if (r->read_chunk_cb && len) { - SoupDataBuffer buf = { - SOUP_BUFFER_SYSTEM_OWNED, - data, - len - }; - - r->callback_issued = TRUE; - - IGNORE_CANCEL (r); - cont = (*r->read_chunk_cb) (&buf, r->user_data); - UNIGNORE_CANCEL (r); - } - - /* - * Remove Null - */ - g_byte_array_remove_index (r->recv_buf, r->recv_buf->len - 1); - - return cont; -} - /* * Count number of hex digits, and convert to decimal. Store number of hex * digits read in @width. @@ -291,6 +280,43 @@ decode_chunk (SoupTransferChunkState *s, return ret; } +static void +issue_chunk_callback (SoupReader *r, gchar *data, gint len, gboolean *cancelled) +{ + /* + * Null terminate + */ + g_byte_array_append (r->recv_buf, "\0", 1); + + /* + * Call chunk callback. Pass len worth of data. + */ + if (r->read_chunk_cb && len) { + SoupTransferDone cont = SOUP_TRANSFER_CONTINUE; + SoupDataBuffer buf = { + SOUP_BUFFER_SYSTEM_OWNED, + data, + len + }; + + r->callback_issued = TRUE; + + IGNORE_CANCEL (r); + cont = (*r->read_chunk_cb) (&buf, r->user_data); + UNIGNORE_CANCEL (r); + + if (cont == SOUP_TRANSFER_END) + *cancelled = TRUE; + else + *cancelled = FALSE; + } + + /* + * Remove Null + */ + g_byte_array_remove_index (r->recv_buf, r->recv_buf->len - 1); +} + static gboolean read_chunk (SoupReader *r, gboolean *cancelled) { @@ -307,13 +333,8 @@ read_chunk (SoupReader *r, gboolean *cancelled) if (!datalen) goto CANCELLED; - *cancelled = FALSE; - if (issue_chunk_callback (r, - arr->data, - s->idx) == SOUP_TRANSFER_END) { - *cancelled = TRUE; - goto CANCELLED; - } + issue_chunk_callback (r, arr->data, s->idx, cancelled); + if (*cancelled) goto CANCELLED; /* * If overwrite, remove datalen worth of data from start of buffer @@ -336,13 +357,8 @@ read_content_length (SoupReader *r, gboolean *cancelled) if (!arr->len) goto CANCELLED; - *cancelled = FALSE; - if (issue_chunk_callback (r, - arr->data, - arr->len) == SOUP_TRANSFER_END) { - *cancelled = TRUE; - goto CANCELLED; - } + issue_chunk_callback (r, arr->data, arr->len, cancelled); + if (*cancelled) goto CANCELLED; /* * If overwrite, clear @@ -357,6 +373,30 @@ read_content_length (SoupReader *r, gboolean *cancelled) } static gboolean +read_unknown (SoupReader *r, gboolean *cancelled) +{ + GByteArray *arr = r->recv_buf; + + if (!arr->len) + goto CANCELLED; + + issue_chunk_callback (r, arr->data, arr->len, cancelled); + if (*cancelled) goto CANCELLED; + + /* + * If overwrite, clear + */ + if (r->overwrite_chunks) + g_byte_array_set_size (arr, 0); + + CANCELLED: + /* + * Keep reading until we get a zero read or HUP. + */ + return FALSE; +} + +static gboolean soup_transfer_read_cb (GIOChannel *iochannel, GIOCondition condition, SoupReader *r) @@ -406,24 +446,23 @@ soup_transfer_read_cb (GIOChannel *iochannel, if (r->headers_done_cb) { GString str; SoupTransferDone ret; - gint len = 0; + + r->encoding = SOUP_TRANSFER_UNKNOWN; + r->content_length = 0; str.len = index; str.str = alloca (index); - strncpy (str.str, r->recv_buf->data, index); IGNORE_CANCEL (r); - ret = (*r->headers_done_cb) (&str, &len, r->user_data); + ret = (*r->headers_done_cb) (&str, + &r->encoding, + &r->content_length, + r->user_data); UNIGNORE_CANCEL (r); if (ret == SOUP_TRANSFER_END) goto FINISH_READ; - - if (len == -1) - r->is_chunked = TRUE; - else - r->content_length = len; } remove_block_at_index (r->recv_buf, 0, index); @@ -433,10 +472,19 @@ soup_transfer_read_cb (GIOChannel *iochannel, if (total_read == 0) read_done = TRUE; - else if (r->is_chunked) - read_done = read_chunk (r, &cancelled); - else - read_done = read_content_length (r, &cancelled); + else { + switch (r->encoding) { + case SOUP_TRANSFER_CHUNKED: + read_done = read_chunk (r, &cancelled); + break; + case SOUP_TRANSFER_CONTENT_LENGTH: + read_done = read_content_length (r, &cancelled); + break; + case SOUP_TRANSFER_UNKNOWN: + read_done = read_unknown (r, &cancelled); + break; + } + } if (cancelled) goto FINISH_READ; @@ -446,21 +494,7 @@ soup_transfer_read_cb (GIOChannel *iochannel, goto READ_AGAIN; } - if (r->read_done_cb) { - SoupDataBuffer buf = { - SOUP_BUFFER_SYSTEM_OWNED, - r->recv_buf->data, - r->recv_buf->len - }; - - g_byte_array_append (r->recv_buf, "\0", 1); - - r->callback_issued = TRUE; - - IGNORE_CANCEL (r); - (*r->read_done_cb) (&buf, r->user_data); - UNIGNORE_CANCEL (r); - } + issue_final_callback (r); FINISH_READ: soup_transfer_read_cancel (GPOINTER_TO_INT (r)); diff --git a/libsoup/soup-transfer.h b/libsoup/soup-transfer.h index 5a7b6792..2f6b3370 100644 --- a/libsoup/soup-transfer.h +++ b/libsoup/soup-transfer.h @@ -20,11 +20,17 @@ typedef enum { SOUP_TRANSFER_CONTINUE, } SoupTransferDone; -#define SOUP_TRANSFER_CHUNKED -1 - -typedef SoupTransferDone (*SoupReadHeadersDoneFn) (const GString *headers, - guint *content_len, - gpointer user_data); +typedef enum { + SOUP_TRANSFER_UNKNOWN = 0, + SOUP_TRANSFER_CHUNKED, + SOUP_TRANSFER_CONTENT_LENGTH, +} SoupTransferEncoding; + +typedef SoupTransferDone (*SoupReadHeadersDoneFn) ( + const GString *headers, + SoupTransferEncoding *encoding, + gint *content_len, + gpointer user_data); typedef SoupTransferDone (*SoupReadChunkFn) (const SoupDataBuffer *data, gpointer user_data); |