New file containing SoupMessagePrivate and some other
authorDan Winship <danw@src.gnome.org>
Fri, 22 Aug 2003 18:49:02 +0000 (18:49 +0000)
committerDan Winship <danw@src.gnome.org>
Fri, 22 Aug 2003 18:49:02 +0000 (18:49 +0000)
* libsoup/soup-message-private.h: New file containing
SoupMessagePrivate and some other soup-message-internal
types/functions. Also includes the new, expanded SoupMessageStatus
enum.

* libsoup/soup-message-io.c: Replaces what used to be in
soup-transfer, but now all the interfaces take SoupMessages
instead of SoupReader/SoupWriter and deal with maintaining
msg->priv->{read,write}_state themselves. Fixes up all the
refcounting madness.

* libsoup/soup-message-handlers.c: Move the handler code here,
mostly unchanged. (But rename SoupHandlerType to SoupHandlerPhase
to make the distinction from SoupHandlerKind clearer.)

* libsoup/soup-message.c: Update for soup-message-io and new
SoupMessageStatus values. Remove handler code.
(soup_message_cleanup): Remove the hack to try to preserve the
connection if the message gets cleaned up before it finishes
reading. soup_message_requeue handles this in the requeuing case,
and there's no especially compelling reason to bother doing it in
any other case. (And the soup-message-io api doesn't support
having a read operation that's not connected to any message.)

* libsoup/soup-private.h: remove SoupMessagePrivate

* libsoup/soup-queue.c: Update for soup-message-io and new
SoupMessageStatus values.

* libsoup/soup-server-message.c: Likewise

* libsoup/soup-server.c: Likewise

* libsoup/soup-transfer.c: Gone (yay)

* libsoup/Makefile.am (libsoup_2_2_la_SOURCES): update

14 files changed:
ChangeLog
libsoup/Makefile.am
libsoup/soup-message-handlers.c [new file with mode: 0644]
libsoup/soup-message-io.c [new file with mode: 0644]
libsoup/soup-message-private.h [new file with mode: 0644]
libsoup/soup-message.c
libsoup/soup-message.h
libsoup/soup-private.h
libsoup/soup-queue.c
libsoup/soup-server-message.c
libsoup/soup-server-message.h
libsoup/soup-server.c
libsoup/soup-transfer.c [deleted file]
libsoup/soup-transfer.h [deleted file]

index 147eddb..3e35433 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2003-08-22  Dan Winship  <danw@ximian.com>
+
+       * libsoup/soup-message-private.h: New file containing
+       SoupMessagePrivate and some other soup-message-internal
+       types/functions. Also includes the new, expanded SoupMessageStatus
+       enum.
+
+       * libsoup/soup-message-io.c: Replaces what used to be in
+       soup-transfer, but now all the interfaces take SoupMessages
+       instead of SoupReader/SoupWriter and deal with maintaining
+       msg->priv->{read,write}_state themselves. Fixes up all the
+       refcounting madness.
+
+       * libsoup/soup-message-handlers.c: Move the handler code here,
+       mostly unchanged. (But rename SoupHandlerType to SoupHandlerPhase
+       to make the distinction from SoupHandlerKind clearer.)
+
+       * libsoup/soup-message.c: Update for soup-message-io and new
+       SoupMessageStatus values. Remove handler code.
+       (soup_message_cleanup): Remove the hack to try to preserve the
+       connection if the message gets cleaned up before it finishes
+       reading. soup_message_requeue handles this in the requeuing case,
+       and there's no especially compelling reason to bother doing it in
+       any other case. (And the soup-message-io api doesn't support
+       having a read operation that's not connected to any message.)
+
+       * libsoup/soup-private.h: remove SoupMessagePrivate
+
+       * libsoup/soup-queue.c: Update for soup-message-io and new
+       SoupMessageStatus values.
+
+       * libsoup/soup-server-message.c: Likewise
+
+       * libsoup/soup-server.c: Likewise
+
+       * libsoup/soup-transfer.c: Gone (yay)
+
+       * libsoup/Makefile.am (libsoup_2_2_la_SOURCES): update
+
 2003-08-20  Dan Winship  <danw@ximian.com>
 
        * libsoup/soup-message.c: Make this a GObject. (Note that since
index 4dbb738..741336a 100644 (file)
@@ -73,7 +73,10 @@ libsoup_2_2_la_SOURCES =     \
        soup-gnutls.h           \
        soup-gnutls.c           \
        soup-headers.c          \
+       soup-message-private.h  \
        soup-message.c          \
+       soup-message-handlers.c \
+       soup-message-io.c       \
        soup-method.c           \
        soup-misc.c             \
        soup-private.h          \
@@ -85,8 +88,6 @@ libsoup_2_2_la_SOURCES =      \
        soup-socket.c           \
        soup-ssl.h              \
        soup-ssl.c              \
-       soup-transfer.h         \
-       soup-transfer.c         \
        soup-uri.c
 
 EXTRA_DIST= soup-marshal.list
diff --git a/libsoup/soup-message-handlers.c b/libsoup/soup-message-handlers.c
new file mode 100644 (file)
index 0000000..8ae6be8
--- /dev/null
@@ -0,0 +1,324 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-message-handlers.c: HTTP response handlers
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "soup-message.h"
+#include "soup-message-private.h"
+#include "soup-misc.h"
+#include "soup-private.h"
+
+typedef enum {
+       SOUP_HANDLER_HEADER = 1,
+       SOUP_HANDLER_ERROR_CODE,
+       SOUP_HANDLER_ERROR_CLASS
+} SoupHandlerKind;
+
+typedef struct {
+       SoupHandlerPhase  phase;
+       SoupCallbackFn    handler_cb;
+       gpointer          user_data;
+
+       SoupHandlerKind   kind;
+       union {
+               guint           errorcode;
+               SoupErrorClass  errorclass;
+               const char     *header;
+       } data;
+} SoupHandlerData;
+
+static void redirect_handler (SoupMessage *msg, gpointer user_data);
+static void authorize_handler (SoupMessage *msg, gpointer proxy);
+
+static SoupHandlerData global_handlers [] = {
+       /* Handle redirect response codes. */
+       {
+               SOUP_HANDLER_PRE_BODY,
+               redirect_handler,
+               NULL,
+               SOUP_HANDLER_ERROR_CLASS,
+               { SOUP_ERROR_CLASS_REDIRECT }
+       },
+
+       /* Handle authorization. */
+       {
+               SOUP_HANDLER_PRE_BODY,
+               authorize_handler,
+               GINT_TO_POINTER (FALSE),
+               SOUP_HANDLER_ERROR_CODE,
+               { 401 }
+       },
+
+       /* Handle proxy authorization. */
+       {
+               SOUP_HANDLER_PRE_BODY,
+               authorize_handler,
+               GINT_TO_POINTER (TRUE),
+               SOUP_HANDLER_ERROR_CODE,
+               { 407 }
+       },
+
+       { 0 }
+};
+
+static inline void
+run_handler (SoupMessage     *msg,
+            SoupHandlerPhase invoke_phase,
+            SoupHandlerData *data)
+{
+       if (data->phase != invoke_phase)
+               return;
+
+       switch (data->kind) {
+       case SOUP_HANDLER_HEADER:
+               if (!soup_message_get_header (msg->response_headers,
+                                             data->data.header))
+                       return;
+               break;
+       case SOUP_HANDLER_ERROR_CODE:
+               if (msg->errorcode != data->data.errorcode)
+                       return;
+               break;
+       case SOUP_HANDLER_ERROR_CLASS:
+               if (msg->errorclass != data->data.errorclass)
+                       return;
+               break;
+       default:
+               break;
+       }
+
+       (*data->handler_cb) (msg, data->user_data);
+}
+
+/*
+ * Run each handler with matching criteria (first per-message then
+ * global handlers). If a handler requeues a message, we stop
+ * processing and terminate the current request.
+ *
+ * After running all handlers, if there is an error set or the invoke
+ * phase was post_body, issue the final callback.
+ *
+ * FIXME: If the errorcode is changed by a handler, we should restart
+ * the processing.
+ */
+void
+soup_message_run_handlers (SoupMessage *msg, SoupHandlerPhase invoke_phase)
+{
+       GSList *list;
+       SoupHandlerData *data;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+       for (list = msg->priv->content_handlers; list; list = list->next) {
+               run_handler (msg, invoke_phase, list->data);
+
+               if (SOUP_MESSAGE_IS_STARTING (msg))
+                       return;
+       }
+
+       for (data = global_handlers; data->phase; data++) {
+               run_handler (msg, invoke_phase, data);
+
+               if (SOUP_MESSAGE_IS_STARTING (msg))
+                       return;
+       }
+
+       /* Issue final callback if the invoke_phase is POST_BODY and
+        * the error class is not INFORMATIONAL.
+        */
+       if (invoke_phase == SOUP_HANDLER_POST_BODY &&
+           msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL)
+               soup_message_issue_callback (msg);
+}
+
+static void
+add_handler (SoupMessage      *msg,
+            SoupHandlerPhase  phase,
+            SoupCallbackFn    handler_cb,
+            gpointer          user_data,
+            SoupHandlerKind   kind,
+            const char       *header,
+            guint             errorcode,
+            guint             errorclass)
+{
+       SoupHandlerData *data;
+
+       data = g_new0 (SoupHandlerData, 1);
+       data->phase = phase;
+       data->handler_cb = handler_cb;
+       data->user_data = user_data;
+       data->kind = kind;
+
+       switch (kind) {
+       case SOUP_HANDLER_HEADER:
+               data->data.header = header;
+               break;
+       case SOUP_HANDLER_ERROR_CODE:
+               data->data.errorcode = errorcode;
+               break;
+       case SOUP_HANDLER_ERROR_CLASS:
+               data->data.errorclass = errorclass;
+               break;
+       default:
+               break;
+       }
+
+       msg->priv->content_handlers =
+               g_slist_append (msg->priv->content_handlers, data);
+}
+
+void
+soup_message_add_header_handler (SoupMessage      *msg,
+                                const char       *header,
+                                SoupHandlerPhase  phase,
+                                SoupCallbackFn    handler_cb,
+                                gpointer          user_data)
+{
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+       g_return_if_fail (header != NULL);
+       g_return_if_fail (handler_cb != NULL);
+
+       add_handler (msg, phase, handler_cb, user_data,
+                    SOUP_HANDLER_HEADER,
+                    header, 0, 0);
+}
+
+void
+soup_message_add_error_code_handler (SoupMessage      *msg,
+                                    guint             errorcode,
+                                    SoupHandlerPhase  phase,
+                                    SoupCallbackFn    handler_cb,
+                                    gpointer          user_data)
+{
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+       g_return_if_fail (errorcode != 0);
+       g_return_if_fail (handler_cb != NULL);
+
+       add_handler (msg, phase, handler_cb, user_data,
+                    SOUP_HANDLER_ERROR_CODE,
+                    NULL, errorcode, 0);
+}
+
+void
+soup_message_add_error_class_handler (SoupMessage      *msg,
+                                     SoupErrorClass    errorclass,
+                                     SoupHandlerPhase  phase,
+                                     SoupCallbackFn    handler_cb,
+                                     gpointer          user_data)
+{
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+       g_return_if_fail (errorclass != 0);
+       g_return_if_fail (handler_cb != NULL);
+
+       add_handler (msg, phase, handler_cb, user_data,
+                    SOUP_HANDLER_ERROR_CLASS,
+                    NULL, 0, errorclass);
+}
+
+void
+soup_message_add_handler (SoupMessage      *msg,
+                         SoupHandlerPhase  phase,
+                         SoupCallbackFn    handler_cb,
+                         gpointer          user_data)
+{
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+       g_return_if_fail (handler_cb != NULL);
+
+       add_handler (msg, phase, handler_cb, user_data, 0, NULL, 0, 0);
+}
+
+void
+soup_message_remove_handler (SoupMessage     *msg,
+                            SoupHandlerPhase phase,
+                            SoupCallbackFn   handler_cb,
+                            gpointer         user_data)
+{
+       GSList *iter = msg->priv->content_handlers;
+
+       while (iter) {
+               SoupHandlerData *data = iter->data;
+
+               if (data->handler_cb == handler_cb &&
+                   data->user_data == user_data &&
+                   data->phase == phase) {
+                       msg->priv->content_handlers =
+                               g_slist_remove (msg->priv->content_handlers,
+                                               data);
+                       g_free (data);
+                       break;
+               }
+
+               iter = iter->next;
+       }
+}
+
+
+/* FIXME: these don't belong here */
+
+static void
+authorize_handler (SoupMessage *msg, gpointer proxy)
+{
+       SoupContext *ctx;
+
+       ctx = proxy ? soup_get_proxy () : msg->context;
+       if (soup_context_update_auth (ctx, msg))
+               soup_message_requeue (msg);
+       else {
+               soup_message_set_error (msg,
+                                       proxy ?
+                                       SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
+                                       SOUP_ERROR_CANT_AUTHENTICATE);
+       }
+}
+
+static void
+redirect_handler (SoupMessage *msg, gpointer user_data)
+{
+       const char *new_loc;
+       const SoupUri *old_uri;
+       SoupUri *new_uri;
+       SoupContext *new_ctx;
+
+       if (msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT)
+               return;
+
+       old_uri = soup_context_get_uri (msg->context);
+
+       new_loc = soup_message_get_header (msg->response_headers, "Location");
+       if (!new_loc)
+               return;
+       new_uri = soup_uri_new (new_loc);
+       if (!new_uri)
+               goto INVALID_REDIRECT;
+
+       /* Copy auth info from original URI. */
+       if (old_uri->user && !new_uri->user)
+               soup_uri_set_auth (new_uri,
+                                  old_uri->user,
+                                  old_uri->passwd,
+                                  old_uri->authmech);
+
+       new_ctx = soup_context_from_uri (new_uri);
+
+       soup_uri_free (new_uri);
+
+       if (!new_ctx)
+               goto INVALID_REDIRECT;
+
+       soup_message_set_context (msg, new_ctx);
+       g_object_unref (new_ctx);
+
+       soup_message_requeue (msg);
+       return;
+
+ INVALID_REDIRECT:
+       soup_message_set_error_full (msg,
+                                    SOUP_ERROR_MALFORMED,
+                                    "Invalid Redirect URL");
+}
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
new file mode 100644 (file)
index 0000000..e1c9a23
--- /dev/null
@@ -0,0 +1,675 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-message-io.c: HTTP message I/O
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "soup-message.h"
+#include "soup-message-private.h"
+#include "soup-misc.h"
+#include "soup-private.h"
+
+typedef struct {
+       guint                     idle_tag;
+       guint                     read_tag;
+       guint                     err_tag;
+
+       GByteArray               *body_buf;
+       GByteArray               *meta_buf;
+
+       SoupTransferEncoding      encoding;
+       guint                     read_length;
+
+       SoupMessageReadHeadersFn  read_headers_cb;
+       SoupMessageReadChunkFn    read_chunk_cb;
+       SoupMessageReadBodyFn     read_body_cb;
+       SoupMessageReadErrorFn    error_cb;
+} SoupMessageReadState;
+
+/* Put these around callback invocation if there is code afterward
+ * that depends on the read not having been cancelled.
+ */
+#define SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
+#define SOUP_MESSAGE_READ_RETURN_IF_CANCELLED cancelled = (msg->priv->read_state != r); g_object_unref (msg); if (cancelled) return; }
+#define SOUP_MESSAGE_READ_RETURN_VAL_IF_CANCELLED(val) cancelled = (msg->priv->read_state != r); g_object_unref (msg); if (cancelled) return val; }
+
+void
+soup_message_read_cancel (SoupMessage *msg)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+
+       if (!r)
+               return;
+
+       if (r->idle_tag)
+               g_source_remove (r->idle_tag);
+       if (r->read_tag)
+               g_signal_handler_disconnect (msg->priv->socket, r->read_tag);
+       if (r->err_tag)
+               g_signal_handler_disconnect (msg->priv->socket, r->err_tag);
+
+       if (r->body_buf)
+               g_byte_array_free (r->body_buf, TRUE);
+       if (r->meta_buf)
+               g_byte_array_free (r->meta_buf, TRUE);
+
+       g_free (r);
+
+       msg->priv->read_state = NULL;
+}
+
+void
+soup_message_read_set_callbacks (SoupMessage              *msg,
+                                SoupMessageReadHeadersFn  read_headers_cb,
+                                SoupMessageReadChunkFn    read_chunk_cb,
+                                SoupMessageReadBodyFn     read_body_cb,
+                                SoupMessageReadErrorFn    error_cb)
+{
+       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;
+}
+
+static void
+issue_final_callback (SoupMessage *msg)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+       SoupMessageReadBodyFn read_body_cb = r->read_body_cb;
+       char *body;
+       guint len;
+
+       if (r->body_buf) {
+               body = r->body_buf->data;
+               len = 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);
+}
+
+static void
+failed_read (SoupSocket *sock, SoupMessage *msg)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+       SoupMessageReadErrorFn error_cb = r->error_cb;
+
+       /* Closing the connection to signify EOF is valid if content
+        * length is unknown, but only if headers have been sent.
+        */
+       if (msg->priv->status > SOUP_MESSAGE_STATUS_READING_HEADERS &&
+           r->encoding == SOUP_TRANSFER_UNKNOWN) {
+               issue_final_callback (msg);
+               return;
+       }
+
+       soup_message_read_cancel (msg);
+       error_cb (msg);
+}
+
+static gboolean
+read_metadata (SoupMessage *msg, const char *boundary, int boundary_len)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+       SoupSocketIOStatus status;
+       char read_buf[RESPONSE_BLOCK_SIZE];
+       guint nread;
+       gboolean done;
+
+       do {
+               status = soup_socket_read_until (msg->priv->socket, read_buf,
+                                                sizeof (read_buf),
+                                                boundary, boundary_len,
+                                                &nread, &done);
+               switch (status) {
+               case SOUP_SOCKET_OK:
+                       g_byte_array_append (r->meta_buf, read_buf, nread);
+                       break;
+
+               case SOUP_SOCKET_ERROR:
+               case SOUP_SOCKET_EOF:
+                       failed_read (msg->priv->socket, msg);
+                       return FALSE;
+
+               case SOUP_SOCKET_WOULD_BLOCK:
+                       return FALSE;
+               }
+       } while (!done);
+
+       return TRUE;
+}
+
+static gboolean
+read_body_chunk (SoupMessage *msg, guint *size)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+       SoupSocketIOStatus status;
+       char read_buf[RESPONSE_BLOCK_SIZE];
+       guint nread, len = sizeof (read_buf);
+       gboolean read_to_eof = (r->encoding == SOUP_TRANSFER_UNKNOWN);
+
+       while (read_to_eof || *size > 0) {
+               if (!read_to_eof)
+                       len = MIN (len, *size);
+
+               status = soup_socket_read (msg->priv->socket, read_buf,
+                                          len, &nread);
+
+               switch (status) {
+               case SOUP_SOCKET_OK:
+                       if (!nread)
+                               break;
+
+                       if (r->read_chunk_cb) {
+                               SOUP_MESSAGE_READ_PREPARE_FOR_CALLBACK;
+                               r->read_chunk_cb (msg, read_buf, nread);
+                               SOUP_MESSAGE_READ_RETURN_VAL_IF_CANCELLED (FALSE);
+                       }
+
+                       if (r->body_buf)
+                               g_byte_array_append (r->body_buf, read_buf, nread);
+                       *size -= nread;
+                       break;
+
+               case SOUP_SOCKET_EOF:
+                       if (read_to_eof)
+                               return TRUE;
+                       /* else fall through */
+
+               case SOUP_SOCKET_ERROR:
+                       failed_read (msg->priv->socket, msg);
+                       return FALSE;
+
+               case SOUP_SOCKET_WOULD_BLOCK:
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+#define SOUP_TRANSFER_EOL     "\r\n"
+#define SOUP_TRANSFER_EOL_LEN 2
+
+#define SOUP_TRANSFER_DOUBLE_EOL     "\r\n\r\n"
+#define SOUP_TRANSFER_DOUBLE_EOL_LEN 4
+
+static void
+do_read (SoupSocket *sock, SoupMessage *msg)
+{
+       SoupMessageReadState *r = msg->priv->read_state;
+
+       while (1) {
+               switch (msg->priv->status) {
+               case SOUP_MESSAGE_STATUS_READING_HEADERS:
+                       if (!read_metadata (msg, SOUP_TRANSFER_DOUBLE_EOL,
+                                           SOUP_TRANSFER_DOUBLE_EOL_LEN))
+                               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);
+                               SOUP_MESSAGE_READ_RETURN_IF_CANCELLED;
+                       }
+                       g_byte_array_set_size (r->meta_buf, 0);
+
+                       switch (r->encoding) {
+                       case SOUP_TRANSFER_UNKNOWN:
+                       case SOUP_TRANSFER_CONTENT_LENGTH:
+                               msg->priv->status =
+                                       SOUP_MESSAGE_STATUS_READING_BODY;
+                               break;
+                       case SOUP_TRANSFER_CHUNKED:
+                               msg->priv->status =
+                                       SOUP_MESSAGE_STATUS_READING_CHUNK_SIZE;
+                               break;
+                       }
+                       break;
+
+               case SOUP_MESSAGE_STATUS_READING_BODY:
+                       if (!read_body_chunk (msg, &r->read_length))
+                               return;
+
+                       goto done;
+                       break;
+
+               case SOUP_MESSAGE_STATUS_READING_CHUNK_SIZE:
+                       if (!read_metadata (msg, SOUP_TRANSFER_EOL,
+                                           SOUP_TRANSFER_EOL_LEN))
+                               return;
+
+                       r->read_length = strtoul (r->meta_buf->data, NULL, 16);
+                       g_byte_array_set_size (r->meta_buf, 0);
+
+                       if (r->read_length > 0) {
+                               msg->priv->status =
+                                       SOUP_MESSAGE_STATUS_READING_CHUNK;
+                       } else {
+                               msg->priv->status =
+                                       SOUP_MESSAGE_STATUS_READING_TRAILERS;
+                       }
+                       break;
+
+               case SOUP_MESSAGE_STATUS_READING_CHUNK:
+                       if (!read_body_chunk (msg, &r->read_length))
+                               return;
+
+                       msg->priv->status =
+                               SOUP_MESSAGE_STATUS_READING_CHUNK_END;
+                       break;
+
+               case SOUP_MESSAGE_STATUS_READING_CHUNK_END:
+                       if (!read_metadata (msg, SOUP_TRANSFER_EOL,
+                                           SOUP_TRANSFER_EOL_LEN))
+                               return;
+
+                       g_byte_array_set_size (r->meta_buf, 0);
+                       msg->priv->status =
+                               SOUP_MESSAGE_STATUS_READING_CHUNK_SIZE;
+                       break;
+
+               case SOUP_MESSAGE_STATUS_READING_TRAILERS:
+                       if (!read_metadata (msg, SOUP_TRANSFER_EOL,
+                                           SOUP_TRANSFER_EOL_LEN))
+                               return;
+
+                       if (r->meta_buf->len == SOUP_TRANSFER_EOL_LEN)
+                               goto done;
+
+                       /* FIXME: process trailers */
+                       g_byte_array_set_size (r->meta_buf, 0);
+                       break;
+
+               default:
+                       g_return_if_reached ();
+               }
+       }
+
+ done:
+       msg->priv->status = SOUP_MESSAGE_STATUS_FINISHED_READING;
+       issue_final_callback (msg);
+}
+
+static gboolean
+idle_read (gpointer user_data)
+{
+       SoupMessage *msg = user_data;
+       SoupMessageReadState *r = msg->priv->read_state;
+
+       g_return_val_if_fail (r != NULL, FALSE);
+
+       r->idle_tag = 0;
+       do_read (msg->priv->socket, msg);
+       return FALSE;
+}
+
+void
+soup_message_read (SoupMessage *msg,
+                  SoupMessageReadHeadersFn read_headers_cb,
+                  SoupMessageReadChunkFn   read_chunk_cb,
+                  SoupMessageReadBodyFn    read_body_cb,
+                  SoupMessageReadErrorFn   error_cb)
+{
+       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);
+
+       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->encoding = SOUP_TRANSFER_UNKNOWN;
+
+       r->meta_buf = g_byte_array_new ();
+       if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
+               r->body_buf = g_byte_array_new ();
+
+       r->read_tag = g_signal_connect (msg->priv->socket, "readable",
+                                       G_CALLBACK (do_read), msg);
+       r->err_tag = g_signal_connect (msg->priv->socket, "disconnected",
+                                      G_CALLBACK (failed_read), msg);
+
+       r->idle_tag = g_idle_add (idle_read, msg);
+
+       msg->priv->status = SOUP_MESSAGE_STATUS_READING_HEADERS;
+       msg->priv->read_state = r;
+}
+
+
+
+typedef struct {
+       guint idle_tag;
+       guint write_tag;
+       guint err_tag;
+
+       GString *buf;
+       SoupTransferEncoding encoding;
+       const SoupDataBuffer *body;
+       SoupDataBuffer chunk;
+       guint nwrote;
+
+       SoupMessageWriteGetHeaderFn get_header_cb;
+       SoupMessageWriteGetChunkFn  get_chunk_cb;
+       SoupMessageWriteDoneFn      write_done_cb;
+       SoupMessageWriteErrorFn     error_cb;
+} SoupMessageWriteState;
+
+/* Put these around callback invocation if there is code afterward
+ * that depends on the write not having been cancelled or paused.
+ */
+#define SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
+#define SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED cancelled = (msg->priv->write_state != w); g_object_unref (msg); if (cancelled || !w->write_tag) return; }
+
+void
+soup_message_write_cancel (SoupMessage *msg)
+{
+       SoupMessageWriteState *w = msg->priv->write_state;
+
+       if (!w)
+               return;
+
+       if (w->idle_tag)
+               g_source_remove (w->idle_tag);
+       if (w->err_tag)
+               g_signal_handler_disconnect (msg->priv->socket, w->err_tag);
+       if (w->write_tag)
+               g_signal_handler_disconnect (msg->priv->socket, w->write_tag);
+
+       g_string_free (w->buf, TRUE);
+
+       g_free (w);
+
+       msg->priv->write_state = NULL;
+}
+
+static void
+failed_write (SoupSocket *sock, SoupMessage *msg)
+{
+       SoupMessageWriteState *w = msg->priv->write_state;
+       SoupMessageWriteErrorFn error_cb = w->error_cb;
+
+       soup_message_write_cancel (msg);
+       error_cb (msg);
+}
+
+static gboolean
+write_data (SoupMessage *msg, const char *data, guint len)
+{
+       SoupMessageWriteState *w = msg->priv->write_state;
+       SoupSocketIOStatus status;
+       guint nwrote;
+
+       while (len - w->nwrote) {
+               status = soup_socket_write (msg->priv->socket,
+                                           data + w->nwrote,
+                                           len - w->nwrote,
+                                           &nwrote);
+               switch (status) {
+               case SOUP_SOCKET_EOF:
+               case SOUP_SOCKET_ERROR:
+                       failed_write (msg->priv->socket, msg);
+                       return FALSE;
+
+               case SOUP_SOCKET_WOULD_BLOCK:
+                       return FALSE;
+
+               case SOUP_SOCKET_OK:
+                       w->nwrote += nwrote;
+                       break;
+               }
+       }
+
+       return TRUE;
+}
+
+static void
+do_write (SoupSocket *sock, SoupMessage *msg)
+{
+       SoupMessageWriteState *w = msg->priv->write_state;
+       SoupMessageWriteDoneFn write_done_cb = w->write_done_cb;
+
+       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);
+                               SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED;
+
+                               w->get_header_cb = NULL;
+                               w->nwrote = 0;
+                       }
+
+                       if (!write_data (msg, w->buf->str, w->buf->len))
+                               return;
+
+                       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;
+
+               case SOUP_MESSAGE_STATUS_WRITING_BODY:
+                       if (!write_data (msg, w->body->body,
+                                        w->body->length))
+                               return;
+
+                       goto done;
+
+               case SOUP_MESSAGE_STATUS_WRITING_CHUNK_SIZE:
+                       if (!w->buf->len) {
+                               gboolean got_chunk;
+
+                               SOUP_MESSAGE_WRITE_PREPARE_FOR_CALLBACK;
+                               got_chunk =
+                                       w->get_chunk_cb (msg, &w->chunk);
+                               SOUP_MESSAGE_WRITE_RETURN_IF_CANCELLED;
+
+                               if (!got_chunk) {
+                                       /* No more chunks. Write the
+                                        * 0-length chunk to signify
+                                        * the end.
+                                        */
+                                       w->chunk.length = 0;
+                                       w->get_chunk_cb = NULL;
+                               }
+
+                               g_string_append_printf (w->buf, "%x\r\n",
+                                                       w->chunk.length);
+                               w->nwrote = 0;
+                       }
+
+                       if (!write_data (msg, w->buf->str, w->buf->len))
+                               return;
+
+                       g_string_truncate (w->buf, 0);
+                       w->nwrote = 0;
+                       msg->priv->status = SOUP_MESSAGE_STATUS_WRITING_CHUNK;
+                       /* fall through */
+
+               case SOUP_MESSAGE_STATUS_WRITING_CHUNK:
+                       if (!write_data (msg, w->chunk.body,
+                                        w->chunk.length))
+                               return;
+
+                       if (w->chunk.owner == SOUP_BUFFER_SYSTEM_OWNED)
+                               g_free (w->chunk.body);
+                       memset (&w->chunk, 0, sizeof (SoupDataBuffer));
+
+                       w->nwrote = 0;
+                       msg->priv->status = SOUP_MESSAGE_STATUS_WRITING_CHUNK_END;
+                       /* fall through */
+
+               case SOUP_MESSAGE_STATUS_WRITING_CHUNK_END:
+                       if (!write_data (msg, SOUP_TRANSFER_EOL,
+                                        SOUP_TRANSFER_EOL_LEN))
+                               return;
+
+                       w->nwrote = 0;
+                       if (w->get_chunk_cb) {
+                               msg->priv->status =
+                                       SOUP_MESSAGE_STATUS_WRITING_CHUNK_SIZE;
+                               break;
+                       }
+
+                       msg->priv->status =
+                               SOUP_MESSAGE_STATUS_WRITING_TRAILERS;
+                       /* fall through */
+
+               case SOUP_MESSAGE_STATUS_WRITING_TRAILERS:
+                       if (!write_data (msg, SOUP_TRANSFER_EOL,
+                                        SOUP_TRANSFER_EOL_LEN))
+                               return;
+
+                       goto done;
+
+               default:
+                       g_return_if_reached ();
+               }
+       }
+
+ done:
+       msg->priv->status = SOUP_MESSAGE_STATUS_FINISHED_WRITING;
+       soup_message_write_cancel (msg);
+       write_done_cb (msg);
+}
+
+static gboolean
+idle_write (gpointer user_data)
+{
+       SoupMessage *msg = user_data;
+       SoupMessageWriteState *w = msg->priv->write_state;
+
+       w->idle_tag = 0;
+       do_write (msg->priv->socket, msg);
+       return FALSE;
+}
+
+static SoupMessageWriteState *
+create_writer (SoupMessage                 *msg,
+              SoupTransferEncoding         encoding,
+              SoupMessageWriteGetHeaderFn  get_header_cb,
+              SoupMessageWriteDoneFn       write_done_cb,
+              SoupMessageWriteErrorFn      error_cb)
+{
+       SoupMessageWriteState *w;
+
+       w = g_new0 (SoupMessageWriteState, 1);
+       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->write_tag =
+               g_signal_connect (msg->priv->socket, "writable",
+                                 G_CALLBACK (do_write), msg);
+       w->err_tag =
+               g_signal_connect (msg->priv->socket, "disconnected",
+                                 G_CALLBACK (failed_write), msg);
+
+       w->idle_tag = g_idle_add (idle_write, msg);
+
+       msg->priv->status = SOUP_MESSAGE_STATUS_WRITING_HEADERS;
+       msg->priv->write_state = w;
+
+       return w;
+}
+
+void
+soup_message_write_simple (SoupMessage                 *msg,
+                          const SoupDataBuffer        *body,
+                          SoupMessageWriteGetHeaderFn  get_header_cb,
+                          SoupMessageWriteDoneFn       write_done_cb,
+                          SoupMessageWriteErrorFn      error_cb)
+{
+       SoupMessageWriteState *w;
+
+       w = create_writer (msg, SOUP_TRANSFER_CONTENT_LENGTH,
+                          get_header_cb, write_done_cb, error_cb);
+
+       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)
+{
+       SoupMessageWriteState *w;
+
+       w = create_writer (msg, encoding, get_header_cb,
+                          write_done_cb, error_cb);
+       w->get_chunk_cb = get_chunk_cb;
+}
+
+void  
+soup_message_write_pause (SoupMessage *msg)
+{
+       SoupMessageWriteState *w;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+       w = msg->priv->write_state;
+       g_return_if_fail (w != NULL);
+
+       if (w->write_tag) {
+               g_signal_handler_disconnect (msg->priv->socket, w->write_tag);
+               w->write_tag = 0;
+       }
+       if (w->idle_tag) {
+               g_source_remove (w->idle_tag);
+               w->idle_tag = 0;
+       }
+}
+
+void  
+soup_message_write_unpause (SoupMessage *msg)
+{
+       SoupMessageWriteState *w;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+       w = msg->priv->write_state;
+       if (!w)
+               return;
+
+       if (!w->write_tag) {
+               w->write_tag = g_signal_connect (msg->priv->socket, "writable",
+                                                G_CALLBACK (do_write), msg);
+       }
+       if (!w->idle_tag)
+               w->idle_tag = g_idle_add (idle_write, msg);
+}
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
new file mode 100644 (file)
index 0000000..a5ee2b2
--- /dev/null
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef SOUP_MESSAGE_PRIVATE_H
+#define SOUP_MESSAGE_PRIVATE_H 1
+
+typedef enum {
+       SOUP_MESSAGE_STATUS_IDLE,
+       SOUP_MESSAGE_STATUS_QUEUED,
+        SOUP_MESSAGE_STATUS_CONNECTING,
+       SOUP_MESSAGE_STATUS_FINISHED,
+
+       SOUP_MESSAGE_STATUS_WRITING_HEADERS,
+       SOUP_MESSAGE_STATUS_WRITING_BODY,
+       SOUP_MESSAGE_STATUS_WRITING_CHUNK_SIZE,
+       SOUP_MESSAGE_STATUS_WRITING_CHUNK,
+       SOUP_MESSAGE_STATUS_WRITING_CHUNK_END,
+       SOUP_MESSAGE_STATUS_WRITING_TRAILERS,
+       SOUP_MESSAGE_STATUS_FINISHED_WRITING,
+
+       SOUP_MESSAGE_STATUS_READING_HEADERS,
+       SOUP_MESSAGE_STATUS_READING_BODY,
+       SOUP_MESSAGE_STATUS_READING_CHUNK_SIZE,
+       SOUP_MESSAGE_STATUS_READING_CHUNK,
+       SOUP_MESSAGE_STATUS_READING_CHUNK_END,
+       SOUP_MESSAGE_STATUS_READING_TRAILERS,
+       SOUP_MESSAGE_STATUS_FINISHED_READING
+
+} SoupMessageStatus;
+
+#define SOUP_MESSAGE_IS_STARTING(msg) (msg->priv->status == SOUP_MESSAGE_STATUS_QUEUED || msg->priv->status == SOUP_MESSAGE_STATUS_CONNECTING)
+#define SOUP_MESSAGE_IS_WRITING(msg) (msg->priv->status >= SOUP_MESSAGE_STATUS_WRITING_HEADERS && msg->priv->status <= SOUP_MESSAGE_STATUS_WRITING_TRAILERS)
+#define SOUP_MESSAGE_IS_READING(msg) (msg->priv->status >= SOUP_MESSAGE_STATUS_READING_HEADERS && msg->priv->status <= SOUP_MESSAGE_STATUS_READING_TRAILERS)
+
+
+struct SoupMessagePrivate {
+       SoupMessageStatus  status;
+
+       SoupConnectId      connect_tag;
+       gpointer           read_state;
+       gpointer           write_state;
+
+       guint              retries;
+
+       SoupCallbackFn     callback;
+       gpointer           user_data;
+
+       guint              msg_flags;
+
+       GSList            *content_handlers;
+
+       SoupHttpVersion    http_version;
+
+       SoupConnection    *connection;
+       SoupSocket        *socket;
+};
+
+void     soup_message_issue_callback (SoupMessage      *req);
+void     soup_message_run_handlers   (SoupMessage      *msg,
+                                     SoupHandlerPhase  invoke_phase);
+
+void     soup_message_cleanup        (SoupMessage      *req);
+
+
+typedef void (*SoupMessageReadHeadersFn) (SoupMessage          *msg,
+                                         char                 *headers,
+                                         guint                 header_len,
+                                         SoupTransferEncoding *encoding,
+                                         int                  *content_len);
+
+typedef void (*SoupMessageReadChunkFn)   (SoupMessage          *msg,
+                                         const char           *chunk,
+                                         guint                 len);
+
+typedef void (*SoupMessageReadBodyFn)    (SoupMessage          *msg,
+                                         char                 *body,
+                                         guint                 len);
+
+typedef void (*SoupMessageReadErrorFn)   (SoupMessage          *msg);
+
+
+void soup_message_read               (SoupMessage              *msg,
+                                     SoupMessageReadHeadersFn  read_headers_cb,
+                                     SoupMessageReadChunkFn    read_chunk_cb,
+                                     SoupMessageReadBodyFn     read_body_cb,
+                                     SoupMessageReadErrorFn    error_cb);
+void soup_message_read_set_callbacks (SoupMessage              *msg,
+                                     SoupMessageReadHeadersFn  read_headers_cb,
+                                     SoupMessageReadChunkFn    read_chunk_cb,
+                                     SoupMessageReadBodyFn     read_body_cb,
+                                     SoupMessageReadErrorFn    error_cb);
+void soup_message_read_cancel        (SoupMessage *msg);
+
+
+typedef void     (*SoupMessageWriteGetHeaderFn) (SoupMessage    *msg,
+                                                GString        *out_hdr);
+
+typedef gboolean (*SoupMessageWriteGetChunkFn)  (SoupMessage    *msg,
+                                                SoupDataBuffer *out_next);
+
+typedef void     (*SoupMessageWriteDoneFn)      (SoupMessage    *msg);
+
+typedef void     (*SoupMessageWriteErrorFn)     (SoupMessage    *msg);
+
+void soup_message_write         (SoupMessage                 *msg,
+                                SoupTransferEncoding         encoding,
+                                SoupMessageWriteGetHeaderFn  get_header_cb,
+                                SoupMessageWriteGetChunkFn   get_chunk_cb,
+                                SoupMessageWriteDoneFn       write_done_cb,
+                                SoupMessageWriteErrorFn      error_cb);
+void soup_message_write_simple  (SoupMessage                 *msg,
+                                const SoupDataBuffer        *body,
+                                SoupMessageWriteGetHeaderFn  get_header_cb,
+                                SoupMessageWriteDoneFn       write_done_cb,
+                                SoupMessageWriteErrorFn      error_cb);
+void soup_message_write_cancel  (SoupMessage                 *msg);
+
+void soup_message_write_pause   (SoupMessage                 *msg);
+void soup_message_write_unpause (SoupMessage                 *msg);
+
+
+#endif /* SOUP_MESSAGE_PRIVATE_H */
index 77d1fd0..fb4a3d4 100644 (file)
 #include "soup-auth.h"
 #include "soup-error.h"
 #include "soup-message.h"
