static void clear_current_request (SoupConnection *conn) { SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn); g_object_freeze_notify (G_OBJECT (conn)); if (priv->state == SOUP_CONNECTION_IN_USE) { /* We don't use soup_connection_set_state here since * it may call clear_current_request()... */ priv->state = SOUP_CONNECTION_IDLE; g_object_notify (G_OBJECT (conn), "state"); } start_idle_timer (conn); if (priv->cur_req) { SoupMessage *cur_req = priv->cur_req; g_object_remove_weak_pointer (G_OBJECT (priv->cur_req), (gpointer)&priv->cur_req); priv->cur_req = NULL; g_object_notify (G_OBJECT (conn), "message"); if (!soup_message_is_keepalive (cur_req)) soup_connection_disconnect (conn); else soup_message_io_stop (cur_req); } g_object_thaw_notify (G_OBJECT (conn)); }
static void do_message_to_session (SoupSession *session, const char *uri, const char *comment, guint expected_status) { SoupMessage *msg; debug_printf (1, " %s\n", comment); msg = soup_message_new ("GET", uri); soup_session_send_message (session, msg); if (msg->status_code != expected_status) { debug_printf (1, " FAILED: %d %s (expected %d %s)\n", msg->status_code, msg->reason_phrase, expected_status, soup_status_get_phrase (expected_status)); errors++; } if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && !soup_message_is_keepalive (msg)) { debug_printf (1, " ERROR: message is not keepalive!"); errors++; } g_object_unref (msg); }
static void queue_message_restarted (SoupMessage *msg, gpointer user_data) { SoupMessageQueueItem *item = user_data; if (item->proxy_addr) { g_object_unref (item->proxy_addr); item->proxy_addr = NULL; } if (item->proxy_uri) { soup_uri_free (item->proxy_uri); item->proxy_uri = NULL; } if (item->conn && (!soup_message_is_keepalive (msg) || SOUP_STATUS_IS_REDIRECTION (msg->status_code))) { if (soup_connection_get_state (item->conn) == SOUP_CONNECTION_IN_USE) soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE); g_object_unref (item->conn); item->conn = NULL; } g_cancellable_reset (item->cancellable); item->state = SOUP_MESSAGE_STARTING; }
static void current_msg_got_body (SoupMessage *msg, gpointer user_data) { SoupConnection *conn = user_data; SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn); priv->unused_timeout = 0; if (priv->proxy_uri && msg->method == SOUP_METHOD_CONNECT && SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATED, NULL); /* We're now effectively no longer proxying */ g_clear_pointer (&priv->proxy_uri, soup_uri_free); } priv->reusable = soup_message_is_keepalive (msg); }
static void request_finished (SoupMessage *msg, SoupClientContext *client) { SoupServer *server = client->server; SoupSocket *sock = client->sock; g_signal_emit (server, msg->status_code == SOUP_STATUS_IO_ERROR ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED], 0, msg, client); soup_client_context_cleanup (client); if (soup_socket_is_connected (sock) && soup_message_is_keepalive (msg)) { /* Start a new request */ start_request (server, client); } else { soup_socket_disconnect (sock); soup_client_context_unref (client); } g_object_unref (msg); g_object_unref (sock); }
static void do_message_to_session (SoupSession *session, const char *uri, const char *comment, guint expected_status) { SoupMessage *msg; gboolean finished = FALSE; debug_printf (1, " msg %s\n", comment); msg = soup_message_new ("GET", uri); g_signal_connect (msg, "finished", G_CALLBACK (message_finished), &finished); soup_session_send_message (session, msg); if (msg->status_code != expected_status) { debug_printf (1, " FAILED: %d %s (expected %d %s)\n", msg->status_code, msg->reason_phrase, expected_status, soup_status_get_phrase (expected_status)); errors++; } if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && !soup_message_is_keepalive (msg)) { debug_printf (1, " ERROR: message is not keepalive!\n"); errors++; } if (!finished) { debug_printf (1, " ERROR: 'finished' was not emitted\n"); errors++; } g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (message_finished), &finished); g_object_unref (msg); }
static void clear_current_request (SoupConnection *conn) { SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn); if (priv->state == SOUP_CONNECTION_IN_USE) priv->state = SOUP_CONNECTION_IDLE; start_idle_timer (conn); if (priv->cur_req) { SoupMessage *cur_req = priv->cur_req; g_object_remove_weak_pointer (G_OBJECT (priv->cur_req), (gpointer)&priv->cur_req); priv->cur_req = NULL; if (!soup_message_is_keepalive (cur_req)) soup_connection_disconnect (conn); else { priv->last_used = time (NULL); soup_message_io_stop (cur_req); } } }
/* Attempts to push forward the reading side of @msg's I/O. Returns * %TRUE if it manages to make some progress, and it is likely that * further progress can be made. Returns %FALSE if it has reached a * stopping point of some sort (need input from the application, * socket not readable, read is complete, etc). */ static gboolean io_read (SoupMessage *msg, gboolean blocking, GCancellable *cancellable, GError **error) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; guchar *stack_buf = NULL; gssize nread; SoupBuffer *buffer; guint status; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: if (!read_headers (msg, blocking, cancellable, error)) return FALSE; status = io->parse_headers_cb (msg, (char *)io->read_header_buf->data, io->read_header_buf->len, &io->read_encoding, io->header_data, error); g_byte_array_set_size (io->read_header_buf, 0); if (status != SOUP_STATUS_OK) { /* Either we couldn't parse the headers, or they * indicated something that would mean we wouldn't * be able to parse the body. (Eg, unknown * Transfer-Encoding.). Skip the rest of the * 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"); io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; break; } if (io->mode == SOUP_MESSAGE_IO_CLIENT && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { if (msg->status_code == SOUP_STATUS_CONTINUE && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) { /* Pause the reader, unpause the writer */ io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START; } else { /* Just stay in HEADERS */ io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; } /* Informational responses have no bodies, so * bail out here rather than parsing encoding, etc */ soup_message_got_informational (msg); /* If this was "101 Switching Protocols", then * the session may have stolen the connection... */ if (io != priv->io_data) return FALSE; soup_message_cleanup_response (msg); break; } else if (io->mode == SOUP_MESSAGE_IO_SERVER && soup_message_headers_get_expectations (msg->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 * else %SOUP_STATUS_CONTINUE otherwise. */ io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; } else { io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START; /* If the client was waiting for a Continue * but got something else, then it's done * writing. */ if (io->mode == SOUP_MESSAGE_IO_CLIENT && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; } if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) { SoupMessageHeaders *hdrs = (io->mode == SOUP_MESSAGE_IO_CLIENT) ? msg->response_headers : msg->request_headers; io->read_length = soup_message_headers_get_content_length (hdrs); if (io->mode == SOUP_MESSAGE_IO_CLIENT && !soup_message_is_keepalive (msg)) { /* Some servers suck and send * incorrect Content-Length values, so * allow EOF termination in this case * (iff the message is too short) too. */ io->read_encoding = SOUP_ENCODING_EOF; } } else io->read_length = -1; soup_message_got_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: if (!io->body_istream) { GInputStream *body_istream = soup_body_input_stream_new (G_INPUT_STREAM (io->istream), io->read_encoding, io->read_length); /* TODO: server-side messages do not have a io->item. This means * that we cannot use content processors for them right now. */ if (io->mode == SOUP_MESSAGE_IO_CLIENT) { io->body_istream = soup_message_setup_body_istream (body_istream, msg, io->item->session, SOUP_STAGE_MESSAGE_BODY); g_object_unref (body_istream); } else { io->body_istream = body_istream; } } if (priv->sniffer) { SoupContentSnifferStream *sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (io->body_istream); const char *content_type; GHashTable *params; if (!soup_content_sniffer_stream_is_ready (sniffer_stream, blocking, cancellable, error)) return FALSE; content_type = soup_content_sniffer_stream_sniff (sniffer_stream, ¶ms); soup_message_content_sniffed (msg, content_type, params); } io->read_state = SOUP_MESSAGE_IO_STATE_BODY; break; case SOUP_MESSAGE_IO_STATE_BODY: if (priv->chunk_allocator) { buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data); if (!buffer) { g_return_val_if_fail (!io->item || !io->item->new_api, FALSE); soup_message_io_pause (msg); return FALSE; } } else { if (!stack_buf) stack_buf = alloca (RESPONSE_BLOCK_SIZE); buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY, stack_buf, RESPONSE_BLOCK_SIZE); } nread = g_pollable_stream_read (io->body_istream, (guchar *)buffer->data, buffer->length, blocking, cancellable, error); if (nread > 0) { buffer->length = nread; soup_message_body_got_chunk (io->read_body, buffer); soup_message_got_chunk (msg, buffer); soup_buffer_free (buffer); break; } soup_buffer_free (buffer); if (nread == -1) return FALSE; /* else nread == 0 */ io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; break; case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; soup_message_got_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: io->read_state = SOUP_MESSAGE_IO_STATE_DONE; if (io->mode == SOUP_MESSAGE_IO_SERVER) io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; break; default: g_return_val_if_reached (FALSE); } return TRUE; }
static void do_request_to_session (SoupSession *session, const char *uri, const char *comment, gboolean expect_timeout) { SoupRequest *req; SoupMessage *msg; GInputStream *stream; GError *error = NULL; gboolean finished = FALSE; debug_printf (1, " req %s\n", comment); req = soup_session_request (session, uri, NULL); msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (req)); g_signal_connect (msg, "finished", G_CALLBACK (message_finished), &finished); stream = soup_test_request_send (req, NULL, &error); if (expect_timeout && !error) { debug_printf (1, " FAILED: request did not time out\n"); errors++; } else if (expect_timeout && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { debug_printf (1, " FAILED: wrong error: %s\n", error->message); errors++; } else if (!expect_timeout && error) { debug_printf (1, " FAILED: expected success but got error: %s\n", error->message); errors++; } g_clear_error (&error); if (stream) { soup_test_request_close_stream (req, stream, NULL, &error); if (error) { debug_printf (1, " ERROR closing string: %s", error->message); errors++; } g_object_unref (stream); } if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && !soup_message_is_keepalive (msg)) { debug_printf (1, " ERROR: message is not keepalive!\n"); errors++; } if (!finished) { debug_printf (1, " ERROR: 'finished' was not emitted\n"); errors++; } g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (message_finished), &finished); g_object_unref (msg); g_object_unref (req); }