diff options
Diffstat (limited to 'libsoup/server/soup-server-io.c')
-rw-r--r-- | libsoup/server/soup-server-io.c | 473 |
1 files changed, 317 insertions, 156 deletions
diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c index 4556635f..e94a366e 100644 --- a/libsoup/server/soup-server-io.c +++ b/libsoup/server/soup-server-io.c @@ -15,34 +15,115 @@ #include "soup-body-input-stream.h" #include "soup-body-output-stream.h" #include "soup-filter-input-stream.h" -#include "soup-message-private.h" +#include "soup-server-message-private.h" #include "soup-misc.h" #include "soup-socket-private.h" +struct _SoupServerMessageIOData { + SoupMessageIOData base; + + GBytes *write_chunk; + goffset write_body_offset; + + GSource *unpause_source; +}; + #define RESPONSE_BLOCK_SIZE 8192 #define HEADER_SIZE_LIMIT (64 * 1024) +void +soup_server_message_io_data_free (SoupServerMessageIOData *io) +{ + if (!io) + return; + + soup_message_io_data_cleanup (&io->base); + + if (io->unpause_source) { + g_source_destroy (io->unpause_source); + g_source_unref (io->unpause_source); + io->unpause_source = NULL; + } + + g_clear_pointer (&io->write_chunk, g_bytes_unref); + + g_slice_free (SoupServerMessageIOData, io); +} + +void +soup_server_message_io_finished (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; + gpointer completion_data; + SoupMessageIOCompletion completion; + + io = soup_server_message_get_io_data (msg); + if (!io) + return; + + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; + + if ((io->base.read_state >= SOUP_MESSAGE_IO_STATE_FINISHING && + io->base.write_state >= SOUP_MESSAGE_IO_STATE_FINISHING)) + completion = SOUP_MESSAGE_IO_COMPLETE; + else + completion = SOUP_MESSAGE_IO_INTERRUPTED; + + g_object_ref (msg); + soup_server_message_set_io_data (msg, NULL); + if (completion_cb) + completion_cb (G_OBJECT (msg), completion, completion_data); + g_object_unref (msg); +} + +GIOStream * +soup_server_message_io_steal (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io; + SoupMessageIOCompletionFn completion_cb; + gpointer completion_data; + GIOStream *iostream; + + io = soup_server_message_get_io_data (msg); + if (!io || !io->base.iostream) + return NULL; + + iostream = g_object_ref (io->base.iostream); + completion_cb = io->base.completion_cb; + completion_data = io->base.completion_data; + + g_object_ref (msg); + soup_server_message_set_io_data (msg, NULL); + if (completion_cb) + completion_cb (G_OBJECT (msg), SOUP_MESSAGE_IO_STOLEN, completion_data); + g_object_unref (msg); + + return iostream; +} + static void closed_async (GObject *source, GAsyncResult *result, gpointer user_data) { GOutputStream *body_ostream = G_OUTPUT_STREAM (source); - SoupMessage *msg = user_data; - SoupMessageIOData *io; + SoupServerMessage *msg = user_data; + SoupServerMessageIOData *io; GCancellable *async_wait; - io = soup_message_get_io_data (msg); - if (!io || !io->async_wait || io->body_ostream != body_ostream) { + io = soup_server_message_get_io_data (msg); + if (!io || !io->base.async_wait || io->base.body_ostream != body_ostream) { g_object_unref (msg); return; } - g_output_stream_close_finish (body_ostream, result, &io->async_error); - g_clear_object (&io->body_ostream); + g_output_stream_close_finish (body_ostream, result, &io->base.async_error); + g_clear_object (&io->base.body_ostream); - async_wait = io->async_wait; - io->async_wait = NULL; + async_wait = io->base.async_wait; + io->base.async_wait = NULL; g_cancellable_cancel (async_wait); g_object_unref (async_wait); @@ -76,12 +157,19 @@ closed_async (GObject *source, */ static void -handle_partial_get (SoupMessage *msg) +handle_partial_get (SoupServerMessage *msg) { SoupRange *ranges; int nranges; GBytes *full_response; guint status; + SoupMessageHeaders *request_headers; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; + + request_headers = soup_server_message_get_request_headers (msg); + response_headers = soup_server_message_get_response_headers (msg); + response_body = soup_server_message_get_response_body (msg); /* Make sure the message is set up right for us to return a * partial response; it has to be a GET, the status must be @@ -89,50 +177,50 @@ handle_partial_get (SoupMessage *msg) * Content), and the SoupServer must have already filled in * the response body */ - if (msg->method != SOUP_METHOD_GET || - msg->status_code != SOUP_STATUS_OK || - soup_message_headers_get_encoding (msg->response_headers) != + if (soup_server_message_get_method (msg) != SOUP_METHOD_GET || + soup_server_message_get_status (msg, NULL) != SOUP_STATUS_OK || + soup_message_headers_get_encoding (response_headers) != SOUP_ENCODING_CONTENT_LENGTH || - msg->response_body->length == 0 || - !soup_message_body_get_accumulate (msg->response_body)) + response_body->length == 0 || + !soup_message_body_get_accumulate (response_body)) return; /* Oh, and there has to have been a valid Range header on the * request, of course. */ - status = soup_message_headers_get_ranges_internal (msg->request_headers, - msg->response_body->length, + status = soup_message_headers_get_ranges_internal (request_headers, + response_body->length, TRUE, &ranges, &nranges); if (status == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE) { - soup_message_set_status (msg, status); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, status, NULL); + soup_message_body_truncate (response_body); return; } else if (status != SOUP_STATUS_PARTIAL_CONTENT) return; - full_response = soup_message_body_flatten (msg->response_body); + full_response = soup_message_body_flatten (response_body); if (!full_response) { - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_message_headers_free_ranges (request_headers, ranges); return; } - soup_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT, NULL); + soup_message_body_truncate (response_body); if (nranges == 1) { GBytes *range_buf; /* Single range, so just set Content-Range and fix the body. */ - soup_message_headers_set_content_range (msg->response_headers, + soup_message_headers_set_content_range (response_headers, ranges[0].start, ranges[0].end, g_bytes_get_size (full_response)); range_buf = g_bytes_new_from_bytes (full_response, ranges[0].start, ranges[0].end - ranges[0].start + 1); - soup_message_body_append_bytes (msg->response_body, range_buf); + soup_message_body_append_bytes (response_body, range_buf); g_bytes_unref (range_buf); } else { SoupMultipart *multipart; @@ -147,7 +235,7 @@ handle_partial_get (SoupMessage *msg) */ multipart = soup_multipart_new ("multipart/byteranges"); - content_type = soup_message_headers_get_one (msg->response_headers, + content_type = soup_message_headers_get_one (response_headers, "Content-Type"); for (i = 0; i < nranges; i++) { part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART); @@ -169,52 +257,62 @@ handle_partial_get (SoupMessage *msg) g_bytes_unref (part_body); } - soup_multipart_to_message (multipart, msg->response_headers, &body); - soup_message_body_append_bytes (msg->response_body, body); + soup_multipart_to_message (multipart, response_headers, &body); + soup_message_body_append_bytes (response_body, body); g_bytes_unref (body); soup_multipart_free (multipart); } g_bytes_unref (full_response); - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_message_headers_free_ranges (request_headers, ranges); } static void -write_headers (SoupMessage *msg, - GString *headers, - SoupEncoding *encoding) +write_headers (SoupServerMessage *msg, + GString *headers, + SoupEncoding *encoding) { SoupEncoding claimed_encoding; SoupMessageHeadersIter iter; const char *name, *value; + guint status_code; + const char *reason_phrase; + const char *method; + SoupMessageHeaders *response_headers; + SoupMessageBody *response_body; - if (msg->status_code == 0) - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + if (soup_server_message_get_status (msg, NULL) == 0) + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, NULL); handle_partial_get (msg); + status_code = soup_server_message_get_status (msg, &reason_phrase); + g_string_append_printf (headers, "HTTP/1.%c %d %s\r\n", - soup_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1', - msg->status_code, msg->reason_phrase); - - claimed_encoding = soup_message_headers_get_encoding (msg->response_headers); - if ((msg->method == SOUP_METHOD_HEAD || - msg->status_code == SOUP_STATUS_NO_CONTENT || - msg->status_code == SOUP_STATUS_NOT_MODIFIED || - SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) || - (msg->method == SOUP_METHOD_CONNECT && - SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))) + soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1', + status_code, reason_phrase); + + method = soup_server_message_get_method (msg); + response_headers = soup_server_message_get_response_headers (msg); + claimed_encoding = soup_message_headers_get_encoding (response_headers); + if ((method == SOUP_METHOD_HEAD || + status_code == SOUP_STATUS_NO_CONTENT || + status_code == SOUP_STATUS_NOT_MODIFIED || + SOUP_STATUS_IS_INFORMATIONAL (status_code)) || + (method == SOUP_METHOD_CONNECT && + SOUP_STATUS_IS_SUCCESSFUL (status_code))) *encoding = SOUP_ENCODING_NONE; else *encoding = claimed_encoding; + response_body = soup_server_message_get_response_body (msg); if (claimed_encoding == SOUP_ENCODING_CONTENT_LENGTH && - !soup_message_headers_get_content_length (msg->response_headers)) { - soup_message_headers_set_content_length (msg->response_headers, - msg->response_body->length); + !soup_message_headers_get_content_length (response_headers)) { + soup_message_headers_set_content_length (response_headers, + response_body->length); } - soup_message_headers_iter_init (&iter, msg->response_headers); + soup_message_headers_iter_init (&iter, response_headers); while (soup_message_headers_iter_next (&iter, &name, &value)) g_string_append_printf (headers, "%s: %s\r\n", name, value); g_string_append (headers, "\r\n"); @@ -227,13 +325,15 @@ write_headers (SoupMessage *msg, * socket not writable, write is complete, etc). */ static gboolean -io_write (SoupMessage *msg, - GCancellable *cancellable, - GError **error) +io_write (SoupServerMessage *msg, + GCancellable *cancellable, + GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; GBytes *chunk; gssize nwrote; + guint status_code; if (io->async_error) { g_propagate_error (error, io->async_error); @@ -248,11 +348,12 @@ io_write (SoupMessage *msg, switch (io->write_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && msg->status_code == 0) { + status_code = soup_server_message_get_status (msg, NULL); + if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && status_code == 0) { /* Client requested "Expect: 100-continue", and * server did not set an error. */ - soup_message_set_status (msg, SOUP_STATUS_CONTINUE); + soup_server_message_set_status (msg, SOUP_STATUS_CONTINUE, NULL); } if (!io->write_buf->len) @@ -272,8 +373,9 @@ io_write (SoupMessage *msg, io->written = 0; g_string_truncate (io->write_buf, 0); - if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { - if (msg->status_code == SOUP_STATUS_CONTINUE) { + status_code = soup_server_message_get_status (msg, NULL); + if (SOUP_STATUS_IS_INFORMATIONAL (status_code)) { + if (status_code == SOUP_STATUS_CONTINUE) { /* Stop and wait for the body now */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; @@ -288,20 +390,20 @@ io_write (SoupMessage *msg, */ } - soup_message_wrote_informational (msg); + soup_server_message_wrote_informational (msg); /* If this was "101 Switching Protocols", then * the server probably stole the connection... */ - if (io != soup_message_get_io_data (msg)) + if (server_io != soup_server_message_get_io_data (msg)) return FALSE; - soup_message_cleanup_response (msg); + soup_server_message_cleanup_response (msg); break; } if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) - io->write_length = soup_message_headers_get_content_length (msg->response_headers); + io->write_length = soup_message_headers_get_content_length (soup_server_message_get_response_headers (msg)); io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START; /* If the client was waiting for a Continue @@ -311,7 +413,7 @@ io_write (SoupMessage *msg, if (io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->read_state = SOUP_MESSAGE_IO_STATE_DONE; - soup_message_wrote_headers (msg); + soup_server_message_wrote_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: @@ -329,51 +431,53 @@ io_write (SoupMessage *msg, break; } - if (!io->write_chunk) { - io->write_chunk = soup_message_body_get_chunk (msg->response_body, io->write_body_offset); - if (!io->write_chunk) { - soup_message_io_pause (msg); + if (!server_io->write_chunk) { + server_io->write_chunk = soup_message_body_get_chunk (soup_server_message_get_response_body (msg), + server_io->write_body_offset); + if (!server_io->write_chunk) { + soup_server_message_io_pause (msg); return FALSE; } - if (!g_bytes_get_size (io->write_chunk)) { + if (!g_bytes_get_size (server_io->write_chunk)) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } } nwrote = g_pollable_stream_write (io->body_ostream, - (guchar*)g_bytes_get_data (io->write_chunk, NULL) + io->written, - g_bytes_get_size (io->write_chunk) - io->written, + (guchar*)g_bytes_get_data (server_io->write_chunk, NULL) + io->written, + g_bytes_get_size (server_io->write_chunk) - io->written, FALSE, cancellable, error); if (nwrote == -1) return FALSE; - chunk = g_bytes_new_from_bytes (io->write_chunk, io->written, nwrote); + chunk = g_bytes_new_from_bytes (server_io->write_chunk, io->written, nwrote); io->written += nwrote; if (io->write_length) io->write_length -= nwrote; - if (io->written == g_bytes_get_size (io->write_chunk)) + if (io->written == g_bytes_get_size (server_io->write_chunk)) io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA; - soup_message_wrote_body_data (msg, chunk); + soup_server_message_wrote_body_data (msg, g_bytes_get_size (chunk)); g_bytes_unref (chunk); break; case SOUP_MESSAGE_IO_STATE_BODY_DATA: io->written = 0; - if (g_bytes_get_size (io->write_chunk) == 0) { + if (g_bytes_get_size (server_io->write_chunk) == 0) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } - soup_message_body_wrote_chunk (msg->response_body, io->write_chunk); - io->write_body_offset += g_bytes_get_size (io->write_chunk); - g_clear_pointer (&io->write_chunk, g_bytes_unref); + soup_message_body_wrote_chunk (soup_server_message_get_response_body (msg), + server_io->write_chunk); + server_io->write_body_offset += g_bytes_get_size (server_io->write_chunk); + g_clear_pointer (&server_io->write_chunk, g_bytes_unref); io->write_state = SOUP_MESSAGE_IO_STATE_BODY; - soup_message_wrote_chunk (msg); + soup_server_message_wrote_chunk (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_FLUSH: @@ -397,7 +501,7 @@ io_write (SoupMessage *msg, case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; - soup_message_wrote_body (msg); + soup_server_message_wrote_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: @@ -435,55 +539,52 @@ parse_connect_authority (const char *req_path) } static guint -parse_headers (SoupMessage *msg, - char *headers, - guint headers_len, - SoupEncoding *encoding, - SoupSocket *sock, - GError **error) +parse_headers (SoupServerMessage *msg, + char *headers, + guint headers_len, + SoupEncoding *encoding, + GError **error) { char *req_method, *req_path, *url; SoupHTTPVersion version; + SoupSocket *sock; const char *req_host; guint status; SoupURI *uri; + SoupMessageHeaders *request_headers; + + request_headers = soup_server_message_get_request_headers (msg); status = soup_headers_parse_request (headers, headers_len, - msg->request_headers, + request_headers, &req_method, &req_path, &version); - if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { - if (status == SOUP_STATUS_MALFORMED) { - g_set_error_literal (error, SOUP_REQUEST_ERROR, - SOUP_REQUEST_ERROR_PARSING, - _("Could not parse HTTP request")); - } + if (!SOUP_STATUS_IS_SUCCESSFUL (status)) return status; - } - g_object_set (G_OBJECT (msg), - SOUP_MESSAGE_METHOD, req_method, - SOUP_MESSAGE_HTTP_VERSION, version, - NULL); + soup_server_message_set_method (msg, req_method); + soup_server_message_set_http_version (msg, version); g_free (req_method); /* Handle request body encoding */ - *encoding = soup_message_headers_get_encoding (msg->request_headers); + *encoding = soup_message_headers_get_encoding (request_headers); if (*encoding == SOUP_ENCODING_UNRECOGNIZED) { - if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding")) + if (soup_message_headers_get_list (request_headers, "Transfer-Encoding")) return SOUP_STATUS_NOT_IMPLEMENTED; else return SOUP_STATUS_BAD_REQUEST; } /* Generate correct context for request */ - req_host = soup_message_headers_get_one (msg->request_headers, "Host"); + req_host = soup_message_headers_get_one (request_headers, "Host"); if (req_host && strchr (req_host, '/')) { g_free (req_path); return SOUP_STATUS_BAD_REQUEST; } + sock = soup_server_message_get_soup_socket (msg); + if (!strcmp (req_path, "*") && req_host) { /* Eg, "OPTIONS * HTTP/1.1" */ url = g_strdup_printf ("%s://%s", @@ -493,7 +594,7 @@ parse_headers (SoupMessage *msg, if (uri) soup_uri_set_path (uri, "*"); g_free (url); - } else if (msg->method == SOUP_METHOD_CONNECT) { + } else if (soup_server_message_get_method (msg) == SOUP_METHOD_CONNECT) { /* Authority */ uri = parse_connect_authority (req_path); } else if (*req_path != '/') { @@ -505,7 +606,7 @@ parse_headers (SoupMessage *msg, req_host, req_path); uri = soup_uri_new (url); g_free (url); - } else if (soup_message_get_http_version (msg) == SOUP_HTTP_1_0) { + } else if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) { /* No Host header, no AbsoluteUri */ GInetSocketAddress *addr = soup_socket_get_local_address (sock); GInetAddress *inet_addr = g_inet_socket_address_get_address (addr); @@ -530,7 +631,7 @@ parse_headers (SoupMessage *msg, return SOUP_STATUS_BAD_REQUEST; } - soup_message_set_uri (msg, uri); + soup_server_message_set_uri (msg, uri); soup_uri_free (uri); return SOUP_STATUS_OK; @@ -543,27 +644,33 @@ parse_headers (SoupMessage *msg, * socket not readable, read is complete, etc). */ static gboolean -io_read (SoupMessage *msg, - GCancellable *cancellable, - GError **error) +io_read (SoupServerMessage *msg, + GCancellable *cancellable, + GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; gssize nread; guint status; + SoupMessageHeaders *request_headers; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: - if (!soup_message_io_read_headers (msg, io->istream, io->read_header_buf, FALSE, cancellable, error)) + if (!soup_message_io_data_read_headers (io, FALSE, cancellable, error)) { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT)) + soup_server_message_set_status (msg, SOUP_STATUS_MALFORMED, NULL); return FALSE; + } status = parse_headers (msg, (char *)io->read_header_buf->data, io->read_header_buf->len, &io->read_encoding, - io->sock, error); g_byte_array_set_size (io->read_header_buf, 0); + request_headers = soup_server_message_get_request_headers (msg); + if (status != SOUP_STATUS_OK) { /* Either we couldn't parse the headers, or they * indicated something that would mean we wouldn't @@ -572,14 +679,13 @@ io_read (SoupMessage *msg, * reading, and make sure the connection gets * closed when we're done. */ - soup_message_set_status (msg, status); - soup_message_headers_append (msg->request_headers, - "Connection", "close"); + soup_server_message_set_status (msg, status, NULL); + soup_message_headers_append (request_headers, "Connection", "close"); io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; break; } - if (soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { + if (soup_message_headers_get_expectations (request_headers) & SOUP_EXPECTATION_CONTINUE) { /* We must return a status code and response * headers to the client; either an error to * be set by a got-headers handler below, or @@ -591,11 +697,11 @@ io_read (SoupMessage *msg, io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START; if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) - io->read_length = soup_message_headers_get_content_length (msg->request_headers); + io->read_length = soup_message_headers_get_content_length (request_headers); else io->read_length = -1; - soup_message_got_headers (msg); + soup_server_message_got_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: @@ -618,10 +724,13 @@ io_read (SoupMessage *msg, FALSE, cancellable, error); if (nread > 0) { - if (msg->request_body) { + SoupMessageBody *request_body; + + request_body = soup_server_message_get_request_body (msg); + if (request_body) { GBytes *bytes = g_bytes_new (buf, nread); - soup_message_body_got_chunk (msg->request_body, bytes); - soup_message_got_chunk (msg, bytes); + soup_message_body_got_chunk (request_body, bytes); + soup_server_message_got_chunk (msg, bytes); g_bytes_unref (bytes); } break; @@ -637,7 +746,7 @@ io_read (SoupMessage *msg, case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; - soup_message_got_body (msg); + soup_server_message_got_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: @@ -653,13 +762,14 @@ io_read (SoupMessage *msg, } static gboolean -io_run_until (SoupMessage *msg, +io_run_until (SoupServerMessage *msg, SoupMessageIOState read_state, SoupMessageIOState write_state, GCancellable *cancellable, GError **error) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; gboolean progress = TRUE, done; GError *my_error = NULL; @@ -674,7 +784,7 @@ io_run_until (SoupMessage *msg, g_object_ref (msg); - while (progress && soup_message_get_io_data (msg) == io && !io->paused && !io->async_wait && + while (progress && soup_server_message_get_io_data (msg) == server_io && !io->paused && !io->async_wait && (io->read_state < read_state || io->write_state < write_state)) { if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state)) @@ -689,7 +799,7 @@ io_run_until (SoupMessage *msg, g_propagate_error (error, my_error); g_object_unref (msg); return FALSE; - } else if (soup_message_get_io_data (msg) != io) { + } else if (soup_server_message_get_io_data (msg) != server_io) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled")); @@ -716,22 +826,22 @@ io_run_until (SoupMessage *msg, return done; } -static void io_run (SoupMessage *msg); +static void io_run (SoupServerMessage *msg); static gboolean -io_run_ready (SoupMessage *msg, - gpointer user_data) +io_run_ready (SoupServerMessage *msg, + gpointer user_data) { io_run (msg); return FALSE; } static void -io_run (SoupMessage *msg) +io_run (SoupServerMessage *msg) { - SoupMessageIOData *io = soup_message_get_io_data (msg); + SoupServerMessageIOData *server_io = soup_server_message_get_io_data (msg); + SoupMessageIOData *io = &server_io->base; GError *error = NULL; - GCancellable *cancellable; if (io->io_source) { g_source_destroy (io->io_source); @@ -740,58 +850,109 @@ io_run (SoupMessage *msg) } g_object_ref (msg); - cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL; - if (io_run_until (msg, SOUP_MESSAGE_IO_STATE_DONE, SOUP_MESSAGE_IO_STATE_DONE, - cancellable, &error)) { - soup_message_io_finished (msg); + NULL, &error)) { + soup_server_message_io_finished (msg); } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_clear_error (&error); - io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg); + io->io_source = soup_message_io_data_get_source (io, G_OBJECT (msg), NULL, + (SoupMessageIOSourceFunc)io_run_ready, + NULL); g_source_attach (io->io_source, io->async_context); } else { - if (soup_message_get_io_data (msg) == io) { - if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code) && + if (soup_server_message_get_io_data (msg) == server_io) { + if (!SOUP_STATUS_IS_TRANSPORT_ERROR (soup_server_message_get_status (msg, NULL)) && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - soup_message_set_status (msg, SOUP_STATUS_IO_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_IO_ERROR, NULL); } - soup_message_io_finished (msg); + soup_server_message_io_finished (msg); } g_error_free (error); } - g_object_unref (msg); - g_clear_object (&cancellable); } void -soup_message_read_request (SoupMessage *msg, - SoupSocket *sock, - SoupMessageCompletionFn completion_cb, - gpointer user_data) +soup_server_message_read_request (SoupServerMessage *msg, + SoupMessageIOCompletionFn completion_cb, + gpointer user_data) { - SoupMessageIOData *io; + SoupServerMessageIOData *io; + SoupSocket *sock; - io = g_slice_new0 (SoupMessageIOData); - io->completion_cb = completion_cb; - io->completion_data = user_data; + io = g_slice_new0 (SoupServerMessageIOData); + io->base.completion_cb = completion_cb; + io->base.completion_data = user_data; - io->sock = sock; - io->iostream = g_object_ref (soup_socket_get_iostream (io->sock)); - io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->iostream)); - io->ostream = g_io_stream_get_output_stream (io->iostream); - io->async_context = g_main_context_ref_thread_default (); + sock = soup_server_message_get_soup_socket (msg); + io->base.iostream = g_object_ref (soup_socket_get_iostream (sock)); + io->base.istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (io->base.iostream)); + io->base.ostream = g_io_stream_get_output_stream (io->base.iostream); + io->base.async_context = g_main_context_ref_thread_default (); - io->read_header_buf = g_byte_array_new (); - io->write_buf = g_string_new (NULL); + io->base.read_header_buf = g_byte_array_new (); + io->base.write_buf = g_string_new (NULL); - io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; - io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; + io->base.read_state = SOUP_MESSAGE_IO_STATE_HEADERS; + io->base.write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED; - soup_message_set_io_data (msg, io); + soup_server_message_set_io_data (msg, io); io_run (msg); } + +void +soup_server_message_io_pause (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_if_fail (io != NULL); + + if (io->unpause_source) { + g_source_destroy (io->unpause_source); + g_source_unref (io->unpause_source); + io->unpause_source = NULL; + } + + soup_message_io_data_pause (&io->base); +} + +static gboolean +io_unpause_internal (gpointer msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_val_if_fail (io != NULL, FALSE); + + g_clear_pointer (&io->unpause_source, g_source_unref); + soup_message_io_data_unpause (&io->base); + if (io->base.io_source) + return FALSE; + + io_run (msg); + return FALSE; +} + +void +soup_server_message_io_unpause (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + g_return_if_fail (io != NULL); + + if (!io->unpause_source) { + io->unpause_source = soup_add_completion_reffed (io->base.async_context, + io_unpause_internal, msg, NULL); + } +} + +gboolean +soup_server_message_is_io_paused (SoupServerMessage *msg) +{ + SoupServerMessageIOData *io = soup_server_message_get_io_data (msg); + + return io && io->base.paused; +} |