+#include "soup-message-private.h"
 #include "soup-misc.h"
 #include "soup-context.h"
 #include "soup-private.h"
 #include "soup-queue.h"
-#include "soup-transfer.h"
 
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class;
@@ -26,7 +26,7 @@ init (GObject *object)
 
        msg->priv = g_new0 (SoupMessagePrivate, 1);
 
-       msg->status  = SOUP_STATUS_IDLE;
+       msg->priv->status  = SOUP_MESSAGE_STATUS_IDLE;
 
        msg->request_headers = g_hash_table_new (soup_str_case_hash,
                                                 soup_str_case_equal);
@@ -89,8 +89,6 @@ SOUP_MAKE_TYPE (soup_message, SoupMessage, class_init, init, PARENT_TYPE)
  * Creates a new empty #SoupMessage, which will connect to the URL
  * represented by @context. A reference will be added to @context.
  * 
- * The new message has a status of %SOUP_STATUS_IDLE.
- *
  * Return value: the new #SoupMessage.
  */
 SoupMessage *
@@ -99,7 +97,6 @@ soup_message_new (SoupContext *context, const char *method)
        SoupMessage *msg;
 
        msg          = g_object_new (SOUP_TYPE_MESSAGE, NULL);
-       msg->status  = SOUP_STATUS_IDLE;
        msg->method  = method ? method : SOUP_METHOD_GET;
 
        soup_message_set_context (msg, context);
