summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Graveley <alex@ximian.com>2001-10-18 20:52:29 +0000
committerAlex Graveley <orph@src.gnome.org>2001-10-18 20:52:29 +0000
commit33e048884df2fd69202688f8e0a97c78f1aef786 (patch)
tree7f5403642825faac8f0c67e259448bbc351c1bda
parent3c964d7328d2620eb41b9494800c3b0453e4407a (diff)
downloadlibsoup-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--ChangeLog18
-rw-r--r--libsoup/soup-queue.c15
-rw-r--r--libsoup/soup-server.c12
-rw-r--r--libsoup/soup-transfer.c204
-rw-r--r--libsoup/soup-transfer.h16
5 files changed, 165 insertions, 100 deletions
diff --git a/ChangeLog b/ChangeLog
index 88c9abae..1ddd1542 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);