+2003-09-18 Dan Winship <danw@ximian.com>
+
+ * libsoup/soup-message.c: Add wrote_informational and
+ got_informational signals.
+
+ * libsoup/soup-message-client-io.c (get_request_headers): Set the
+ EXPECT_CONTINUE flag on the message if that header is set.
+
+ * libsoup/soup-message-server-io.c (parse_request_headers):
+ Likewise
+
+ * libsoup/soup-message-io.c (io_write): Set read_state to HEADERS
+ when blocking on an expect-continue. Emit wrote_informational
+ instead of wrote_headers in the 1xx case.
+ (io_read): Set read_state to BLOCKING, not NOT_STARTED after
+ reading a 100 Continue response. Emit got_informational instead of
+ got_headers in the 1xx case.
+
+ * libsoup/soup-session.c (soup_session_send_message): Reorder
+ things to deal with the fact that the message could finish right
+ away if there is a connection available and the server is very
+ close.
+
+ * libsoup/soup-status.h: Rename SOUP_STATUS_CLASS_TRANSPORT to
+ SOUP_STATUS_CLASS_TRANSPORT_ERROR.
+
2003-09-17 Dan Winship <danw@ximian.com>
* libsoup/soup-session.c (find_oldest_connection): Fix two bugs
{
gboolean proxy = GPOINTER_TO_UINT (user_data);
const SoupUri *uri = soup_message_get_uri (req);
+ const char *expect;
char *uri_string;
if (!strcmp (req->method, "CONNECT")) {
soup_message_foreach_header (req->request_headers, add_header, header);
g_string_append (header, "\r\n");
+
+ expect = soup_message_get_header (req->request_headers, "Expect");
+ if (expect && !strcmp (expect, "100-continue"))
+ req->priv->msg_flags |= SOUP_MESSAGE_EXPECT_CONTINUE;
}
void
/* We just wrote a 1xx response
* header, so stay in STATE_HEADERS.
* (The caller will pause us from the
- * wrote_headers callback if he is not
- * ready to send the final response.)
+ * wrote_informational callback if he
+ * is not ready to send the final
+ * response.)
*/
}
} else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE) {
/* Need to wait for the Continue response */
io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
+ io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
} else
io->write_state = io_body_state (io->write_encoding);
SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
- soup_message_wrote_headers (msg);
+ if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
+ soup_message_wrote_informational (msg);
+ else
+ soup_message_wrote_headers (msg);
SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
break;
if (msg->status_code == SOUP_STATUS_CONTINUE &&
io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
- /* Restart the reader, unpause the writer */
+ /* Pause the reader, unpause the writer */
io->read_state =
- SOUP_MESSAGE_IO_STATE_NOT_STARTED;
+ SOUP_MESSAGE_IO_STATE_BLOCKING;
io->write_state =
io_body_state (io->write_encoding);
} else {
io->read_state = io_body_state (io->read_encoding);
SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
- soup_message_got_headers (msg);
+ if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
+ soup_message_got_informational (msg);
+ else
+ soup_message_got_headers (msg);
SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
break;
{
SoupUri *uri;
char *req_path = NULL, *url;
- const char *length, *enc, *req_host;
+ const char *expect, *length, *enc, *req_host;
SoupServer *server;
if (!soup_headers_parse_request (headers, headers_len,
&msg->priv->http_version))
return SOUP_STATUS_BAD_REQUEST;
+ expect = soup_message_get_header (msg->request_headers, "Expect");
+ if (expect && !strcmp (expect, "100-continue"))
+ msg->priv->msg_flags |= SOUP_MESSAGE_EXPECT_CONTINUE;
+
/* Handle request body encoding */
length = soup_message_get_header (msg->request_headers,
"Content-Length");
static GObjectClass *parent_class;
enum {
+ WROTE_INFORMATIONAL,
WROTE_HEADERS,
WROTE_CHUNK,
WROTE_BODY,
+ GOT_INFORMATIONAL,
GOT_HEADERS,
GOT_CHUNK,
GOT_BODY,
object_class->finalize = finalize;
/* signals */
+ signals[WROTE_INFORMATIONAL] =
+ g_signal_new ("wrote_informational",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SoupMessageClass, wrote_informational),
+ NULL, NULL,
+ soup_marshal_NONE__NONE,
+ G_TYPE_NONE, 0);
signals[WROTE_HEADERS] =
g_signal_new ("wrote_headers",
G_OBJECT_CLASS_TYPE (object_class),
soup_marshal_NONE__NONE,
G_TYPE_NONE, 0);
+ signals[GOT_INFORMATIONAL] =
+ g_signal_new ("got_informational",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (SoupMessageClass, got_informational),
+ NULL, NULL,
+ soup_marshal_NONE__NONE,
+ G_TYPE_NONE, 0);
signals[GOT_HEADERS] =
g_signal_new ("got_headers",
G_OBJECT_CLASS_TYPE (object_class),
}
void
+soup_message_wrote_informational (SoupMessage *msg)
+{
+ g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
+}
+
+void
soup_message_wrote_headers (SoupMessage *msg)
{
g_signal_emit (msg, signals[WROTE_HEADERS], 0);
g_signal_emit (msg, signals[WROTE_BODY], 0);
}
+void
+soup_message_got_informational (SoupMessage *msg)
+{
+ g_signal_emit (msg, signals[GOT_INFORMATIONAL], 0);
+}
+
static void
got_headers (SoupMessage *req)
{
GObjectClass parent_class;
/* signals */
- void (*wrote_headers) (SoupMessage *msg);
- void (*wrote_chunk) (SoupMessage *msg);
- void (*wrote_body) (SoupMessage *msg);
- void (*got_headers) (SoupMessage *msg);
- void (*got_chunk) (SoupMessage *msg);
- void (*got_body) (SoupMessage *msg);
- void (*finished) (SoupMessage *msg);
+ void (*wrote_informational) (SoupMessage *msg);
+ void (*wrote_headers) (SoupMessage *msg);
+ void (*wrote_chunk) (SoupMessage *msg);
+ void (*wrote_body) (SoupMessage *msg);
+ void (*got_informational) (SoupMessage *msg);
+ void (*got_headers) (SoupMessage *msg);
+ void (*got_chunk) (SoupMessage *msg);
+ void (*got_body) (SoupMessage *msg);
+ void (*finished) (SoupMessage *msg);
} SoupMessageClass;
GType soup_message_get_type (void);
SOUP_MESSAGE_OVERWRITE_CHUNKS = (1 << 3),
/*
- * SOUP_MESSAGE_EXPECT_CONTINUE:
- * The message includes an "Expect: 100-continue" header, and we
- * should not send the body until the Continue response has been
- * received. (This should be synchronized with the existence
- * of the "Expect: 100-continue" header. FIXME!)
+ * SOUP_MESSAGE_EXPECT_CONTINUE: The message includes an
+ * "Expect: 100-continue" header, and we should not send the
+ * body until the Continue response has been received. (This
+ * is automatically set if there is an "Expect: 100-continue"
+ * header.)
*/
SOUP_MESSAGE_EXPECT_CONTINUE = (1 << 4)
} SoupMessageFlags;
void soup_message_io_unpause (SoupMessage *msg);
-void soup_message_wrote_headers (SoupMessage *msg);
-void soup_message_wrote_chunk (SoupMessage *msg);
-void soup_message_wrote_body (SoupMessage *msg);
-void soup_message_got_headers (SoupMessage *msg);
-void soup_message_got_chunk (SoupMessage *msg);
-void soup_message_got_body (SoupMessage *msg);
-void soup_message_finished (SoupMessage *msg);
+void soup_message_wrote_informational (SoupMessage *msg);
+void soup_message_wrote_headers (SoupMessage *msg);
+void soup_message_wrote_chunk (SoupMessage *msg);
+void soup_message_wrote_body (SoupMessage *msg);
+void soup_message_got_informational (SoupMessage *msg);
+void soup_message_got_headers (SoupMessage *msg);
+void soup_message_got_chunk (SoupMessage *msg);
+void soup_message_got_body (SoupMessage *msg);
+void soup_message_finished (SoupMessage *msg);
#endif /*SOUP_MESSAGE_H*/
soup_session_queue_message (session, req, NULL, NULL);
- while (1) {
+ while (req->status != SOUP_MESSAGE_STATUS_FINISHED &&
+ !SOUP_STATUS_IS_TRANSPORT_ERROR (req->status_code))
g_main_iteration (TRUE);
- if (req->status == SOUP_MESSAGE_STATUS_FINISHED ||
- SOUP_STATUS_IS_TRANSPORT (req->status_code))
- break;
- }
-
return req->status_code;
}
#define SOUP_STATUS_H 1
typedef enum {
- SOUP_STATUS_CLASS_TRANSPORT = 0,
+ SOUP_STATUS_CLASS_TRANSPORT_ERROR = 0,
SOUP_STATUS_CLASS_INFORMATIONAL,
SOUP_STATUS_CLASS_SUCCESS,
SOUP_STATUS_CLASS_REDIRECT,
SOUP_STATUS_CLASS_SERVER_ERROR,
} SoupStatusClass;
-#define SOUP_STATUS_IS_TRANSPORT(x) (((x) > 0 && (x) < 100) || (x) >= 600)
-#define SOUP_STATUS_IS_INFORMATIONAL(x) ((x) >= 100 && (x) < 200)
-#define SOUP_STATUS_IS_SUCCESSFUL(x) ((x) >= 200 && (x) < 300)
-#define SOUP_STATUS_IS_REDIRECTION(x) ((x) >= 300 && (x) < 400)
-#define SOUP_STATUS_IS_CLIENT_ERROR(x) ((x) >= 400 && (x) < 500)
-#define SOUP_STATUS_IS_SERVER_ERROR(x) ((x) >= 500 && (x) < 600)
+#define SOUP_STATUS_IS_TRANSPORT_ERROR(x) ((x) > 0 && (x) < 100)
+#define SOUP_STATUS_IS_INFORMATIONAL(x) ((x) >= 100 && (x) < 200)
+#define SOUP_STATUS_IS_SUCCESSFUL(x) ((x) >= 200 && (x) < 300)
+#define SOUP_STATUS_IS_REDIRECTION(x) ((x) >= 300 && (x) < 400)
+#define SOUP_STATUS_IS_CLIENT_ERROR(x) ((x) >= 400 && (x) < 500)
+#define SOUP_STATUS_IS_SERVER_ERROR(x) ((x) >= 500 && (x) < 600)
typedef enum {
/* Transport Errors */