@@ -121,8 +118,6 @@ soup_message_new (SoupContext *context, const char *method)
  * request data buffer will be filled from @req_owner, @req_body, and
  * @req_length.
  *
- * The new message has a status of %SOUP_STATUS_IDLE.
- *
  * Return value: the new #SoupMessage.
  */
 SoupMessage *
@@ -141,27 +136,6 @@ soup_message_new_full (SoupContext   *context,
        return msg;
 }
 
-static void
-release_connection (char     *body,
-                   guint     len,
-                   gpointer  user_data)
-{
-       SoupConnection *conn = user_data;
-
-       soup_connection_set_in_use (conn, FALSE);
-       g_object_unref (conn);
-       g_free (body);
-}
-
-static void
-release_and_close_connection (gboolean headers_done, gpointer user_data)
-{
-       SoupConnection *conn = user_data;
-
-       soup_connection_disconnect (conn);
-       g_object_unref (conn);
-}
-
 /**
  * soup_message_cleanup:
  * @req: a #SoupMessage.
@@ -175,31 +149,11 @@ soup_message_cleanup (SoupMessage *req)
 {
        g_return_if_fail (SOUP_IS_MESSAGE (req));
 
-       if (req->priv->connection && req->priv->read_tag &&
-           req->status == SOUP_STATUS_READING_RESPONSE) {
-               soup_transfer_read_set_callbacks (req->priv->read_tag,
-                                                 NULL,
-                                                 NULL,
-                                                 release_connection,
-                                                 release_and_close_connection,
-                                                 req->priv->connection);
-               soup_transfer_read_unref (req->priv->read_tag);
-               req->priv->read_tag = NULL;
-               req->priv->connection = NULL;
-
-               g_object_unref (req->priv->socket);
-               req->priv->socket = NULL;
-       }
-
-       if (req->priv->read_tag) {
-               soup_transfer_read_cancel (req->priv->read_tag);
-               req->priv->read_tag = NULL;
-       }
+       if (req->priv->read_state)
+               soup_message_read_cancel (req);
 
-       if (req->priv->write_tag) {
-               soup_transfer_write_cancel (req->priv->write_tag);
-               req->priv->write_tag = NULL;
-       }
+       if (req->priv->write_state)
+               soup_message_write_cancel (req);
 
        if (req->priv->connect_tag) {
                soup_context_cancel_connect (req->priv->connect_tag);
@@ -237,7 +191,7 @@ soup_message_issue_callback (SoupMessage *req)
        if (req->priv->callback) {
                (*req->priv->callback) (req, req->priv->user_data);
 
-               if (req->status != SOUP_STATUS_QUEUED)
+               if (!SOUP_MESSAGE_IS_STARTING (req))
                        g_object_unref (req);
        }
 }
@@ -262,9 +216,9 @@ soup_message_disconnect (SoupMessage *msg)
  * soup_message_cancel:
  * @msg: a #SoupMessage currently being processed.
  * 
- * Cancel a running message, and issue completion callback with a
- * #SoupTransferStatus of %SOUP_ERROR_CANCELLED. If not requeued by
- * the completion callback, the @msg will be destroyed.
+ * Cancel a running message, and issue completion callback with an
+ * error code of %SOUP_ERROR_CANCELLED. If not requeued by the
+ * completion callback, the @msg will be destroyed.
  */
 void
 soup_message_cancel (SoupMessage *msg)
