From 9c1ef03ebbe9f0d12e84034bb0986ef7fccd312e Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 26 Aug 2003 15:34:16 +0000 Subject: [PATCH] Define SoupMessage signal stuff (READ_HEADERS, READ_CHUNK, READ_BODY, * libsoup/soup-message-private.h: Define SoupMessage signal stuff (READ_HEADERS, READ_CHUNK, READ_BODY, READ_ERROR, WROTE_HEADERS, WROTE_CHUNK, WROTE_BODY, WRITE_ERROR). * libsoup/soup-message.c (class_init): set up signals (requeue_read_finished): Update for changes. * libsoup/soup-message-io.c (soup_message_read): Split out parse_headers_cb from read_headers_cb. Also add a SoupDataBuffer * arg to say where to store the message body. Set up read_headers_cb, read_chunk_cb, read_body_cb, and error_cb as signal handlers. (do_read): Call r->parse_headers_cb, then emit READ_HEADERS (read_body_chunk): emit READ_CHUNK. (issue_final_callback): Set r->body. emit READ_BODY. (failed_read): emit READ_ERROR. (soup_message_read_set_callbacks): Disconnect old signal handlers, connect new ones. (soup_message_read_cancel): Disconnect signal handlers. (soup_message_write, soup_message_write_simple): Set up wrote_body_cb and error_cb as signal handlers. (do_write): emit WROTE_HEADERS and WROTE_CHUNK, even though nothing currently ever listens for them. emit WROTE_BODY when done. (failed_write): emit WRITE_ERROR * libsoup/soup-queue.c (soup_queue_parse_headers_cb, soup_queue_read_headers_cb): Split this into two unequal chunks. (read_header_cb only runs the pre-body handlers). (soup_queue_read_chunk_cb, soup_queue_read_done_cb): Update prototypes. (soup_queue_write_done_cb): Update call to soup_message_read * libsoup/soup-server.c (parse_headers_cb): Renamed from read_headers_cb (read_done_cb): Update prototype (start_request): Update soup_message_read call. --- ChangeLog | 40 +++++ libsoup/soup-marshal.list | 1 + libsoup/soup-message-io.c | 331 +++++++++++++++++++++++++++-------------- libsoup/soup-message-private.h | 107 ++++++------- libsoup/soup-message.c | 76 +++++++++- libsoup/soup-message.h | 14 +- libsoup/soup-queue.c | 90 +++++------ libsoup/soup-server.c | 61 ++++---- 8 files changed, 471 insertions(+), 249 deletions(-) diff --git a/ChangeLog b/ChangeLog index 06c4f03..b0b16e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2003-08-26 Dan Winship + + * libsoup/soup-message-private.h: Define SoupMessage signal stuff + (READ_HEADERS, READ_CHUNK, READ_BODY, READ_ERROR, WROTE_HEADERS, + WROTE_CHUNK, WROTE_BODY, WRITE_ERROR). + + * libsoup/soup-message.c (class_init): set up signals + (requeue_read_finished): Update for changes. + + * libsoup/soup-message-io.c (soup_message_read): Split out + parse_headers_cb from read_headers_cb. Also add a SoupDataBuffer * + arg to say where to store the message body. Set up + read_headers_cb, read_chunk_cb, read_body_cb, and error_cb as + signal handlers. + (do_read): Call r->parse_headers_cb, then emit READ_HEADERS + (read_body_chunk): emit READ_CHUNK. + (issue_final_callback): Set r->body. emit READ_BODY. + (failed_read): emit READ_ERROR. + (soup_message_read_set_callbacks): Disconnect old signal handlers, + connect new ones. + (soup_message_read_cancel): Disconnect signal handlers. + (soup_message_write, soup_message_write_simple): Set up + wrote_body_cb and error_cb as signal handlers. + (do_write): emit WROTE_HEADERS and WROTE_CHUNK, even though + nothing currently ever listens for them. emit WROTE_BODY when + done. + (failed_write): emit WRITE_ERROR + + * libsoup/soup-queue.c (soup_queue_parse_headers_cb, + soup_queue_read_headers_cb): Split this into two unequal chunks. + (read_header_cb only runs the pre-body handlers). + (soup_queue_read_chunk_cb, soup_queue_read_done_cb): Update + prototypes. + (soup_queue_write_done_cb): Update call to soup_message_read + + * libsoup/soup-server.c (parse_headers_cb): Renamed from + read_headers_cb + (read_done_cb): Update prototype + (start_request): Update soup_message_read call. + 2003-08-25 Dan Winship * libsoup/soup-message-io.c (soup_message_read, diff --git a/libsoup/soup-marshal.list b/libsoup/soup-marshal.list index 1b091eb..0541e0b 100644 --- a/libsoup/soup-marshal.list +++ b/libsoup/soup-marshal.list @@ -1,3 +1,4 @@ NONE:NONE NONE:INT NONE:OBJECT +NONE:POINTER diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index 7be5556..cf4057c 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -18,21 +18,24 @@ #include "soup-private.h" typedef struct { - guint idle_tag; - guint read_tag; - guint err_tag; + guint idle_tag; + guint read_tag; + guint err_tag; - GByteArray *body_buf; - GByteArray *meta_buf; + SoupDataBuffer *body; + GByteArray *body_buf; + GByteArray *meta_buf; - SoupTransferEncoding encoding; - guint read_length; + SoupTransferEncoding encoding; + guint read_length; - SoupMessageReadHeadersFn read_headers_cb; - SoupMessageReadChunkFn read_chunk_cb; - SoupMessageReadBodyFn read_body_cb; - SoupMessageReadErrorFn error_cb; - gpointer user_data; + SoupMessageParseHeadersFn parse_headers_cb; + gpointer user_data; + + guint read_headers_id; + guint read_chunk_id; + guint read_body_id; + guint error_id; } SoupMessageReadState; /* Put these around callback invocation if there is code afterward @@ -63,58 +66,97 @@ soup_message_read_cancel (SoupMessage *msg) if (r->meta_buf) g_byte_array_free (r->meta_buf, TRUE); + if (r->read_headers_id) + g_signal_handler_disconnect (msg, r->read_headers_id); + if (r->read_chunk_id) + g_signal_handler_disconnect (msg, r->read_chunk_id); + if (r->read_body_id) + g_signal_handler_disconnect (msg, r->read_body_id); + if (r->error_id) + g_signal_handler_disconnect (msg, r->error_id); + g_free (r); msg->priv->read_state = NULL; } +static inline void +update_handler (gpointer msg, const char *name, guint *id, + GCallback new_handler, gpointer user_data) +{ + if (*id) + g_signal_handler_disconnect (msg, *id); + + if (new_handler) + *id = g_signal_connect (msg, name, new_handler, user_data); + else + *id = 0; +} + void -soup_message_read_set_callbacks (SoupMessage *msg, - SoupMessageReadHeadersFn read_headers_cb, - SoupMessageReadChunkFn read_chunk_cb, - SoupMessageReadBodyFn read_body_cb, - SoupMessageReadErrorFn error_cb, - gpointer user_data) +soup_message_read_set_callbacks (SoupMessage *msg, + SoupMessageCallbackFn read_headers_cb, + SoupMessageReadChunkFn read_chunk_cb, + SoupMessageCallbackFn read_body_cb, + SoupMessageCallbackFn error_cb, + gpointer user_data) { SoupMessageReadState *r = msg->priv->read_state; - r->read_headers_cb = read_headers_cb; - r->read_chunk_cb = read_chunk_cb; - r->read_body_cb = read_body_cb; - r->error_cb = error_cb; - r->user_data = user_data; + update_handler (msg, "read_headers", &r->read_headers_id, + G_CALLBACK (read_headers_cb), user_data); + update_handler (msg, "read_chunk", &r->read_chunk_id, + G_CALLBACK (read_chunk_cb), user_data); + update_handler (msg, "read_body", &r->read_body_id, + G_CALLBACK (read_body_cb), user_data); + update_handler (msg, "read_error", &r->error_id, + G_CALLBACK (error_cb), user_data); +} + +static void +soup_message_read_finish (SoupMessage *msg, guint signal) +{ + SoupMessageReadState *r = msg->priv->read_state; + guint handler_id; + + if (signal == READ_BODY) { + handler_id = r->read_body_id; + r->read_body_id = 0; + } else { + handler_id = r->error_id; + r->error_id = 0; + } + + g_object_ref (msg); + soup_message_read_cancel (msg); + + g_signal_emit (msg, soup_message_signals[signal], 0); + if (handler_id) + g_signal_handler_disconnect (msg, handler_id); + g_object_unref (msg); } static void issue_final_callback (SoupMessage *msg) { SoupMessageReadState *r = msg->priv->read_state; - SoupMessageReadBodyFn read_body_cb = r->read_body_cb; - gpointer user_data = r->user_data; - char *body; - guint len; - if (r->body_buf) { - body = r->body_buf->data; - len = r->body_buf->len; + if (r->body && r->body_buf) { + r->body->owner = SOUP_BUFFER_SYSTEM_OWNED; + r->body->body = r->body_buf->data; + r->body->length = r->body_buf->len; g_byte_array_free (r->body_buf, FALSE); r->body_buf = NULL; - } else { - body = NULL; - len = 0; } - soup_message_read_cancel (msg); - read_body_cb (msg, body, len, user_data); + soup_message_read_finish (msg, READ_BODY); } static void failed_read (SoupSocket *sock, SoupMessage *msg) { SoupMessageReadState *r = msg->priv->read_state; - SoupMessageReadErrorFn error_cb = r->error_cb; - gpointer user_data = r->user_data; /* Closing the connection to signify EOF is valid if content * length is unknown, but only if headers have been sent. @@ -125,8 +167,7 @@ failed_read (SoupSocket *sock, SoupMessage *msg) return; } - soup_message_read_cancel (msg); - error_cb (msg, user_data); + soup_message_read_finish (msg, READ_ERROR); } static gboolean @@ -169,6 +210,7 @@ read_body_chunk (SoupMessage *msg, guint *size) char read_buf[RESPONSE_BLOCK_SIZE]; guint nread, len = sizeof (read_buf); gboolean read_to_eof = (r->encoding == SOUP_TRANSFER_UNKNOWN); + SoupDataBuffer chunk; while (read_to_eof || *size > 0) { if (!read_to_eof) @@ -182,11 +224,14 @@ read_body_chunk (SoupMessage *msg, guint *size) if (!nread) break; - if (r->read_chunk_cb) { - SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK; - r->read_chunk_cb (msg, read_buf, nread, r->user_data); - SOUP_MESSAGE_READ_RETURN_VAL_IF_CANCELLED (FALSE); - } + chunk.owner = SOUP_BUFFER_STATIC; + chunk.body = read_buf; + chunk.length = nread; + + SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK; + g_signal_emit (msg, soup_message_signals[READ_CHUNK], + 0, &chunk); + SOUP_MESSAGE_READ_RETURN_VAL_IF_CANCELLED (FALSE); if (r->body_buf) g_byte_array_append (r->body_buf, read_buf, nread); @@ -220,6 +265,7 @@ static void do_read (SoupSocket *sock, SoupMessage *msg) { SoupMessageReadState *r = msg->priv->read_state; + SoupKnownErrorCode err; while (1) { switch (msg->priv->status) { @@ -229,18 +275,26 @@ do_read (SoupSocket *sock, SoupMessage *msg) return; r->meta_buf->len -= SOUP_TRANSFER_DOUBLE_EOL_LEN; - if (r->read_headers_cb) { - SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK; - r->read_headers_cb (msg, - r->meta_buf->data, - r->meta_buf->len, - &r->encoding, - &r->read_length, - r->user_data); - SOUP_MESSAGE_READ_RETURN_IF_CANCELLED; - } + + SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK; + err = r->parse_headers_cb (msg, + r->meta_buf->data, + r->meta_buf->len, + &r->encoding, + &r->read_length, + r->user_data); + SOUP_MESSAGE_READ_RETURN_IF_CANCELLED; g_byte_array_set_size (r->meta_buf, 0); + if (!SOUP_ERROR_IS_SUCCESSFUL (err)) { + soup_message_set_error (msg, err); + goto done; + } + + SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK; + g_signal_emit (msg, soup_message_signals[READ_HEADERS], 0); + SOUP_MESSAGE_READ_RETURN_IF_CANCELLED; + switch (r->encoding) { case SOUP_TRANSFER_UNKNOWN: case SOUP_TRANSFER_CONTENT_LENGTH: @@ -332,30 +386,51 @@ idle_read (gpointer user_data) } void -soup_message_read (SoupMessage *msg, - SoupMessageReadHeadersFn read_headers_cb, - SoupMessageReadChunkFn read_chunk_cb, - SoupMessageReadBodyFn read_body_cb, - SoupMessageReadErrorFn error_cb, - gpointer user_data) +soup_message_read (SoupMessage *msg, + SoupDataBuffer *body, + SoupMessageParseHeadersFn parse_headers_cb, + SoupMessageCallbackFn read_headers_cb, + SoupMessageReadChunkFn read_chunk_cb, + SoupMessageCallbackFn read_body_cb, + SoupMessageCallbackFn error_cb, + gpointer user_data) { SoupMessageReadState *r; g_return_if_fail (SOUP_IS_MESSAGE (msg)); g_return_if_fail (msg->priv->socket != NULL); - g_return_if_fail (read_body_cb && error_cb); + g_return_if_fail (parse_headers_cb && read_body_cb && error_cb); r = g_new0 (SoupMessageReadState, 1); - r->read_headers_cb = read_headers_cb; - r->read_chunk_cb = read_chunk_cb; - r->read_body_cb = read_body_cb; - r->error_cb = error_cb; + r->parse_headers_cb = parse_headers_cb; + + if (read_headers_cb) { + r->read_headers_id = + g_signal_connect (msg, "read_headers", + G_CALLBACK (read_headers_cb), + user_data); + } + if (read_chunk_cb) { + r->read_chunk_id = + g_signal_connect (msg, "read_chunk", + G_CALLBACK (read_chunk_cb), + user_data); + } + r->read_body_id = g_signal_connect (msg, "read_body", + G_CALLBACK (read_body_cb), + user_data); + r->error_id = g_signal_connect (msg, "read_error", + G_CALLBACK (error_cb), + user_data); r->user_data = user_data; + r->encoding = SOUP_TRANSFER_UNKNOWN; r->meta_buf = g_byte_array_new (); - if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS)) + if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS)) { + r->body = body; r->body_buf = g_byte_array_new (); + } r->read_tag = g_signal_connect (msg->priv->socket, "readable", G_CALLBACK (do_read), msg); @@ -381,11 +456,12 @@ typedef struct { SoupDataBuffer chunk; guint nwrote; - SoupMessageWriteGetHeaderFn get_header_cb; - SoupMessageWriteGetChunkFn get_chunk_cb; - SoupMessageWriteDoneFn write_done_cb; - SoupMessageWriteErrorFn error_cb; - gpointer user_data; + SoupMessageGetHeadersFn get_header_cb; + SoupMessageGetChunkFn get_chunk_cb; + gpointer user_data; + + guint wrote_body_id; + guint error_id; } SoupMessageWriteState; /* Put these around callback invocation if there is code afterward @@ -409,6 +485,11 @@ soup_message_write_cancel (SoupMessage *msg) if (w->write_tag) g_signal_handler_disconnect (msg->priv->socket, w->write_tag); + if (w->wrote_body_id) + g_signal_handler_disconnect (msg, w->wrote_body_id); + if (w->error_id) + g_signal_handler_disconnect (msg, w->error_id); + g_string_free (w->buf, TRUE); g_free (w); @@ -417,14 +498,32 @@ soup_message_write_cancel (SoupMessage *msg) } static void -failed_write (SoupSocket *sock, SoupMessage *msg) +soup_message_write_finish (SoupMessage *msg, guint signal) { SoupMessageWriteState *w = msg->priv->write_state; - SoupMessageWriteErrorFn error_cb = w->error_cb; - gpointer user_data = w->user_data; + guint handler_id; + + if (signal == WROTE_BODY) { + handler_id = w->wrote_body_id; + w->wrote_body_id = 0; + } else { + handler_id = w->error_id; + w->error_id = 0; + } + g_object_ref (msg); soup_message_write_cancel (msg); - error_cb (msg, user_data); + + g_signal_emit (msg, soup_message_signals[signal], 0); + if (handler_id) + g_signal_handler_disconnect (msg, handler_id); + g_object_unref (msg); +} + +static void +failed_write (SoupSocket *sock, SoupMessage *msg) +{ + soup_message_write_finish (msg, WRITE_ERROR); } static gboolean @@ -461,15 +560,13 @@ static void do_write (SoupSocket *sock, SoupMessage *msg) { SoupMessageWriteState *w = msg->priv->write_state; - SoupMessageWriteDoneFn write_done_cb = w->write_done_cb; - gpointer user_data = w->user_data; while (1) { switch (msg->priv->status) { case SOUP_MESSAGE_STATUS_WRITING_HEADERS: if (w->get_header_cb) { SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK; - w->get_header_cb (msg, w->buf, user_data); + w->get_header_cb (msg, w->buf, w->user_data); SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED; w->get_header_cb = NULL; @@ -479,16 +576,21 @@ do_write (SoupSocket *sock, SoupMessage *msg) if (!write_data (msg, w->buf->str, w->buf->len)) return; + SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK; + g_signal_emit (msg, soup_message_signals[WROTE_HEADERS], 0); + SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED; + g_string_truncate (w->buf, 0); w->nwrote = 0; if (w->encoding == SOUP_TRANSFER_CHUNKED) { msg->priv->status = SOUP_MESSAGE_STATUS_WRITING_CHUNK_SIZE; - } else { - msg->priv->status = - SOUP_MESSAGE_STATUS_WRITING_BODY; + break; } - break; + + msg->priv->status = + SOUP_MESSAGE_STATUS_WRITING_BODY; + /* fall through */ case SOUP_MESSAGE_STATUS_WRITING_BODY: if (!write_data (msg, w->body->body, @@ -504,7 +606,7 @@ do_write (SoupSocket *sock, SoupMessage *msg) SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK; got_chunk = w->get_chunk_cb (msg, &w->chunk, - user_data); + w->user_data); SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED; if (!got_chunk) { @@ -538,6 +640,10 @@ do_write (SoupSocket *sock, SoupMessage *msg) g_free (w->chunk.body); memset (&w->chunk, 0, sizeof (SoupDataBuffer)); + SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK; + g_signal_emit (msg, soup_message_signals[WROTE_CHUNK], 0); + SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED; + w->nwrote = 0; msg->priv->status = SOUP_MESSAGE_STATUS_WRITING_CHUNK_END; /* fall through */ @@ -572,8 +678,7 @@ do_write (SoupSocket *sock, SoupMessage *msg) done: msg->priv->status = SOUP_MESSAGE_STATUS_FINISHED_WRITING; - soup_message_write_cancel (msg); - write_done_cb (msg, user_data); + soup_message_write_finish (msg, WROTE_BODY); } static gboolean @@ -588,12 +693,13 @@ idle_write (gpointer user_data) } static SoupMessageWriteState * -create_writer (SoupMessage *msg, - SoupTransferEncoding encoding, - SoupMessageWriteGetHeaderFn get_header_cb, - SoupMessageWriteDoneFn write_done_cb, - SoupMessageWriteErrorFn error_cb, - gpointer user_data) +create_writer (SoupMessage *msg, + SoupTransferEncoding encoding, + SoupMessageGetHeadersFn get_header_cb, + SoupMessageGetChunkFn get_chunk_cb, + SoupMessageCallbackFn wrote_body_cb, + SoupMessageCallbackFn error_cb, + gpointer user_data) { SoupMessageWriteState *w; @@ -601,10 +707,16 @@ create_writer (SoupMessage *msg, w->encoding = encoding; w->buf = g_string_new (NULL); w->get_header_cb = get_header_cb; - w->write_done_cb = write_done_cb; - w->error_cb = error_cb; + w->get_chunk_cb = get_chunk_cb; w->user_data = user_data; + w->wrote_body_id = g_signal_connect (msg, "wrote_body", + G_CALLBACK (wrote_body_cb), + user_data); + w->error_id = g_signal_connect (msg, "write_error", + G_CALLBACK (error_cb), + user_data); + w->write_tag = g_signal_connect (msg->priv->socket, "writable", G_CALLBACK (do_write), msg); @@ -621,36 +733,35 @@ create_writer (SoupMessage *msg, } void -soup_message_write_simple (SoupMessage *msg, - const SoupDataBuffer *body, - SoupMessageWriteGetHeaderFn get_header_cb, - SoupMessageWriteDoneFn write_done_cb, - SoupMessageWriteErrorFn error_cb, - gpointer user_data) +soup_message_write_simple (SoupMessage *msg, + const SoupDataBuffer *body, + SoupMessageGetHeadersFn get_header_cb, + SoupMessageCallbackFn wrote_body_cb, + SoupMessageCallbackFn error_cb, + gpointer user_data) { SoupMessageWriteState *w; w = create_writer (msg, SOUP_TRANSFER_CONTENT_LENGTH, - get_header_cb, write_done_cb, + get_header_cb, NULL, wrote_body_cb, error_cb, user_data); w->body = body; } void -soup_message_write (SoupMessage *msg, - SoupTransferEncoding encoding, - SoupMessageWriteGetHeaderFn get_header_cb, - SoupMessageWriteGetChunkFn get_chunk_cb, - SoupMessageWriteDoneFn write_done_cb, - SoupMessageWriteErrorFn error_cb, - gpointer user_data) +soup_message_write (SoupMessage *msg, + SoupTransferEncoding encoding, + SoupMessageGetHeadersFn get_header_cb, + SoupMessageGetChunkFn get_chunk_cb, + SoupMessageCallbackFn wrote_body_cb, + SoupMessageCallbackFn error_cb, + gpointer user_data) { SoupMessageWriteState *w; - w = create_writer (msg, encoding, get_header_cb, - write_done_cb, error_cb, user_data); - w->get_chunk_cb = get_chunk_cb; + w = create_writer (msg, encoding, get_header_cb, get_chunk_cb, + wrote_body_cb, error_cb, user_data); } void diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h index ba56a83..322a40e 100644 --- a/libsoup/soup-message-private.h +++ b/libsoup/soup-message-private.h @@ -9,6 +9,21 @@ #include #include +enum { + WROTE_HEADERS, + WROTE_CHUNK, + WROTE_BODY, + WRITE_ERROR, + + READ_HEADERS, + READ_CHUNK, + READ_BODY, + READ_ERROR, + + LAST_SIGNAL +}; +extern guint soup_message_signals[LAST_SIGNAL]; + typedef enum { SOUP_MESSAGE_STATUS_IDLE, SOUP_MESSAGE_STATUS_QUEUED, @@ -77,68 +92,54 @@ SoupConnection *soup_message_get_connection (SoupMessage *msg); SoupSocket *soup_message_get_socket (SoupMessage *msg); -typedef void (*SoupMessageReadHeadersFn) (SoupMessage *msg, - char *headers, - guint header_len, - SoupTransferEncoding *encoding, - int *content_len, - gpointer user_data); - -typedef void (*SoupMessageReadChunkFn) (SoupMessage *msg, - const char *chunk, - guint len, - gpointer user_data); - -typedef void (*SoupMessageReadBodyFn) (SoupMessage *msg, - char *body, - guint len, - gpointer user_data); - -typedef void (*SoupMessageReadErrorFn) (SoupMessage *msg, - gpointer user_data); - - -void soup_message_read (SoupMessage *msg, - SoupMessageReadHeadersFn read_headers_cb, - SoupMessageReadChunkFn read_chunk_cb, - SoupMessageReadBodyFn read_body_cb, - SoupMessageReadErrorFn error_cb, - gpointer user_data); -void soup_message_read_set_callbacks (SoupMessage *msg, - SoupMessageReadHeadersFn read_headers_cb, - SoupMessageReadChunkFn read_chunk_cb, - SoupMessageReadBodyFn read_body_cb, - SoupMessageReadErrorFn error_cb, - gpointer user_data); +typedef SoupKnownErrorCode + (*SoupMessageParseHeadersFn) (SoupMessage *msg, + char *headers, + guint header_len, + SoupTransferEncoding *encoding, + guint *content_len, + gpointer user_data); + +typedef void (*SoupMessageReadChunkFn) (SoupMessage *msg, + SoupDataBuffer *chunk, + gpointer user_data); + +void soup_message_read (SoupMessage *msg, + SoupDataBuffer *body, + SoupMessageParseHeadersFn parse_headers_cb, + SoupCallbackFn read_headers_cb, + SoupMessageReadChunkFn read_chunk_cb, + SoupCallbackFn read_body_cb, + SoupCallbackFn error_cb, + gpointer user_data); +void soup_message_read_set_callbacks (SoupMessage *msg, + SoupCallbackFn read_headers_cb, + SoupMessageReadChunkFn read_chunk_cb, + SoupCallbackFn read_body_cb, + SoupCallbackFn error_cb, + gpointer user_data); void soup_message_read_cancel (SoupMessage *msg); -typedef void (*SoupMessageWriteGetHeaderFn) (SoupMessage *msg, - GString *out_hdr, - gpointer user_data); - -typedef gboolean (*SoupMessageWriteGetChunkFn) (SoupMessage *msg, - SoupDataBuffer *out_next, - gpointer user_data); - -typedef void (*SoupMessageWriteDoneFn) (SoupMessage *msg, - gpointer user_data); - -typedef void (*SoupMessageWriteErrorFn) (SoupMessage *msg, - gpointer user_data); +typedef void (*SoupMessageGetHeadersFn) (SoupMessage *msg, + GString *out_hdr, + gpointer user_data); +typedef gboolean (*SoupMessageGetChunkFn) (SoupMessage *msg, + SoupDataBuffer *chunk, + gpointer user_data); void soup_message_write (SoupMessage *msg, SoupTransferEncoding encoding, - SoupMessageWriteGetHeaderFn get_header_cb, - SoupMessageWriteGetChunkFn get_chunk_cb, - SoupMessageWriteDoneFn write_done_cb, - SoupMessageWriteErrorFn error_cb, + SoupMessageGetHeadersFn get_header_cb, + SoupMessageGetChunkFn get_chunk_cb, + SoupCallbackFn write_done_cb, + SoupCallbackFn error_cb, gpointer user_data); void soup_message_write_simple (SoupMessage *msg, const SoupDataBuffer *body, - SoupMessageWriteGetHeaderFn get_header_cb, - SoupMessageWriteDoneFn write_done_cb, - SoupMessageWriteErrorFn error_cb, + SoupMessageGetHeadersFn get_header_cb, + SoupCallbackFn write_done_cb, + SoupCallbackFn error_cb, gpointer user_data); void soup_message_write_cancel (SoupMessage *msg); diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c index 2d6ef30..87868c7 100644 --- a/libsoup/soup-message.c +++ b/libsoup/soup-message.c @@ -9,6 +9,7 @@ #include "soup-auth.h" #include "soup-error.h" +#include "soup-marshal.h" #include "soup-message.h" #include "soup-message-private.h" #include "soup-misc.h" @@ -19,6 +20,8 @@ #define PARENT_TYPE G_TYPE_OBJECT static GObjectClass *parent_class; +guint soup_message_signals[LAST_SIGNAL] = { 0 }; + static void cleanup_message (SoupMessage *req); static void @@ -77,6 +80,74 @@ class_init (GObjectClass *object_class) /* virtual method override */ object_class->finalize = finalize; + + /* signals */ + soup_message_signals[WROTE_HEADERS] = + g_signal_new ("wrote_headers", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, wrote_headers), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + soup_message_signals[WROTE_CHUNK] = + g_signal_new ("wrote_chunk", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + soup_message_signals[WROTE_BODY] = + g_signal_new ("wrote_body", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, wrote_body), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + soup_message_signals[WRITE_ERROR] = + g_signal_new ("write_error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, write_error), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + + soup_message_signals[READ_HEADERS] = + g_signal_new ("read_headers", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, read_headers), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + soup_message_signals[READ_CHUNK] = + g_signal_new ("read_chunk", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, read_chunk), + NULL, NULL, + soup_marshal_NONE__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + soup_message_signals[READ_BODY] = + g_signal_new ("read_body", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, read_body), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); + soup_message_signals[READ_ERROR] = + g_signal_new ("read_error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SoupMessageClass, read_error), + NULL, NULL, + soup_marshal_NONE__NONE, + G_TYPE_NONE, 0); } SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE) @@ -489,13 +560,10 @@ requeue_read_error (SoupMessage *msg, gpointer user_data) } static void -requeue_read_finished (SoupMessage *msg, char *body, guint len, - gpointer user_data) +requeue_read_finished (SoupMessage *msg, gpointer user_data) { SoupConnection *conn = msg->priv->connection; - g_free (body); - g_object_ref (conn); soup_message_set_connection (msg, NULL); diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h index e069dfa..66959d6 100644 --- a/libsoup/soup-message.h +++ b/libsoup/soup-message.h @@ -59,6 +59,16 @@ typedef struct { typedef struct { GObjectClass parent_class; + /* signals */ + void (*wrote_headers) (SoupMessage *msg); + void (*wrote_chunk) (SoupMessage *msg); + void (*wrote_body) (SoupMessage *msg); + void (*write_error) (SoupMessage *msg); + + void (*read_headers) (SoupMessage *msg); + void (*read_chunk) (SoupMessage *msg, SoupDataBuffer *chunk); + void (*read_body) (SoupMessage *msg); + void (*read_error) (SoupMessage *msg); } SoupMessageClass; GType soup_message_get_type (void); @@ -69,7 +79,9 @@ GType soup_message_get_type (void); msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL && \ msg->errorclass != SOUP_ERROR_CLASS_UNKNOWN) -typedef void (*SoupCallbackFn) (SoupMessage *req, gpointer user_data); +typedef void (*SoupMessageCallbackFn) (SoupMessage *req, gpointer user_data); +/* Backward compat; FIXME */ +typedef SoupMessageCallbackFn SoupCallbackFn; SoupMessage *soup_message_new (const char *method, const char *uri); diff --git a/libsoup/soup-queue.c b/libsoup/soup-queue.c index 0928a73..da924e2 100644 --- a/libsoup/soup-queue.c +++ b/libsoup/soup-queue.c @@ -109,10 +109,12 @@ soup_queue_error_cb (SoupMessage *req, gpointer user_data) } } -static void -soup_queue_read_headers_cb (SoupMessage *req, char *headers, guint headers_len, - SoupTransferEncoding *encoding, int *content_len, - gpointer user_data) +static SoupKnownErrorCode +soup_queue_parse_headers_cb (SoupMessage *req, + char *headers, guint headers_len, + SoupTransferEncoding *encoding, + guint *content_len, + gpointer user_data) { const char *length, *enc; SoupHttpVersion version; @@ -123,13 +125,8 @@ soup_queue_read_headers_cb (SoupMessage *req, char *headers, guint headers_len, req->response_headers, &version, &req->errorcode, - (char **) &req->errorphrase)) { - soup_message_set_error_full (req, - SOUP_ERROR_MALFORMED, - "Unable to parse response " - "headers"); - goto THROW_MALFORMED_HEADER; - } + (char **) &req->errorphrase)) + return SOUP_ERROR_MALFORMED; meth_id = soup_method_get_id (req->method); resp_hdrs = req->response_headers; @@ -153,7 +150,7 @@ soup_queue_read_headers_cb (SoupMessage *req, char *headers, guint headers_len, req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) { *encoding = SOUP_TRANSFER_CONTENT_LENGTH; *content_len = 0; - goto SUCCESS_CONTINUE; + return SOUP_ERROR_OK; } /* @@ -162,16 +159,11 @@ soup_queue_read_headers_cb (SoupMessage *req, char *headers, guint headers_len, */ enc = soup_message_get_header (resp_hdrs, "Transfer-Encoding"); if (enc) { - if (g_strcasecmp (enc, "chunked") == 0) + if (g_strcasecmp (enc, "chunked") == 0) { *encoding = SOUP_TRANSFER_CHUNKED; - else { - soup_message_set_error_full ( - req, - SOUP_ERROR_MALFORMED, - "Unknown Response Encoding"); - goto THROW_MALFORMED_HEADER; - } - goto SUCCESS_CONTINUE; + return SOUP_ERROR_OK; + } else + return SOUP_ERROR_MALFORMED; } /* @@ -179,55 +171,48 @@ soup_queue_read_headers_cb (SoupMessage *req, char *headers, guint headers_len, */ length = soup_message_get_header (resp_hdrs, "Content-Length"); if (length) { + int len; + *encoding = SOUP_TRANSFER_CONTENT_LENGTH; - *content_len = atoi (length); - if (*content_len < 0) { - soup_message_set_error_full (req, - SOUP_ERROR_MALFORMED, - "Invalid Content-Length"); - goto THROW_MALFORMED_HEADER; - } - goto SUCCESS_CONTINUE; + len = atoi (length); + if (len < 0) + return SOUP_ERROR_MALFORMED; + else + *content_len = len; } - SUCCESS_CONTINUE: - soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY); - return; + return SOUP_ERROR_OK; +} - THROW_MALFORMED_HEADER: - soup_message_disconnect (req); - soup_message_issue_callback (req); - return; +static void +soup_queue_read_headers_cb (SoupMessage *req, gpointer user_data) +{ + soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY); } static void -soup_queue_read_chunk_cb (SoupMessage *req, const char *chunk, guint len, +soup_queue_read_chunk_cb (SoupMessage *req, SoupDataBuffer *chunk, gpointer user_data) { - req->response.owner = SOUP_BUFFER_STATIC; - req->response.length = len; - req->response.body = (char *)chunk; + /* FIXME? */ + memcpy (&req->response, chunk, sizeof (req->response)); soup_message_run_handlers (req, SOUP_HANDLER_BODY_CHUNK); - - return; } static void -soup_queue_read_done_cb (SoupMessage *req, char *body, guint len, - gpointer user_data) +soup_queue_read_done_cb (SoupMessage *req, gpointer user_data) { - if (soup_message_is_keepalive (req)) - soup_connection_mark_old (soup_message_get_connection (req)); + SoupConnection *conn = soup_message_get_connection (req); + + if (soup_message_is_keepalive (req) && conn) + soup_connection_mark_old (conn); else soup_message_disconnect (req); - req->response.owner = SOUP_BUFFER_SYSTEM_OWNED; - req->response.length = len; - req->response.body = body; - if (req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) { - soup_message_read (req, + soup_message_read (req, &req->response, + soup_queue_parse_headers_cb, soup_queue_read_headers_cb, soup_queue_read_chunk_cb, soup_queue_read_done_cb, @@ -407,7 +392,8 @@ soup_queue_get_request_header_cb (SoupMessage *req, GString *header, static void soup_queue_write_done_cb (SoupMessage *req, gpointer user_data) { - soup_message_read (req, + soup_message_read (req, &req->response, + soup_queue_parse_headers_cb, soup_queue_read_headers_cb, soup_queue_read_chunk_cb, soup_queue_read_done_cb, diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c index 6a46a71..de35f99 100644 --- a/libsoup/soup-server.c +++ b/libsoup/soup-server.c @@ -252,7 +252,6 @@ issue_bad_request (SoupMessage *msg) { soup_message_read_cancel (msg); - set_response_error (msg, SOUP_ERROR_BAD_REQUEST, NULL, NULL); soup_message_add_header (msg->response_headers, "Connection", "close"); soup_server_message_finish (SOUP_SERVER_MESSAGE (msg)); @@ -263,10 +262,10 @@ issue_bad_request (SoupMessage *msg) NULL); } -static void -read_headers_cb (SoupMessage *msg, char *headers, guint headers_len, - SoupTransferEncoding *encoding, int *content_len, - gpointer user_data) +static SoupKnownErrorCode +parse_headers_cb (SoupMessage *msg, char *headers, guint headers_len, + SoupTransferEncoding *encoding, guint *content_len, + gpointer user_data) { SoupContext *ctx; char *req_path = NULL, *url; @@ -278,7 +277,7 @@ read_headers_cb (SoupMessage *msg, char *headers, guint headers_len, (char **) &msg->method, &req_path, &msg->priv->http_version)) - goto THROW_MALFORMED_HEADER; + return SOUP_ERROR_BAD_REQUEST; /* Handle request body encoding */ length = soup_message_get_header (msg->request_headers, @@ -291,13 +290,18 @@ read_headers_cb (SoupMessage *msg, char *headers, guint headers_len, *encoding = SOUP_TRANSFER_CHUNKED; else { g_warning ("Unknown encoding type in HTTP request."); - goto THROW_MALFORMED_HEADER; + g_free (req_path); + return SOUP_ERROR_NOT_IMPLEMENTED; } } else if (length) { + int len; *encoding = SOUP_TRANSFER_CONTENT_LENGTH; - *content_len = atoi (length); - if (*content_len < 0) - goto THROW_MALFORMED_HEADER; + len = atoi (length); + if (len < 0) { + g_free (req_path); + return SOUP_ERROR_BAD_REQUEST; + } + *content_len = len; } else { *encoding = SOUP_TRANSFER_CONTENT_LENGTH; *content_len = 0; @@ -315,8 +319,10 @@ read_headers_cb (SoupMessage *msg, char *headers, guint headers_len, if (absolute) { url = g_strdup (req_path); soup_uri_free (absolute); - } else - goto THROW_MALFORMED_HEADER; + } else { + g_free (req_path); + return SOUP_ERROR_BAD_REQUEST; + } } else if (req_host) { url = g_strdup_printf ("%s://%s:%d%s", server->priv->proto == SOUP_PROTOCOL_HTTPS ? "https" : "http", @@ -332,26 +338,22 @@ read_headers_cb (SoupMessage *msg, char *headers, guint headers_len, server->priv->proto == SOUP_PROTOCOL_HTTPS ? "https" : "http", host, server->priv->port, req_path); - } else - goto THROW_MALFORMED_HEADER; + } else { + g_free (req_path); + return SOUP_ERROR_BAD_REQUEST; + } ctx = soup_context_get (url); g_free (url); + g_free (req_path); if (!ctx) - goto THROW_MALFORMED_HEADER; + return SOUP_ERROR_BAD_REQUEST; soup_message_set_context (msg, ctx); g_object_unref (ctx); - g_free (req_path); - - return; - - THROW_MALFORMED_HEADER: - g_free (req_path); - - issue_bad_request(msg); + return SOUP_ERROR_OK; } static void @@ -452,14 +454,15 @@ get_chunk_cb (SoupMessage *msg, SoupDataBuffer *out_next, gpointer user_data) } static void -read_done_cb (SoupMessage *req, char *body, guint len, gpointer user_data) +read_done_cb (SoupMessage *req, gpointer user_data) { SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (req); SoupTransferEncoding encoding; - req->request.owner = SOUP_BUFFER_SYSTEM_OWNED; - req->request.body = body; - req->request.length = len; + if (req->errorcode && !SOUP_ERROR_IS_SUCCESSFUL (req->errorcode)) { + issue_bad_request (req); + return; + } call_handler (req); @@ -486,8 +489,8 @@ start_request (SoupServer *server, SoupSocket *server_sock) /* Listen for another request on this connection */ msg = (SoupMessage *)soup_server_message_new (server, server_sock); - soup_message_read (msg, read_headers_cb, NULL, - read_done_cb, error_cb, NULL); + soup_message_read (msg, &msg->request, parse_headers_cb, + NULL, NULL, read_done_cb, error_cb, NULL); } static void -- 2.7.4