+2001-06-06 Alex Graveley <alex@ximian.com>
+
+ * src/soup-core/soup-message.c (soup_message_add_header_handler):
+ implement.
+ (soup_message_add_response_code_handler): ditto.
+ (soup_message_add_body_handler): ditto.
+ (soup_message_run_handlers): uh-huh.
+ (soup_message_free): Free allocated handler info.
+
+ * src/soup-core/soup-message.h: Change SOUP_MESSAGE_PROCESS_CHUNKS
+ to SOUP_MESSAGE_OVERWRITE_CHUNKS. This will allow large files to
+ be processed using a BODY_CHUNK handler, instead of keeping
+ everything in memory.
+
+ * src/soup-core/soup-queue.c (soup_process_headers): Run PRE_BODY
+ handlers.
+ (soup_finish_read): Run POST_BODY handlers.
+ (soup_queue_read_cb): Run BODY_CHUNK handlers.
+
2001-06-06 Joe Shaw <joe@ximian.com>
* src/soup-core/soup-message.c (soup_message_set_method,
g_hash_table_destroy (req->response_headers);
}
+ g_slist_foreach (req->priv->content_handlers, (GFunc) g_free, NULL);
+ g_slist_free (req->priv->content_handlers);
+
g_free (req->priv);
g_free (req->action);
g_free (req);
void
soup_message_set_method (SoupMessage *msg, const gchar *method)
{
- g_return_if_fail(msg);
- g_return_if_fail(method);
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (method != NULL);
msg->method = method;
}
const gchar *
soup_message_get_method (SoupMessage *msg)
{
- g_return_val_if_fail(msg, NULL);
+ g_return_val_if_fail (msg != NULL, NULL);
return msg->method;
}
+typedef enum {
+ RESPONSE_HEADER_HANDLER,
+ RESPONSE_CODE_HANDLER,
+ RESPONSE_BODY_HANDLER
+} SoupHandlerKind;
+
+typedef struct {
+ SoupHandlerType type;
+ SoupHandlerFn handler_cb;
+ gpointer user_data;
+
+ SoupHandlerKind kind;
+ const gchar *header;
+ guint code;
+} SoupHandlerData;
+
+static void
+soup_message_add_handler (SoupMessage *msg,
+ SoupHandlerType type,
+ SoupHandlerFn handler_cb,
+ gpointer user_data,
+ SoupHandlerKind kind,
+ const gchar *header,
+ guint code)
+{
+ SoupHandlerData *data;
+
+ data = g_new0 (SoupHandlerData, 1);
+ data->type = type;
+ data->handler_cb = handler_cb;
+ data->user_data = user_data;
+ data->kind = kind;
+ data->header = header;
+ data->code = code;
+
+ msg->priv->content_handlers =
+ g_slist_append (msg->priv->content_handlers, data);
+}
+
void
soup_message_add_header_handler (SoupMessage *msg,
const gchar *header,
SoupHandlerFn handler_cb,
gpointer user_data)
{
- g_warning ("Not yet implemented.");
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (header != NULL);
+ g_return_if_fail (handler_cb != NULL);
+
+ soup_message_add_handler (msg,
+ type,
+ handler_cb,
+ user_data,
+ RESPONSE_HEADER_HANDLER,
+ header,
+ 0);
}
void
SoupHandlerFn handler_cb,
gpointer user_data)
{
- g_warning ("Not yet implemented.");
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (code != 0);
+ g_return_if_fail (handler_cb != NULL);
+
+ soup_message_add_handler (msg,
+ type,
+ handler_cb,
+ user_data,
+ RESPONSE_CODE_HANDLER,
+ NULL,
+ code);
}
void
SoupHandlerFn handler_cb,
gpointer user_data)
{
- g_warning ("Not yet implemented.");
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (handler_cb != NULL);
+
+ soup_message_add_handler (msg,
+ type,
+ handler_cb,
+ user_data,
+ RESPONSE_BODY_HANDLER,
+ NULL,
+ 0);
+}
+
+SoupErrorCode
+soup_message_run_handlers (SoupMessage *msg, SoupHandlerType invoke_type)
+{
+ GSList *list;
+ SoupErrorCode retval = SOUP_ERROR_NONE;
+
+ g_return_val_if_fail (msg != NULL, retval);
+
+ for (list = msg->priv->content_handlers; list; list = list->next) {
+ SoupHandlerData *data = list->data;
+
+ if (data->type != invoke_type) continue;
+
+ switch (data->kind) {
+ case RESPONSE_HEADER_HANDLER:
+ if (!soup_message_get_response_header (msg,
+ data->header))
+ continue;
+ break;
+ case RESPONSE_CODE_HANDLER:
+ if (msg->response_code != data->code) continue;
+ break;
+ }
+
+ retval = (*data->handler_cb) (msg, data->user_data);
+
+ if (retval != SOUP_ERROR_NONE) break;
+ }
+
+ return retval;
}
SOUP_HANDLER_POST_BODY
} SoupHandlerType;
-typedef SoupErrorCode SoupHandlerFn (SoupMessage *msg, gpointer user_data);
+typedef SoupErrorCode (*SoupHandlerFn) (SoupMessage *msg, gpointer user_data);
void soup_message_add_header_handler (SoupMessage *msg,
const gchar *header,
/* FIXME: None of these are implemented yet, oh well... */
typedef enum {
- SOUP_MESSAGE_FOLLOW_REDIRECT = (1 << 1),
- SOUP_MESSAGE_NO_COOKIE = (1 << 2),
- SOUP_MESSAGE_PROCESS_CHUNKS = (1 << 3)
+ SOUP_MESSAGE_FOLLOW_REDIRECT = (1 << 1),
+ SOUP_MESSAGE_NO_COOKIE = (1 << 2),
+ SOUP_MESSAGE_OVERWRITE_CHUNKS = (1 << 3)
} SoupMessageFlags;
void soup_message_set_flags (SoupMessage *msg,
gpointer digest_data;
guint msg_flags;
+
+ GSList *content_handlers;
};
typedef struct {
soup_process_headers (SoupMessage *req)
{
gchar *connection, *length, *enc;
+ SoupErrorCode err = SOUP_ERROR_MALFORMED_HEADER;
/* Handle connection persistence */
connection = g_hash_table_lookup (req->response_headers, "Connection");
}
}
+ err = soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY);
+ if (err) goto THROW_MALFORMED_HEADER;
+
return TRUE;
THROW_MALFORMED_HEADER:
- soup_message_issue_callback (req, SOUP_ERROR_MALFORMED_HEADER);
+ soup_message_issue_callback (req, err);
return FALSE;
}
{
GByteArray *arr = req->priv->recv_buf;
gint index = req->priv->header_len;
+ SoupErrorCode err;
req->response.owner = SOUP_BUFFER_SYSTEM_OWNED;
req->response.length = arr->len - index ;
req->priv->recv_buf = NULL;
req->status = SOUP_STATUS_FINISHED;
- soup_message_issue_callback (req, SOUP_ERROR_NONE);
+
+ err = soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY);
+
+ if (err)
+ soup_message_issue_callback (req, err);
+ else
+ soup_message_issue_callback (req, SOUP_ERROR_NONE);
}
static gboolean
gint index = req->priv->header_len;
GByteArray *arr = req->priv->recv_buf;
GIOError error;
+ SoupErrorCode err;
error = g_io_channel_read (iochannel,
read_buf,
return FALSE;
}
+ /* Don't call chunk handlers if we didn't actually read anything */
+ if (bytes_read != 0) {
+ err = soup_message_run_handlers (req, SOUP_HANDLER_BODY_CHUNK);
+ if (err) {
+ soup_message_issue_callback (req, err);
+ return FALSE;
+ }
+ }
+
if (bytes_read == 0) read_done = TRUE;
else if (req->priv->is_chunked) read_done = soup_read_chunk (req);
else if (req->priv->content_length==arr->len-index-4) read_done = TRUE;