@@ -431,10 +385,8 @@ soup_message_queue (SoupMessage    *req,
 }
 
 static void
-requeue_read_error (gboolean body_started, gpointer user_data)
+requeue_read_error (SoupMessage *msg)
 {
-       SoupMessage *msg = user_data;
-
        soup_message_disconnect (msg);
        soup_queue_message (msg,
                            msg->priv->callback,
@@ -442,11 +394,8 @@ requeue_read_error (gboolean body_started, gpointer user_data)
 }
 
 static void
-requeue_read_finished (char     *body,
-                      guint     len,
-                      gpointer  user_data)
+requeue_read_finished (SoupMessage *msg, char *body, guint len)
 {
-       SoupMessage *msg = user_data;
        SoupConnection *conn = msg->priv->connection;
 
        g_free (body);
@@ -479,24 +428,18 @@ soup_message_requeue (SoupMessage *req)
 {
        g_return_if_fail (SOUP_IS_MESSAGE (req));
 
-       if (req->priv->connection && req->priv->read_tag) {
-               soup_transfer_read_set_callbacks (req->priv->read_tag,
-                                                 NULL,
-                                                 NULL,
-                                                 requeue_read_finished,
-                                                 requeue_read_error,
-                                                 req);
-               soup_transfer_read_unref (req->priv->read_tag);
-               req->priv->read_tag = NULL;
-
-               if (req->priv->write_tag) {
-                       soup_transfer_write_cancel (req->priv->write_tag);
-                       req->priv->write_tag = NULL;
-               }
-       } else
+       if (req->priv->connection && req->priv->read_state) {
+               soup_message_read_set_callbacks (req, NULL, NULL,
+                                                requeue_read_finished,
+                                                requeue_read_error);
+
+               if (req->priv->write_state)
+                       soup_message_write_cancel (req);
+       } else {
                soup_queue_message (req,
                                    req->priv->callback,
                                    req->priv->user_data);
+       }
 }
 
 /**
@@ -520,7 +463,7 @@ soup_message_send (SoupMessage *msg)
        while (1) {
                g_main_iteration (TRUE);
 
-               if (msg->status == SOUP_STATUS_FINISHED ||
+               if (msg->priv->status == SOUP_MESSAGE_STATUS_FINISHED ||
                    SOUP_ERROR_IS_TRANSPORT (msg->errorcode))
                        break;
 
@@ -532,317 +475,6 @@ soup_message_send (SoupMessage *msg)
        return msg->errorclass;
 }
 
-static void
-authorize_handler (SoupMessage *msg, gboolean proxy)
-{
-       SoupContext *ctx;
-
-       ctx = proxy ? soup_get_proxy () : msg->context;
-       if (soup_context_update_auth (ctx, msg))
-               soup_message_requeue (msg);
-       else {
-               soup_message_set_error (msg,
-                                       proxy ?
-                                       SOUP_ERROR_CANT_AUTHENTICATE_PROXY :
-                                       SOUP_ERROR_CANT_AUTHENTICATE);
-       }
-}
-
-static void
-redirect_handler (SoupMessage *msg, gpointer user_data)
-{
-       const char *new_loc;
-       const SoupUri *old_uri;
-       SoupUri *new_uri;
-       SoupContext *new_ctx;
-
-       if (msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT)
-               return;
-
-       new_loc = soup_message_get_header (msg->response_headers, "Location");
-       if (!new_loc)
-               return;
-
-       old_uri = soup_context_get_uri (msg->context);
-
-       new_uri = soup_uri_new (new_loc);
-       if (!new_uri)
-               goto INVALID_REDIRECT;
-
-       /*
-        * Copy auth info from original URI.
-        */
-       if (old_uri->user && !new_uri->user)
-               soup_uri_set_auth (new_uri,
-                                  old_uri->user,
-                                  old_uri->passwd,
-                                  old_uri->authmech);
-
-       new_ctx = soup_context_from_uri (new_uri);
-
-       soup_uri_free (new_uri);
-
-       if (!new_ctx)
-               goto INVALID_REDIRECT;
-
-       soup_message_set_context (msg, new_ctx);
-       g_object_unref (new_ctx);
-
-       soup_message_requeue (msg);
-       return;
-
- INVALID_REDIRECT:
-       soup_message_set_error_full (msg,
-                                    SOUP_ERROR_MALFORMED,
-                                    "Invalid Redirect URL");
-}
-
-typedef enum {
-       RESPONSE_HEADER_HANDLER = 1,
-       RESPONSE_ERROR_CODE_HANDLER,
-       RESPONSE_ERROR_CLASS_HANDLER
-} SoupHandlerKind;
-
-typedef struct {
-       SoupHandlerType   type;
-       SoupCallbackFn    handler_cb;
-       gpointer          user_data;
-
-       SoupHandlerKind   kind;
-       union {
-               guint             errorcode;
-               SoupErrorClass    errorclass;
-               const char       *header;
-       } data;
-} SoupHandlerData;
-
-static SoupHandlerData global_handlers [] = {
-       /*
-        * Handle redirect response codes 300, 301, 302, 303, and 305.
-        */
-       {
-               SOUP_HANDLER_PRE_BODY,
-               redirect_handler,
-               NULL,
-               RESPONSE_ERROR_CLASS_HANDLER,
-               { SOUP_ERROR_CLASS_REDIRECT }
-       },
-       /*
-        * Handle authorization.
-        */
-       {
-               SOUP_HANDLER_PRE_BODY,
-               (SoupCallbackFn) authorize_handler,
-               GINT_TO_POINTER (FALSE),
-               RESPONSE_ERROR_CODE_HANDLER,
-               { 401 }
-       },
-       /*
-        * Handle proxy authorization.
-        */
-       {
-               SOUP_HANDLER_PRE_BODY,
-               (SoupCallbackFn) authorize_handler,
-               GINT_TO_POINTER (TRUE),
-               RESPONSE_ERROR_CODE_HANDLER,
-               { 407 }
-       },
-       { 0 }
-};
-
-static inline void
-run_handler (SoupMessage     *msg,
-            SoupHandlerType  invoke_type,
-            SoupHandlerData *data)
-{
-       if (data->type != invoke_type) return;
-
-       switch (data->kind) {
-       case RESPONSE_HEADER_HANDLER:
-               if (!soup_message_get_header (msg->response_headers,
-                                             data->data.header))
-                       return;
-               break;
-       case RESPONSE_ERROR_CODE_HANDLER:
-               if (msg->errorcode != data->data.errorcode) return;
-               break;
-       case RESPONSE_ERROR_CLASS_HANDLER:
-               if (msg->errorclass != data->data.errorclass) return;
-               break;
-       default:
-               break;
-       }
-
-       (*data->handler_cb) (msg, data->user_data);
-}
-
-/*
- * Run each handler with matching criteria (first per-message then global
- * handlers). If a handler requeues a message, we stop processing and terminate
- * the current request.
- *
- * After running all handlers, if there is an error set or the invoke type was
- * post_body, issue the final callback.
- *
- * FIXME: If the errorcode is changed by a handler, we should restart the
- * processing.
- */
-gboolean
-soup_message_run_handlers (SoupMessage *msg, SoupHandlerType invoke_type)
-{
-       GSList *list;
-       SoupHandlerData *data;
-
-       g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
-
-       for (list = msg->priv->content_handlers; list; list = list->next) {
-               data = list->data;
-
-               run_handler (msg, invoke_type, data);
-
-               if (msg->status == SOUP_STATUS_QUEUED ||
-                   msg->status == SOUP_STATUS_CONNECTING) return TRUE;
-       }
-
-       for (data = global_handlers; data->type; data++) {
-               run_handler (msg, invoke_type, data);
-
-               if (msg->status == SOUP_STATUS_QUEUED ||
-                   msg->status == SOUP_STATUS_CONNECTING) return TRUE;
-       }
-
-       /*
-        * Issue final callback if the invoke_type is POST_BODY and the error
-        * class is not INFORMATIONAL.
-        */
-       if (invoke_type == SOUP_HANDLER_POST_BODY &&
-           msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL) {
-               soup_message_issue_callback (msg);
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-static void
-add_handler (SoupMessage      *msg,
-            SoupHandlerType   type,
-            SoupCallbackFn    handler_cb,
-            gpointer          user_data,
-            SoupHandlerKind   kind,
-            const char       *header,
-            guint             errorcode,
-            guint             errorclass)
-{
-       SoupHandlerData *data;
-
-       data = g_new0 (SoupHandlerData, 1);
-       data->type = type;
-       data->handler_cb = handler_cb;
-       data->user_data = user_data;
-       data->kind = kind;
-
-       switch (kind) {
-       case RESPONSE_HEADER_HANDLER:
-               data->data.header = header;
-               break;
-       case RESPONSE_ERROR_CODE_HANDLER:
-               data->data.errorcode = errorcode;
-               break;
-       case RESPONSE_ERROR_CLASS_HANDLER:
-               data->data.errorclass = errorclass;
-               break;
-       default:
-               break;
-       }
-
-       msg->priv->content_handlers =
-               g_slist_append (msg->priv->content_handlers, data);
-}
-
-void
-soup_message_add_header_handler (SoupMessage      *msg,
-                                const char       *header,
-                                SoupHandlerType   type,
-                                SoupCallbackFn    handler_cb,
-                                gpointer          user_data)
-{
-       g_return_if_fail (SOUP_IS_MESSAGE (msg));
-       g_return_if_fail (header != NULL);
-       g_return_if_fail (handler_cb != NULL);
-
-       add_handler (msg, type, handler_cb, user_data,
-                    RESPONSE_HEADER_HANDLER, header, 0, 0);
-}
-
-void
-soup_message_add_error_code_handler (SoupMessage      *msg,
-                                    guint             errorcode,
-                                    SoupHandlerType   type,
-                                    SoupCallbackFn    handler_cb,
-                                    gpointer          user_data)
-{
-       g_return_if_fail (SOUP_IS_MESSAGE (msg));
-       g_return_if_fail (errorcode != 0);
-       g_return_if_fail (handler_cb != NULL);
-
-       add_handler (msg, type, handler_cb, user_data,
-                    RESPONSE_ERROR_CODE_HANDLER, NULL, errorcode, 0);
-}
-
-void
-soup_message_add_error_class_handler (SoupMessage      *msg,
-                                     SoupErrorClass    errorclass,
-                                     SoupHandlerType   type,
-                                     SoupCallbackFn    handler_cb,
-                                     gpointer          user_data)
-{
-       g_return_if_fail (SOUP_IS_MESSAGE (msg));
-       g_return_if_fail (errorclass != 0);
-       g_return_if_fail (handler_cb != NULL);
-
-       add_handler (msg, type, handler_cb, user_data,
-                    RESPONSE_ERROR_CLASS_HANDLER, NULL, 0, errorclass);
-}
-
-void
-soup_message_add_handler (SoupMessage      *msg,
-                         SoupHandlerType   type,
-                         SoupCallbackFn    handler_cb,
-                         gpointer          user_data)
-{
-       g_return_if_fail (SOUP_IS_MESSAGE (msg));
-       g_return_if_fail (handler_cb != NULL);
-
-       add_handler (msg, type, handler_cb, user_data, 0, NULL, 0, 0);
-}
-
-void
-soup_message_remove_handler (SoupMessage     *msg,
-                            SoupHandlerType  type,
-                            SoupCallbackFn   handler_cb,
-                            gpointer         user_data)
-{
-       GSList *iter = msg->priv->content_handlers;
-
-       while (iter) {
-               SoupHandlerData *data = iter->data;
-
-               if (data->handler_cb == handler_cb &&
-                   data->user_data == user_data &&
-                   data->type == type) {
-                       msg->priv->content_handlers =
-                               g_slist_remove_link (
-                                       msg->priv->content_handlers,
-                                       iter);
-                       g_free (data);
-                       break;
-               }
-
-               iter = iter->next;
-       }
-}
-
 void
 soup_message_set_flags (SoupMessage *msg, guint flags)
 {
index 2c72252..96882a8 100644 (file)
 typedef struct SoupMessagePrivate SoupMessagePrivate;
 
 typedef enum {
-       SOUP_STATUS_IDLE = 0,
-       SOUP_STATUS_QUEUED,
-        SOUP_STATUS_CONNECTING,
-       SOUP_STATUS_SENDING_REQUEST,
-       SOUP_STATUS_READING_RESPONSE,
-       SOUP_STATUS_FINISHED
-} SoupTransferStatus;
+       SOUP_TRANSFER_UNKNOWN = 0,
+       SOUP_TRANSFER_CHUNKED,
+       SOUP_TRANSFER_CONTENT_LENGTH,
+} SoupTransferEncoding;
 
 typedef enum {
        SOUP_BUFFER_SYSTEM_OWNED = 0,
@@ -50,8 +47,6 @@ typedef struct {
 
        const char         *method;
 
-       SoupTransferStatus  status;
-
        guint               errorcode;
        SoupErrorClass      errorclass;
        const char         *errorphrase;
@@ -183,35 +178,35 @@ typedef enum {
        SOUP_HANDLER_PRE_BODY = 1,
        SOUP_HANDLER_BODY_CHUNK,
        SOUP_HANDLER_POST_BODY
-} SoupHandlerType;
+} SoupHandlerPhase;
 
 void           soup_message_add_handler         (SoupMessage       *msg,
-                                                SoupHandlerType    type,
+                                                SoupHandlerPhase   type,
                                                 SoupCallbackFn     handler_cb,
                                                 gpointer           user_data);
 
 void           soup_message_add_header_handler  (SoupMessage       *msg,
                                                 const char        *header,
-                                                SoupHandlerType    type,
+                                                SoupHandlerPhase   type,
                                                 SoupCallbackFn     handler_cb,
                                                 gpointer           user_data);
 
 void           soup_message_add_error_code_handler (
                                                 SoupMessage       *msg,
                                                 guint              errorcode,
-                                                SoupHandlerType    type,
+                                                SoupHandlerPhase   type,
                                                 SoupCallbackFn     handler_cb,
                                                 gpointer           user_data);
 
 void           soup_message_add_error_class_handler (
                                                 SoupMessage       *msg,
                                                 SoupErrorClass     errorclass,
-                                                SoupHandlerType    type,
+                                                SoupHandlerPhase   type,
                                                 SoupCallbackFn     handler_cb,
                                                 gpointer           user_data);
 
 void           soup_message_remove_handler      (SoupMessage       *msg, 
-                                                SoupHandlerType    type,
+                                                SoupHandlerPhase   type,
                                                 SoupCallbackFn     handler_cb,
                                                 gpointer           user_data);
 
index c40ac0b..0c8bf99 100644 (file)
@@ -62,27 +62,6 @@ typedef struct {
 #define soup_sockaddr_max sockaddr_in
 #endif
 
-struct SoupMessagePrivate {
-       SoupConnectId      connect_tag;
-       gpointer           read_tag;
-       gpointer           write_tag;
-       guint              timeout_tag;
-
-       guint              retries;
-
-       SoupCallbackFn     callback;
-       gpointer           user_data;
-
-       guint              msg_flags;
-
-       GSList            *content_handlers;
-
-       SoupHttpVersion    http_version;
-
-       SoupConnection    *connection;
-       SoupSocket        *socket;
-};
-
 /* from soup-context.c */
 
 SoupAuth   *soup_context_lookup_auth       (SoupContext    *ctx,
@@ -97,15 +76,6 @@ gboolean    soup_context_authenticate_auth (SoupContext    *ctx,
 void        soup_context_invalidate_auth   (SoupContext    *ctx,
                                            SoupAuth       *auth);
                                          
-/* from soup-message.c */
-
-void     soup_message_issue_callback (SoupMessage      *req);
-
-gboolean soup_message_run_handlers   (SoupMessage      *msg,
-                                     SoupHandlerType   invoke_type);
-
-void     soup_message_cleanup        (SoupMessage      *req);
-
 /* from soup-misc.c */
 
 guint     soup_str_case_hash   (gconstpointer  key);
index a087bd3..fdc2b49 100644 (file)
 #include "soup-queue.h"
 #include "soup-auth.h"
 #include "soup-message.h"
+#include "soup-message-private.h"
 #include "soup-context.h"
 #include "soup-headers.h"
 #include "soup-misc.h"
 #include "soup-private.h"
 #include "soup-ssl.h"
-#include "soup-transfer.h"
 
 static GSList *soup_active_requests = NULL, *soup_active_request_next = NULL;
 
@@ -54,58 +54,51 @@ soup_debug_print_headers (SoupMessage *req)
 }
 
 static void 
-soup_queue_error_cb (gboolean body_started, gpointer user_data)
+soup_queue_error_cb (SoupMessage *req)
 {
-       SoupMessage *req = user_data;
        SoupConnection *conn = soup_message_get_connection (req);
+       const SoupUri *uri;
        gboolean conn_is_new;
 
        conn_is_new = soup_connection_is_new (conn);
        soup_message_disconnect (req);
 
-       switch (req->status) {
-       case SOUP_STATUS_IDLE:
-       case SOUP_STATUS_QUEUED:
-       case SOUP_STATUS_FINISHED:
+       switch (req->priv->status) {
+       case SOUP_MESSAGE_STATUS_IDLE:
+       case SOUP_MESSAGE_STATUS_QUEUED:
+       case SOUP_MESSAGE_STATUS_FINISHED:
                break;
 
-       case SOUP_STATUS_CONNECTING:
+       case SOUP_MESSAGE_STATUS_CONNECTING:
                soup_message_set_error (req, SOUP_ERROR_CANT_CONNECT);
                soup_message_issue_callback (req);
                break;
 
-       case SOUP_STATUS_READING_RESPONSE:
-       case SOUP_STATUS_SENDING_REQUEST:
-               if (!body_started) {
-                       const SoupUri *uri = soup_context_get_uri (req->context);
-
-                       if (uri->protocol == SOUP_PROTOCOL_HTTPS) {
-                               /*
-                                * This can happen if the SSL handshake fails
-                                * for some reason (untrustable signatures,
-                                * etc.)
-                                */
-                               if (req->priv->retries >= 3) {
-                                       soup_message_set_error (
-                                               req,
-                                               SOUP_ERROR_SSL_FAILED);
-                                       soup_message_issue_callback (req);
-                               } else {
-                                       req->priv->retries++;
-                                       soup_message_requeue (req);
-                               }
-                       } else if (conn_is_new) {
-                               soup_message_set_error (
-                                       req,
-                                       SOUP_ERROR_CANT_CONNECT);
+       case SOUP_MESSAGE_STATUS_WRITING_HEADERS:
+       case SOUP_MESSAGE_STATUS_READING_HEADERS:
+               uri = soup_context_get_uri (req->context);
+
+               if (uri->protocol == SOUP_PROTOCOL_HTTPS) {
+                       /* FIXME: what does this really do? */
+
+                       /*
+                        * This can happen if the SSL handshake fails
+                        * for some reason (untrustable signatures,
+                        * etc.)
+                        */
+                       if (req->priv->retries >= 3) {
+                               soup_message_set_error (req, SOUP_ERROR_SSL_FAILED);
                                soup_message_issue_callback (req);
                        } else {
-                               /* Must have timed out. Try a new connection */
+                               req->priv->retries++;
                                soup_message_requeue (req);
                        }
-               } else {
-                       soup_message_set_error (req, SOUP_ERROR_IO);
+               } else if (conn_is_new) {
+                       soup_message_set_error (req, SOUP_ERROR_CANT_CONNECT);
                        soup_message_issue_callback (req);
+               } else {
+                       /* Must have timed out. Try a new connection */
+                       soup_message_requeue (req);
                }
                break;
 
@@ -117,13 +110,12 @@ soup_queue_error_cb (gboolean body_started, gpointer user_data)
 }
 
 static void
-soup_queue_read_headers_cb (char                 *headers,
+soup_queue_read_headers_cb (SoupMessage          *req,
+                           char                 *headers,
                            guint                 headers_len,
                             SoupTransferEncoding *encoding,
-                           int                  *content_len,
-                           gpointer              user_data)
+                           int                  *content_len)
 {
-       SoupMessage *req = user_data;
        const char *length, *enc;
        SoupHttpVersion version;
        GHashTable *resp_hdrs;
@@ -211,12 +203,10 @@ soup_queue_read_headers_cb (char                 *headers,
 }
 
 static void
-soup_queue_read_chunk_cb (const char *chunk,
-                         guint       len,
-                         gpointer    user_data)
+soup_queue_read_chunk_cb (SoupMessage *req,
+                         const char  *chunk,
+                         guint        len)
 {
-       SoupMessage *req = user_data;
-
        req->response.owner = SOUP_BUFFER_STATIC;
        req->response.length = len;
        req->response.body = (char *)chunk;
@@ -227,12 +217,8 @@ soup_queue_read_chunk_cb (const char *chunk,
 }
 
 static void
-soup_queue_read_done_cb (char     *body,
-                        guint     len,
-                        gpointer  user_data)
+soup_queue_read_done_cb (SoupMessage *req, char *body, guint len)
 {
-       SoupMessage *req = user_data;
-
        if (soup_message_is_keepalive (req))
                soup_connection_mark_old (soup_message_get_connection (req));
        else
@@ -242,28 +228,14 @@ soup_queue_read_done_cb (char     *body,
        req->response.length = len;
        req->response.body = body;
 
-       soup_transfer_read_unref (req->priv->read_tag);
-
        if (req->errorclass == SOUP_ERROR_CLASS_INFORMATIONAL) {
-               SoupSocket *sock;
-               gboolean overwrt;
-
-               sock = soup_message_get_socket (req);
-               overwrt = req->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS;
-
-               req->priv->read_tag = 
-                       soup_transfer_read (sock,
-                                           overwrt,
-                                           soup_queue_read_headers_cb,
-                                           soup_queue_read_chunk_cb,
-                                           soup_queue_read_done_cb,
-                                           soup_queue_error_cb,
-                                           req);
-       } 
-       else {
-               req->status = SOUP_STATUS_FINISHED;
-               req->priv->read_tag = NULL;
-       }
+               soup_message_read (req,
+                                  soup_queue_read_headers_cb,
+                                  soup_queue_read_chunk_cb,
+                                  soup_queue_read_done_cb,
+                                  soup_queue_error_cb);
+       } else
+               req->priv->status = SOUP_MESSAGE_STATUS_FINISHED;
 
        soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY);
 }
@@ -350,11 +322,10 @@ soup_check_used_headers (gchar  *key,
        }
 }
 
-static GString *
-soup_get_request_header (SoupMessage *req)
+static void
+soup_queue_get_request_header_cb (SoupMessage *req, GString *header)
 {
-       GString *header;
-       gchar *uri;
+       char *uri;
        SoupContext *proxy;
        const SoupUri *suri;
        struct SoupUsedHeaders hdrs = {
@@ -367,7 +338,7 @@ soup_get_request_header (SoupMessage *req)
                NULL
        };
 
-       header = hdrs.out = g_string_new (NULL);
+       hdrs.out = header;
        proxy = soup_get_proxy ();
        suri = soup_context_get_uri (req->context);
 
@@ -431,25 +402,22 @@ soup_get_request_header (SoupMessage *req)
                soup_encode_http_auth (req, header, FALSE);
 
        g_string_append (header, "\r\n");
-
-       return header;
 }
 
 static void 
-soup_queue_write_done_cb (gpointer user_data)
+soup_queue_write_done_cb (SoupMessage *req)
 {
-       SoupMessage *req = user_data;
-
-       soup_transfer_write_unref (req->priv->write_tag);
-       req->priv->write_tag = NULL;
-       req->status = SOUP_STATUS_READING_RESPONSE;
+       soup_message_read (req,
+                          soup_queue_read_headers_cb,
+                          soup_queue_read_chunk_cb,
+                          soup_queue_read_done_cb,
+                          soup_queue_error_cb);
 }
 
 static void
 start_request (SoupContext *ctx, SoupMessage *req)
 {
        SoupSocket *sock;
-       gboolean overwrt; 
 
        sock = soup_message_get_socket (req);
        if (!sock) {    /* FIXME */
@@ -478,26 +446,10 @@ start_request (SoupContext *ctx, SoupMessage *req)
                return;
        }
 
-       req->priv->write_tag = 
-               soup_transfer_write_simple (sock,
-                                           soup_get_request_header (req),
-                                           &req->request,
-                                           soup_queue_write_done_cb,
-                                           soup_queue_error_cb,
-                                           req);
-
-       overwrt = req->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS;
-
-       req->priv->read_tag = 
-               soup_transfer_read (sock,
-                                   overwrt,
-                                   soup_queue_read_headers_cb,
-                                   soup_queue_read_chunk_cb,
-                                   soup_queue_read_done_cb,
-                                   soup_queue_error_cb,
-                                   req);
-
-       req->status = SOUP_STATUS_SENDING_REQUEST;
+       soup_message_write_simple (req, &req->request,
+                                  soup_queue_get_request_header_cb,
+                                  soup_queue_write_done_cb,
+                                  soup_queue_error_cb);
 }
 
 static void
@@ -667,13 +619,13 @@ soup_idle_handle_new_requests (gpointer unused)
        for (; req; req = soup_queue_next_request ()) {
                SoupContext *ctx, *proxy;
 
-               if (req->status != SOUP_STATUS_QUEUED)
+               if (req->priv->status != SOUP_MESSAGE_STATUS_QUEUED)
                        continue;
 
                proxy = soup_get_proxy ();
                ctx = proxy ? proxy : req->context;
 
-               req->status = SOUP_STATUS_CONNECTING;
+               req->priv->status = SOUP_MESSAGE_STATUS_CONNECTING;
 
                conn = soup_message_get_connection (req);
                if (conn && soup_connection_is_connected (conn))
@@ -726,7 +678,7 @@ soup_queue_message (SoupMessage    *req,
                return;
        }
 
-       if (req->status != SOUP_STATUS_IDLE)
+       if (req->priv->status != SOUP_MESSAGE_STATUS_IDLE)
                soup_message_cleanup (req);
 
        switch (req->response.owner) {
@@ -759,7 +711,7 @@ soup_queue_message (SoupMessage    *req,
                req->errorphrase = NULL;
        }
 
-       req->status = SOUP_STATUS_QUEUED;
+       req->priv->status = SOUP_MESSAGE_STATUS_QUEUED;
 
        soup_queue_add_request (req);
 
index 98ccbfa..43642f5 100644 (file)
@@ -15,8 +15,8 @@
 #include <unistd.h>
 
 #include "soup-server-message.h"
+#include "soup-message-private.h"
 #include "soup-private.h"
-#include "soup-transfer.h"
 
 struct SoupServerMessagePrivate {
        SoupServer *server;
@@ -145,7 +145,7 @@ soup_server_message_start (SoupServerMessage *smsg)
 
        smsg->priv->started = TRUE;
 
-       soup_transfer_write_unpause (SOUP_MESSAGE (smsg)->priv->write_tag);
+       soup_message_write_unpause (SOUP_MESSAGE (smsg));
 }
 
 gboolean
@@ -181,7 +181,7 @@ soup_server_message_add_chunk (SoupServerMessage *smsg,
 
        smsg->priv->chunks = g_slist_append (smsg->priv->chunks, buf);
 
-       soup_transfer_write_unpause (SOUP_MESSAGE (smsg)->priv->write_tag);
+       soup_message_write_unpause (SOUP_MESSAGE (smsg));
 }
 
 SoupDataBuffer *
@@ -208,7 +208,7 @@ soup_server_message_finish  (SoupServerMessage *smsg)
        smsg->priv->started = TRUE;
        smsg->priv->finished = TRUE;
 
-       soup_transfer_write_unpause (SOUP_MESSAGE (smsg)->priv->write_tag);
+       soup_message_write_unpause (SOUP_MESSAGE (smsg));
 }
 
 gboolean
index f9e2b65..5798960 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <libsoup/soup-message.h>
 #include <libsoup/soup-server.h>
-#include <libsoup/soup-transfer.h>
 
 #define SOUP_TYPE_SERVER_MESSAGE            (soup_server_message_get_type ())
 #define SOUP_SERVER_MESSAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SERVER_MESSAGE, SoupServerMessage))
index 6c678d3..6441886 100644 (file)
@@ -21,8 +21,8 @@
 #include "soup-server.h"
 #include "soup-headers.h"
 #include "soup-private.h"
+#include "soup-message-private.h"
 #include "soup-ssl.h"
-#include "soup-transfer.h"
 
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class;
@@ -181,54 +181,57 @@ soup_server_get_protocol (SoupServer *server)
 static void start_request (SoupServer *, SoupSocket *);
 
 static void
-error_cb (gboolean body_started, gpointer msg)
+error_cb (SoupMessage *msg)
 {
        g_object_unref (msg);
 }
 
 static void
-write_done_cb (gpointer user_data)
+write_done_cb (SoupMessage *msg)
 {
-       SoupServerMessage *smsg = user_data;
-       SoupMessage *msg = user_data;
+       SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (msg);
 
-       soup_transfer_write_unref (msg->priv->write_tag);
-       msg->priv->write_tag = 0;
-
-       start_request (soup_server_message_get_server (smsg),
-                      soup_message_get_socket (msg));
+       if (soup_message_is_keepalive (msg)) {
+               /* Start a new request */
+               start_request (soup_server_message_get_server (smsg),
+                              soup_message_get_socket (msg));
+       }
        g_object_unref (msg);
 }
 
 static void
-write_header (char *key, char *value, GString *ret)
+write_header (gpointer name, gpointer value, gpointer headers)
 {
-       g_string_sprintfa (ret, "%s: %s\r\n", key, value);
+       g_string_append_printf (headers, "%s: %s\r\n",
+                               (char *)name, (char *)value);
 }
 
-static GString *
-get_response_header (SoupMessage          *req,
-                    SoupTransferEncoding  encoding)
+static void
+get_response_header_cb (SoupMessage *msg,
+                       GString     *headers)
 {
-       GString *ret = g_string_new (NULL);
+       SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (msg);
+       SoupTransferEncoding encoding =
+               soup_server_message_get_encoding (smsg);
 
-       g_string_sprintfa (ret, "HTTP/1.1 %d %s\r\n",
-                          req->errorcode, req->errorphrase);
+       if (!soup_server_message_is_started (smsg)) {
+               soup_message_write_pause (msg);
+               return;
+       }
 
-       if (encoding == SOUP_TRANSFER_CONTENT_LENGTH)
-               g_string_sprintfa (ret,
-                                  "Content-Length: %d\r\n",
-                                  req->response.length);
-       else if (encoding == SOUP_TRANSFER_CHUNKED)
-               g_string_append (ret, "Transfer-Encoding: chunked\r\n");
+       g_string_append_printf (headers, "HTTP/1.1 %d %s\r\n",
+                               msg->errorcode, msg->errorphrase);
 
-       soup_message_foreach_header (req->response_headers,
-                                    (GHFunc) write_header,
-                                    ret);
+       if (encoding == SOUP_TRANSFER_CONTENT_LENGTH) {
+               g_string_append_printf (headers, "Content-Length: %d\r\n",
+                                       msg->response.length);
+       } else if (encoding == SOUP_TRANSFER_CHUNKED)
+               g_string_append (headers, "Transfer-Encoding: chunked\r\n");
 
-       g_string_append (ret, "\r\n");
+       soup_message_foreach_header (msg->response_headers,
+                                    write_header, headers);
 
-       return ret;
+       g_string_append (headers, "\r\n");
 }
 
 static inline void
@@ -250,36 +253,25 @@ set_response_error (SoupMessage    *req,
 static void
 issue_bad_request (SoupMessage *msg)
 {
-       GString *header;
+       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));
 
-       if (msg->priv->read_tag) {
-               soup_transfer_read_cancel (msg->priv->read_tag);
-               msg->priv->read_tag = 0;
-       }
-
-       header = get_response_header (msg, SOUP_TRANSFER_CONTENT_LENGTH);
-
-       msg->priv->write_tag =
-               soup_transfer_write_simple (soup_message_get_socket (msg),
-                                           header,
-                                           &msg->response,
-                                           write_done_cb,
-                                           error_cb,
-                                           msg);
+       soup_message_write_simple (msg, &msg->response,
+                                  get_response_header_cb,
+                                  write_done_cb, error_cb);
 }
 
 static void
-read_headers_cb (char                 *headers,
+read_headers_cb (SoupMessage          *msg,
+                char                 *headers,
                 guint                 headers_len,
                 SoupTransferEncoding *encoding,
-                int                  *content_len,
-                gpointer              user_data)
+                int                  *content_len)
 {
-       SoupMessage *msg = user_data;
        SoupContext *ctx;
        char *req_path = NULL, *url;
        const char *length, *enc, *req_host;
@@ -379,7 +371,6 @@ call_handler (SoupMessage *req)
        server = soup_server_message_get_server (SOUP_SERVER_MESSAGE (req));
        handler_path = soup_context_get_uri (req->context)->path;
 
-       req->status = SOUP_STATUS_FINISHED;
        hand = soup_server_get_handler (server, handler_path);
        if (!hand) {
                set_response_error (req, SOUP_ERROR_NOT_FOUND, NULL, NULL);
@@ -443,30 +434,10 @@ call_handler (SoupMessage *req)
                soup_server_auth_free (auth);
 }
 
-static void
-get_header_cb (GString  **out_hdr,
-              gpointer   user_data)
+static gboolean
+get_chunk_cb (SoupMessage *msg, SoupDataBuffer *out_next)
 {
-       SoupMessage *msg = user_data;
-       SoupServerMessage *smsg = user_data;
-       SoupTransferEncoding encoding;
-
-       if (soup_server_message_is_started (smsg)) {
-               if (msg->priv->http_version == SOUP_HTTP_1_0)
-                       encoding = SOUP_TRANSFER_UNKNOWN;
-               else
-                       encoding = SOUP_TRANSFER_CHUNKED;
-
-               *out_hdr = get_response_header (msg, encoding);
-       } else
-               soup_transfer_write_pause (msg->priv->write_tag);
-}
-
-static SoupTransferDone
-get_chunk_cb (SoupDataBuffer *out_next, gpointer user_data)
-{
-       SoupMessage *msg = user_data;
-       SoupServerMessage *smsg = user_data;
+       SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (msg);
        SoupDataBuffer *next;
 
        next = soup_server_message_get_chunk (smsg);
@@ -476,28 +447,22 @@ get_chunk_cb (SoupDataBuffer *out_next, gpointer user_data)
                out_next->length = next->length;
                g_free (next);
 
-               return SOUP_TRANSFER_CONTINUE;
-       } else if (soup_server_message_is_finished (smsg)) {
-               return SOUP_TRANSFER_END;
-       } else {
-               soup_transfer_write_pause (msg->priv->write_tag);
-               return SOUP_TRANSFER_CONTINUE;
+               return TRUE;
        }
+
+       if (!soup_server_message_is_finished (smsg))
+               soup_message_write_pause (msg);
+       return FALSE;
 }
 
 static void
-read_done_cb (char     *body,
-             guint     len,
-             gpointer  user_data)
+read_done_cb (SoupMessage *req,
+             char        *body,
+             guint        len)
 {
-       SoupMessage *req = user_data;
-       SoupServerMessage *smsg = user_data;
-       SoupSocket *server_sock = soup_message_get_socket (req);
+       SoupServerMessage *smsg = SOUP_SERVER_MESSAGE (req);
        SoupTransferEncoding encoding;
 
-       soup_transfer_read_unref (req->priv->read_tag);
-       req->priv->read_tag = 0;
-
        req->request.owner = SOUP_BUFFER_SYSTEM_OWNED;
        req->request.body = body;
        req->request.length = len;
@@ -506,28 +471,14 @@ read_done_cb (char     *body,
 
        encoding = soup_server_message_get_encoding (smsg);
        if (encoding == SOUP_TRANSFER_CONTENT_LENGTH) {
-               GString *header;
-               header = get_response_header (req, encoding);
-               req->priv->write_tag =
-                       soup_transfer_write_simple (server_sock,
-                                                   header,
-                                                   &req->response,
-                                                   write_done_cb,
-                                                   error_cb,
-                                                   req);
+               soup_message_write_simple (req, &req->response,
+                                          get_response_header_cb,
+                                          write_done_cb, error_cb);
+               soup_server_message_start (smsg);
        } else {
-               req->priv->write_tag =
-                       soup_transfer_write (server_sock,
-                                            encoding,
-                                            get_header_cb,
-                                            get_chunk_cb,
-                                            write_done_cb,
-                                            error_cb,
-                                            req);
-
-               /* Pause write until soup_server_message_start() */
-               if (!soup_server_message_is_started (smsg))
-                       soup_transfer_write_pause (req->priv->write_tag);
+               soup_message_write (req, encoding,
+                                   get_response_header_cb, get_chunk_cb,
+                                   write_done_cb, error_cb);
        }
 
        return;
@@ -540,14 +491,8 @@ start_request (SoupServer *server, SoupSocket *server_sock)
 
        /* Listen for another request on this connection */
        msg = (SoupMessage *)soup_server_message_new (server, server_sock);
-       msg->priv->read_tag =
-               soup_transfer_read (server_sock,
-                                   FALSE,
-                                   read_headers_cb,
-                                   NULL,
-                                   read_done_cb,
-                                   error_cb,
-                                   msg);
+       soup_message_read (msg, read_headers_cb, NULL,
+                          read_done_cb, error_cb);
 }
 
 static void
diff --git a/libsoup/soup-transfer.c b/libsoup/soup-transfer.c
deleted file mode 100644 (file)
index 16db62a..0000000
+++ /dev/null
@@ -1,816 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * soup-queue.c: Asyncronous Callback-based HTTP Request Queue.
- *
- * Authors:
- *      Alex Graveley (alex@ximian.com)
- *
- * Copyright (C) 2000-2002, Ximian, Inc.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <ctype.h>
-#include <glib.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-
-#include "soup-transfer.h"
-#include "soup-private.h"
-
-typedef enum {
-       SOUP_READER_STATE_HEADERS,
-       SOUP_READER_STATE_READ_TO_EOF,
-       SOUP_READER_STATE_CONTENT_LENGTH,
-       SOUP_READER_STATE_CHUNK_SIZE,
-       SOUP_READER_STATE_CHUNK,
-       SOUP_READER_STATE_BETWEEN_CHUNKS,
-       SOUP_READER_STATE_TRAILERS
-} SoupReaderState;
-
-struct _SoupReader {
-        int                    ref_count;
-
-       SoupSocket            *sock;
-       guint                  idle_tag;
-       guint                  read_tag;
-       guint                  err_tag;
-
-       SoupReaderState        state;
-       GByteArray            *body_buf;
-       GByteArray            *meta_buf;
-
-       SoupTransferEncoding   encoding;
-       guint                  read_length;
-
-       SoupReadHeadersDoneFn  headers_done_cb;
-       SoupReadChunkFn        read_chunk_cb;
-       SoupReadDoneFn         read_done_cb;
-       SoupReadErrorFn        error_cb;
-       gpointer               user_data;
-};
-
-/* Stops reading and releases soup-transfer's ref. */
-static void
-soup_transfer_read_stop (SoupReader *r)
-{
-       if (!r->err_tag)
-               return;
-
-       g_signal_handler_disconnect (r->sock, r->read_tag);
-       r->read_tag = 0;
-       g_signal_handler_disconnect (r->sock, r->err_tag);
-       r->err_tag = 0;
-
-       if (r->idle_tag) {
-               g_source_remove (r->idle_tag);
-               r->idle_tag = 0;
-       }
-
-       soup_transfer_read_unref (r);
-}
-
-void
-soup_transfer_read_ref (SoupReader *r)
-{
-       r->ref_count++;
-}
-
-gboolean
-soup_transfer_read_unref (SoupReader *r)
-{
-       r->ref_count--;
-       if (r->ref_count)
-               return TRUE;
-
-       soup_transfer_read_stop (r);
-       if (r->body_buf)
-               g_byte_array_free (r->body_buf, TRUE);
-       if (r->meta_buf)
-               g_byte_array_free (r->meta_buf, TRUE);
-       g_object_unref (r->sock);
-       g_free (r);
-       return FALSE;
-}
-
-void
-soup_transfer_read_cancel (SoupReader *r)
-{
-       soup_transfer_read_stop (r);
-       soup_transfer_read_unref (r);
-}
-
-void 
-soup_transfer_read_set_callbacks (SoupReader             *r,
-                                 SoupReadHeadersDoneFn   headers_done_cb,
-                                 SoupReadChunkFn         read_chunk_cb,
-                                 SoupReadDoneFn          read_done_cb,
-                                 SoupReadErrorFn         error_cb,
-                                 gpointer                user_data)
-{
-       g_assert (read_done_cb && error_cb);
-
-       r->headers_done_cb = headers_done_cb;
-       r->read_chunk_cb = read_chunk_cb;
-       r->read_done_cb = read_done_cb;
-       r->error_cb = error_cb;
-
-       r->user_data = user_data;
-}
-
-static void
-issue_final_callback (SoupReader *r)
-{
-       char *body;
-       guint len;
-
-       if (r->body_buf) {
-               /* 
-                * Null terminate. FIXME
-                */
-               g_byte_array_append (r->body_buf, "\0", 1);
-
-               body = r->body_buf->data;
-               len = r->body_buf->len - 1;
-               g_byte_array_free (r->body_buf, FALSE);
-               r->body_buf = NULL;
-       } else {
-               body = NULL;
-               len = 0;
-       }
-
-       soup_transfer_read_ref (r);
-       soup_transfer_read_stop (r);
-
-       (*r->read_done_cb) (body, len, r->user_data);
-       soup_transfer_read_unref (r);
-}
-
-static void
-reader_disconnected (SoupSocket *sock, SoupReader *r)
-{
-       soup_transfer_read_ref (r);
-       soup_transfer_read_stop (r);
-
-       /*
-        * Closing the connection to signify EOF is valid if content length is
-        * unknown, but only if headers have been sent.
-        */
-       if (r->state == SOUP_READER_STATE_READ_TO_EOF)
-               issue_final_callback (r);
-       else {
-               (*r->error_cb) (r->state > SOUP_READER_STATE_HEADERS,
-                               r->user_data);
-       }
-
-       soup_transfer_read_unref (r);
-}
-
-static gboolean
-soup_reader_read_metadata (SoupReader *r, const char *boundary, int boundary_len)
-{
-       SoupSocketIOStatus status;
-       char read_buf[RESPONSE_BLOCK_SIZE];
-       guint nread;
-       gboolean done;
-
-       do {
-               status = soup_socket_read_until (r->sock, read_buf,
-                                                sizeof (read_buf),
-                                                boundary, boundary_len,
-                                                &nread, &done);
-               switch (status) {
-               case SOUP_SOCKET_OK:
-                       g_byte_array_append (r->meta_buf, read_buf, nread);
-                       break;
-
-               case SOUP_SOCKET_ERROR:
-               case SOUP_SOCKET_EOF:
-                       reader_disconnected (r->sock, r);
-                       return FALSE;
-
-               case SOUP_SOCKET_WOULD_BLOCK:
-                       return FALSE;
-               }
-       } while (!done);
-
-       return TRUE;
-}
-
-static gboolean
-soup_reader_read_body_chunk (SoupReader *r, guint *size)
-{
-       SoupSocketIOStatus status;
-       char read_buf[RESPONSE_BLOCK_SIZE];
-       guint nread, len = sizeof (read_buf);
-
-       while (!size || *size > 0) {
-               if (size)
-                       len = MIN (len, *size);
-
-               status = soup_socket_read (r->sock, read_buf, len, &nread);
-
-               switch (status) {
-               case SOUP_SOCKET_OK:
-                       if (!nread)
-                               break;
-
-                       if (r->read_chunk_cb) {
-                               soup_transfer_read_ref (r);
-                               r->read_chunk_cb (read_buf, nread,
-                                                 r->user_data);
-                               if (!soup_transfer_read_unref (r))
-                                       return FALSE;
-                       }
-                       if (r->body_buf)
-                               g_byte_array_append (r->body_buf, read_buf, nread);
-                       if (size)
-                               *size -= nread;
-                       break;
-
-               case SOUP_SOCKET_EOF:
-                       if (!size)
-                               return TRUE;
-                       /* else fall through */
-
-               case SOUP_SOCKET_ERROR:
-                       reader_disconnected (r->sock, r);
-                       return FALSE;
-
-               case SOUP_SOCKET_WOULD_BLOCK:
-                       return FALSE;
-               }
-       }
-
-       return TRUE;
-}
-
-#define SOUP_TRANSFER_EOL     "\r\n"
-#define SOUP_TRANSFER_EOL_LEN 2
-
-#define SOUP_TRANSFER_DOUBLE_EOL     "\r\n\r\n"
-#define SOUP_TRANSFER_DOUBLE_EOL_LEN 4
-
-static void
-reader_read (SoupSocket *sock, SoupReader *r)
-{
-       while (1) {
-               switch (r->state) {
-               case SOUP_READER_STATE_HEADERS:
-                       if (!soup_reader_read_metadata (
-                                   r, SOUP_TRANSFER_DOUBLE_EOL,
-                                   SOUP_TRANSFER_DOUBLE_EOL_LEN))
-                               return;
-
-                       r->meta_buf->len -= SOUP_TRANSFER_DOUBLE_EOL_LEN;
-                       if (r->headers_done_cb) {
-                               soup_transfer_read_ref (r);
-                               (*r->headers_done_cb) (r->meta_buf->data,
-                                                      r->meta_buf->len,
-                                                      &r->encoding, 
-                                                      &r->read_length, 
-                                                      r->user_data);
-                               if (!soup_transfer_read_unref (r))
-                                       return;
-                       }
-                       g_byte_array_set_size (r->meta_buf, 0);
-
-                       switch (r->encoding) {
-                       case SOUP_TRANSFER_UNKNOWN:
-                               r->state = SOUP_READER_STATE_READ_TO_EOF;
-                               break;
-                       case SOUP_TRANSFER_CONTENT_LENGTH:
-                               r->state = SOUP_READER_STATE_CONTENT_LENGTH;
-                               break;
-                       case SOUP_TRANSFER_CHUNKED:
-                               r->state = SOUP_READER_STATE_CHUNK_SIZE;
-                               break;
-                       }
-                       break;
-
-               case SOUP_READER_STATE_READ_TO_EOF:
-                       if (!soup_reader_read_body_chunk (r, NULL))
-                               return;
-
-                       goto done;
-                       break;
-
-               case SOUP_READER_STATE_CONTENT_LENGTH:
-                       if (!soup_reader_read_body_chunk (r, &r->read_length))
-                               return;
-
-                       goto done;
-                       break;
-
-               case SOUP_READER_STATE_CHUNK_SIZE:
-                       if (!soup_reader_read_metadata (r, SOUP_TRANSFER_EOL,
-                                                       SOUP_TRANSFER_EOL_LEN))
-                               return;
-
-                       r->read_length = strtoul (r->meta_buf->data, NULL, 16);
-                       g_byte_array_set_size (r->meta_buf, 0);
-
-                       if (r->read_length > 0)
-                               r->state = SOUP_READER_STATE_CHUNK;
-                       else
-                               r->state = SOUP_READER_STATE_TRAILERS;
-                       break;
-
-               case SOUP_READER_STATE_CHUNK:
-                       if (!soup_reader_read_body_chunk (r, &r->read_length))
-                               return;
-
-                       r->state = SOUP_READER_STATE_BETWEEN_CHUNKS;
-                       break;
-
-               case SOUP_READER_STATE_BETWEEN_CHUNKS:
-                       if (!soup_reader_read_metadata (r, SOUP_TRANSFER_EOL,
-                                                       SOUP_TRANSFER_EOL_LEN))
-                               return;
-
-                       g_byte_array_set_size (r->meta_buf, 0);
-                       r->state = SOUP_READER_STATE_CHUNK_SIZE;
-                       break;
-
-               case SOUP_READER_STATE_TRAILERS:
-                       if (!soup_reader_read_metadata (r, SOUP_TRANSFER_EOL,
-                                                       SOUP_TRANSFER_EOL_LEN))
-                               return;
-
-                       if (r->meta_buf->len == SOUP_TRANSFER_EOL_LEN)
-                               goto done;
-
-                       /* FIXME: process trailers */
-                       g_byte_array_set_size (r->meta_buf, 0);
-                       break;
-
-               }
-       }
-
- done:
-       issue_final_callback (r);
-}
-
-static gboolean
-idle_read (gpointer user_data)
-{
-       SoupReader *r = user_data;
-
-       r->idle_tag = 0;
-       reader_read (r->sock, r);
-       return FALSE;
-}
-
-/**
- * soup_transfer_read:
- * @chan: the iochannel to read from
- * @overwrite_chunks: if %TRUE, body chunks will not be preserved after
- * chunk callbacks.
- * @headers_done_cb: (optional) callback to call after headers have
- * been read.
- * @read_chunk_cb: (optional) callback to call as body data is being read
- * @read_done_cb: (mandatory) callback to call when the body has been
- * completely read
- * @error_cb: (mandatory) callback to call when an error occurs
- * @user_data: data to pass to the callbacks.
- *
- * Attempts to read a single HTTP message from @chan.
- *
- * Unless the caller calls soup_transfer_read_cancel(), either
- * @read_done_cb or @read_error_cb will eventually be called.
- *
- * Return value: a #SoupReader, which must eventually be freed by
- * calling either soup_transfer_read_unref() or
- * soup_transfer_read_cancel().
- **/
-SoupReader *
-soup_transfer_read (SoupSocket            *sock,
-                   gboolean               overwrite_chunks,
-                   SoupReadHeadersDoneFn  headers_done_cb,
-                   SoupReadChunkFn        read_chunk_cb,
-                   SoupReadDoneFn         read_done_cb,
-                   SoupReadErrorFn        error_cb,
-                   gpointer               user_data)
-{
-       SoupReader *reader;
-
-       g_assert (read_done_cb && error_cb);
-
-       reader = g_new0 (SoupReader, 1);
-       reader->sock = g_object_ref (sock);
-       reader->headers_done_cb = headers_done_cb;
-       reader->read_chunk_cb = read_chunk_cb;
-       reader->read_done_cb = read_done_cb;
-       reader->error_cb = error_cb;
-       reader->user_data = user_data;
-       reader->encoding = SOUP_TRANSFER_UNKNOWN;
-
-       reader->meta_buf = g_byte_array_new ();
-       if (!overwrite_chunks)
-               reader->body_buf = g_byte_array_new ();
-
-       reader->read_tag =
-               g_signal_connect (sock, "readable",
-                                 G_CALLBACK (reader_read), reader);
-
-       reader->err_tag =
-               g_signal_connect (sock, "disconnected",
-                                 G_CALLBACK (reader_disconnected), reader);
-
-       reader->idle_tag = g_idle_add (idle_read, reader);
-
-       /* Initial ref_count is 2: one reference owned by
-        * soup-transfer and one by the caller.
-        */
-       reader->ref_count = 2;
-
-       return reader;
-}
-
-
-struct _SoupWriter {
-        int                     ref_count;
-
-       SoupSocket             *sock;
-       guint                   idle_tag;
-       guint                   write_tag;
-       guint                   err_tag;
-
-       SoupTransferEncoding    encoding;
-       GByteArray             *write_buf;
-
-       gboolean                headers_done;
-       int                     chunk_cnt;
-
-       SoupWriteGetHeaderFn    get_header_cb;
-       SoupWriteGetChunkFn     get_chunk_cb;
-       SoupWriteDoneFn         write_done_cb;
-       SoupWriteErrorFn        error_cb;
-       gpointer                user_data;
-};
-
-static void
-soup_transfer_write_stop (SoupWriter *w)
-{
-       if (!w->err_tag)
-               return;
-
-       g_signal_handler_disconnect (w->sock, w->err_tag);
-       w->err_tag = 0;
-
-       if (w->write_tag) {
-               g_signal_handler_disconnect (w->sock, w->write_tag);
-               w->write_tag = 0;
-       }
-
-       if (w->idle_tag) {
-               g_source_remove (w->idle_tag);
-               w->idle_tag = 0;
-       }
-
-       /* Give up soup-transfer's ref */
-       soup_transfer_write_unref (w);
-}
-
-void
-soup_transfer_write_ref (SoupWriter *w)
-{
-       w->ref_count++;
-}
-
-gboolean
-soup_transfer_write_unref (SoupWriter *w)
-{
-       w->ref_count--;
-       if (w->ref_count)
-               return TRUE;
-
-       soup_transfer_write_stop (w);
-       g_byte_array_free (w->write_buf, TRUE);
-       g_object_unref (w->sock);
-       g_free (w);
-       return FALSE;
-}
-
-void
-soup_transfer_write_cancel (SoupWriter *w)
-{
-       soup_transfer_write_stop (w);
-       soup_transfer_write_unref (w);
-}
-
-static void
-writer_disconnected (SoupSocket *sock, SoupWriter *w)
-{
-       soup_transfer_write_stop (w);
-       (*w->error_cb) (w->headers_done, w->user_data);
-}
-
-static gboolean 
-get_header (SoupWriter *w)
-{
-       GString *header = NULL;
-
-       (*w->get_header_cb) (&header, w->user_data);
-
-       if (!header)
-               return FALSE;
-
-       g_byte_array_append (w->write_buf, header->str, header->len);
-       g_string_free (header, TRUE);
-
-       w->get_header_cb = NULL;
-       return TRUE;
-}
-
-static void
-write_chunk_sep (GByteArray *arr, gint len, gint chunk_cnt)
-{
-       gchar *hex;
-       gchar *end = "0\r\n\r\n";
-
-       /*
-        * Only prefix the chunk length with a \r\n if its not the first chunk
-        */
-       if (chunk_cnt)
-               g_byte_array_append (arr, "\r\n", 2);
-
-       if (len) {
-               hex = g_strdup_printf ("%x\r\n", len);
-               g_byte_array_append (arr, hex, strlen (hex));
-               g_free (hex);
-       } else
-               g_byte_array_append (arr, end, strlen (end));
-}
-
-static void
-get_next_chunk (SoupWriter *w)
-{
-       SoupTransferStatus ret = SOUP_TRANSFER_END;
-       SoupDataBuffer buf = { 0 , NULL, 0 };
-
-       ret = (*w->get_chunk_cb) (&buf, w->user_data);
-
-       if (buf.length) {
-               if (w->encoding == SOUP_TRANSFER_CHUNKED)
-                       write_chunk_sep (w->write_buf, 
-                                        buf.length, 
-                                        w->chunk_cnt++);
-
-               g_byte_array_append (w->write_buf, buf.body, buf.length);
-
-               if (buf.owner == SOUP_BUFFER_SYSTEM_OWNED)
-                       g_free (buf.body);
-       }
-
-       if (ret == SOUP_TRANSFER_END) {
-               if (w->encoding == SOUP_TRANSFER_CHUNKED)
-                       write_chunk_sep (w->write_buf, 0, w->chunk_cnt);
-
-               w->get_chunk_cb = NULL;
-       }
-}
-
-static void
-writer_write (SoupSocket *sock, SoupWriter *w)
-{
-       SoupSocketIOStatus status;
-       guint bytes_written = 0;
-
-       /* Get the header and first data chunk (if available). */
-       if (w->get_header_cb) {
-               soup_transfer_write_ref (w);
-
-               if (!get_header (w)) {
-                       soup_transfer_write_unref (w);
-                       return;
-               }
-
-               if (w->get_chunk_cb)
-                       get_next_chunk (w);
-
-               if (!soup_transfer_write_unref (w))
-                       return;
-       }
-
- WRITE_AGAIN:
-       while (w->write_buf->len) {
-               status = soup_socket_write (sock, w->write_buf->data,
-                                           w->write_buf->len, &bytes_written);
-
-               switch (status) {
-               case SOUP_SOCKET_EOF:
-               case SOUP_SOCKET_ERROR:
-                       writer_disconnected (sock, w);
-                       return;
-
-               case SOUP_SOCKET_WOULD_BLOCK:
-                       return;
-
-               case SOUP_SOCKET_OK:
-                       memmove (w->write_buf->data,
-                                w->write_buf->data + bytes_written,
-                                w->write_buf->len - bytes_written);
-                       g_byte_array_set_size (w->write_buf,
-                                              w->write_buf->len - bytes_written);
-                       break;
-               }
-       }
-
-       /* When we exit the above block, we are certain that the headers have
-        * been written.  
-        */
-       w->headers_done = TRUE;
-
-       /* Get the next data chunk and try again, or quit if paused. */
-       if (w->get_chunk_cb) {
-               soup_transfer_write_ref (w);
-               get_next_chunk (w);
-               if (!soup_transfer_write_unref (w))
-                       return;
-
-               if (!w->write_tag)
-                       return;
-
-               goto WRITE_AGAIN;
-       }
-
-       soup_transfer_write_ref (w);
-       soup_transfer_write_stop (w);
-       (*w->write_done_cb) (w->user_data);
-       soup_transfer_write_unref (w);
-}
-
-static gboolean
-idle_write (gpointer user_data)
-{
-       SoupWriter *w = user_data;
-
-       w->idle_tag = 0;
-       writer_write (w->sock, w);
-       return FALSE;
-}
-
-static SoupWriter *
-create_writer (SoupSocket             *sock,
-              SoupTransferEncoding    encoding,
-              SoupWriteDoneFn         write_done_cb,
-              SoupWriteErrorFn        error_cb,
-              gpointer                user_data)
-{
-       SoupWriter *writer;
-
-       g_assert (write_done_cb && error_cb);
-
-       writer = g_new0 (SoupWriter, 1);
-       writer->sock          = g_object_ref (sock);
-       writer->encoding      = encoding;
-       writer->write_buf     = g_byte_array_new ();
-       writer->write_done_cb = write_done_cb;
-       writer->error_cb      = error_cb;
-       writer->user_data     = user_data;
-
-       writer->write_tag =
-               g_signal_connect (sock, "writable",
-                                 G_CALLBACK (writer_write), writer);
-
-       writer->err_tag =
-               g_signal_connect (sock, "disconnected",
-                                 G_CALLBACK (writer_disconnected), writer);
-
-       writer->idle_tag = g_idle_add (idle_write, writer);
-
-       /* As with SoupReader, one reference is owned by soup-transfer
-        * and one by the caller.
-        */
-       writer->ref_count = 2;
-
-       return writer;
-}
-
-/**
- * soup_transfer_write_simple:
- * @sock: the socket to write to
- * @header: message headers (including trailing blank line)
- * @src: buffer to write
- * @write_done_cb: (mandatory) callback to call when the body has been
- * completely written
- * @error_cb: (mandatory) callback to call when an error occurs
- * @user_data: data to pass to the callbacks.
- *
- * Attempts to write a single HTTP message to @sock using identity
- * encoding and Content-Length.
- *
- * Unless the caller calls soup_transfer_write_cancel(), either
- * @write_done_cb or @write_error_cb will eventually be called.
- *
- * Return value: a #SoupWriter, which must eventually be freed by
- * calling either soup_transfer_write_unref() or
- * soup_transfer_write_cancel().
- **/
-SoupWriter *
-soup_transfer_write_simple (SoupSocket             *sock,
-                           GString                *header,
-                           const SoupDataBuffer   *src,
-                           SoupWriteDoneFn         write_done_cb,
-                           SoupWriteErrorFn        error_cb,
-                           gpointer                user_data)
-{
-       SoupWriter *writer;
-
-       writer = create_writer (sock,
-                               SOUP_TRANSFER_CONTENT_LENGTH,
-                               write_done_cb,
-                               error_cb,
-                               user_data);
-
-       if (header) {
-               g_byte_array_append (writer->write_buf, 
-                                    header->str, 
-                                    header->len);
-               g_string_free (header, TRUE);
-       }
-
-       if (src && src->length)
-               g_byte_array_append (writer->write_buf, 
-                                    src->body, 
-                                    src->length);
-
-       return writer;
-}
-
-/**
- * soup_transfer_write:
- * @sock: the socket to write to
- * @encoding: HTTP encoding mechanism to use.
- * @get_header_cb: (mandatory) callback to call to get message headers
- * @get_chunk_cb: (optional) callback to call to get body chunks
- * @write_done_cb: (mandatory) callback to call when the body has been
- * completely written
- * @error_cb: (mandatory) callback to call when an error occurs
- * @user_data: data to pass to the callbacks.
- *
- * Attempts to write a single HTTP message to @sock using @encoding.
- *
- * Unless the caller calls soup_transfer_write_cancel(), either
- * @write_done_cb or @write_error_cb will eventually be called.
- *
- * Return value: a #SoupWriter, which must eventually be freed by
- * calling either soup_transfer_write_unref() or
- * soup_transfer_write_cancel().
- **/
-SoupWriter *
-soup_transfer_write (SoupSocket             *sock,
-                    SoupTransferEncoding    encoding,
-                    SoupWriteGetHeaderFn    get_header_cb,
-                    SoupWriteGetChunkFn     get_chunk_cb,
-                    SoupWriteDoneFn         write_done_cb,
-                    SoupWriteErrorFn        error_cb,
-                    gpointer                user_data)
-{
-       SoupWriter *writer;
-
-       writer = create_writer (sock,
-                               encoding,
-                               write_done_cb,
-                               error_cb,
-                               user_data);
-
-       writer->get_header_cb = get_header_cb;
-       writer->get_chunk_cb = get_chunk_cb;
-
-       return writer;
-}
-
-void  
-soup_transfer_write_pause (SoupWriter *w)
-{
-       g_return_if_fail (w != NULL);
-
-       if (w->write_tag) {
-               g_signal_handler_disconnect (w->sock, w->write_tag);
-               w->write_tag = 0;
-       }
-       if (w->idle_tag) {
-               g_source_remove (w->idle_tag);
-               w->idle_tag = 0;
-       }
-}
-
-void  
-soup_transfer_write_unpause (SoupWriter *w)
-{
-       g_return_if_fail (w != NULL);
-
-       if (!w->write_tag) {
-               w->write_tag =
-                       g_signal_connect (w->sock, "writable",
-                                         G_CALLBACK (writer_write), w);
-       }
-       if (!w->idle_tag)
-               w->idle_tag = g_idle_add (idle_write, w);
-}
diff --git a/libsoup/soup-transfer.h b/libsoup/soup-transfer.h
deleted file mode 100644 (file)
index 068529a..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * soup-queue.c: Asyncronous Callback-based HTTP Request Queue.
- *
- * Authors:
- *      Alex Graveley (alex@ximian.com)
- *
- * Copyright (C) 2000-2002, Ximian, Inc.
- */
-
-#ifndef SOUP_TRANSFER_H
-#define SOUP_TRANSFER_H 1
-
-#include <glib.h>
-
-#include <libsoup/soup-message.h>
-
-typedef enum {
-       SOUP_TRANSFER_END = 0,
-       SOUP_TRANSFER_CONTINUE,
-} SoupTransferDone;
-
-typedef enum {
-       SOUP_TRANSFER_UNKNOWN = 0,
-       SOUP_TRANSFER_CHUNKED,
-       SOUP_TRANSFER_CONTENT_LENGTH,
-} SoupTransferEncoding;
-
-typedef struct _SoupReader SoupReader;
-typedef struct _SoupWriter SoupWriter;
-
-typedef void (*SoupReadHeadersDoneFn) (char                 *headers,
-                                      guint                 header_len,
-                                      SoupTransferEncoding *encoding,
-                                      int                  *content_len,
-                                      gpointer              user_data);
-
-typedef void (*SoupReadChunkFn) (const char *chunk,
-                                guint       len,
-                                gpointer    user_data);
-
-typedef void (*SoupReadDoneFn) (char     *body,
-                               guint     len,
-                               gpointer  user_data);
-
-typedef void (*SoupReadErrorFn) (gboolean headers_done, gpointer user_data);
-
-SoupReader *soup_transfer_read  (SoupSocket             *sock,
-                                gboolean                overwrite_chunks,
-                                SoupReadHeadersDoneFn   headers_done_cb,
-                                SoupReadChunkFn         read_chunk_cb,
-                                SoupReadDoneFn          read_done_cb,
-                                SoupReadErrorFn         error_cb,
-                                gpointer                user_data);
-
-void     soup_transfer_read_ref    (SoupReader *r);
-gboolean soup_transfer_read_unref  (SoupReader *r);
-void     soup_transfer_read_cancel (SoupReader *r);
-
-void  soup_transfer_read_set_callbacks (SoupReader             *r,
-                                       SoupReadHeadersDoneFn   headers_done_cb,
-                                       SoupReadChunkFn         read_chunk_cb,
-                                       SoupReadDoneFn          read_done_cb,
-                                       SoupReadErrorFn         error_cb,
-                                       gpointer                user_data);
-
-
-typedef void (*SoupWriteDoneFn) (gpointer user_data);
-
-typedef void (*SoupWriteErrorFn) (gboolean headers_done, gpointer user_data);
-
-SoupWriter *soup_transfer_write_simple (SoupSocket             *sock,
-                                       GString                *header,
-                                       const SoupDataBuffer   *src,
-                                       SoupWriteDoneFn         write_done_cb,
-                                       SoupWriteErrorFn        error_cb,
-                                       gpointer                user_data);
-
-typedef void (*SoupWriteGetHeaderFn) (GString  **out_hdr,
-                                     gpointer   user_data);
-
-typedef SoupTransferDone (*SoupWriteGetChunkFn) (SoupDataBuffer *out_next,
-                                                gpointer        user_data);
-
-SoupWriter *soup_transfer_write (SoupSocket             *sock,
-                                SoupTransferEncoding    encoding,
-                                SoupWriteGetHeaderFn    get_header_cb,
-                                SoupWriteGetChunkFn     get_chunk_cb,
-                                SoupWriteDoneFn         write_done_cb,
-                                SoupWriteErrorFn        error_cb,
-                                gpointer                user_data);
-
-void  soup_transfer_write_pause (SoupWriter *w);
-
-void  soup_transfer_write_unpause (SoupWriter *w);
-
-void     soup_transfer_write_ref    (SoupWriter *w);
-gboolean soup_transfer_write_unref  (SoupWriter *w);
-void     soup_transfer_write_cancel (SoupWriter *w);
-
-#endif /*SOUP_TRANSFER_H*/