static void gotHeadersCallback(SoupMessage* msg, gpointer data) { // For 401, we will accumulate the resource body, and only use it // in case authentication with the soup feature doesn't happen if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) { soup_message_body_set_accumulate(msg->response_body, TRUE); return; } // For all the other responses, we handle each chunk ourselves, // and we don't need msg->response_body to contain all of the data // we got, when we finish downloading. soup_message_body_set_accumulate(msg->response_body, FALSE); RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); // The content-sniffed callback will handle the response if WebCore // require us to sniff. if(!handle || statusWillBeHandledBySoup(msg->status_code) || handle->shouldContentSniff()) return; ResourceHandleInternal* d = handle->getInternal(); if (d->m_cancelled) return; ResourceHandleClient* client = handle->client(); if (!client) return; fillResponseFromMessage(msg, &d->m_response); client->didReceiveResponse(handle.get(), d->m_response); }
/** * e_soap_message_new: * @method: the HTTP method for the created request. * @uri_string: the destination endpoint (as a string). * @standalone: ??? FIXME * @xml_encoding: ??? FIXME * @env_prefix: ??? FIXME * @env_uri: ??? FIXME * * Creates a new empty #ESoapMessage, which will connect to @uri_string. * * Returns: the new #ESoapMessage (or %NULL if @uri_string could not be * parsed). * * Since: 2.92 */ ESoapMessage * e_soap_message_new (const gchar *method, const gchar *uri_string, gboolean standalone, const gchar *xml_encoding, const gchar *env_prefix, const gchar *env_uri) { ESoapMessage *msg; SoupURI *uri; uri = soup_uri_new (uri_string); if (!uri) return NULL; msg = e_soap_message_new_from_uri (method, uri, standalone, xml_encoding, env_prefix, env_uri); soup_uri_free (uri); /* Don't accumulate body data into a huge buffer. * Instead, parse it as it arrives. */ soup_message_body_set_accumulate (SOUP_MESSAGE (msg)->response_body, FALSE); g_signal_connect (msg, "got-headers", G_CALLBACK (soap_got_headers), NULL); g_signal_connect (msg, "got-chunk", G_CALLBACK (soap_got_chunk), NULL); g_signal_connect (msg, "restarted", G_CALLBACK (soap_restarted), NULL); return msg; }
static void do_large_chunk_test (SoupSession *session, SoupURI *base_uri) { SoupMessage *msg; char *buf_data; int i; LargeChunkData lcd; debug_printf (1, "PUT w/ large chunk\n"); msg = soup_message_new_from_uri ("PUT", base_uri); buf_data = g_malloc0 (LARGE_CHUNK_SIZE); for (i = 0; i < LARGE_CHUNK_SIZE; i++) buf_data[i] = i & 0xFF; lcd.buf = soup_buffer_new (SOUP_MEMORY_TAKE, buf_data, LARGE_CHUNK_SIZE); lcd.offset = 0; soup_message_body_append_buffer (msg->request_body, lcd.buf); soup_message_body_set_accumulate (msg->request_body, FALSE); g_signal_connect (msg, "wrote_body_data", G_CALLBACK (large_wrote_body_data), &lcd); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } soup_buffer_free (lcd.buf); g_object_unref (msg); }
static void do_response_test (SoupSession *session, SoupURI *base_uri) { GetTestData gtd; SoupMessage *msg; const char *client_md5, *server_md5; debug_printf (1, "GET\n"); gtd.current_chunk = NULL; gtd.length = 0; gtd.check = g_checksum_new (G_CHECKSUM_MD5); msg = soup_message_new_from_uri ("GET", base_uri); soup_message_body_set_accumulate (msg->response_body, FALSE); G_GNUC_BEGIN_IGNORE_DEPRECATIONS; soup_message_set_chunk_allocator (msg, chunk_allocator, >d, NULL); G_GNUC_END_IGNORE_DEPRECATIONS; g_signal_connect (msg, "got_chunk", G_CALLBACK (got_chunk), >d); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } if (msg->response_body->data) { debug_printf (1, " msg->response_body set!\n"); errors++; } if (soup_message_headers_get_content_length (msg->response_headers) != gtd.length) { debug_printf (1, " received length mismatch: %d vs %d\n", (int)soup_message_headers_get_content_length (msg->response_headers), gtd.length); errors++; } client_md5 = g_checksum_get_string (gtd.check); server_md5 = soup_message_headers_get_one (msg->response_headers, "Content-MD5"); if (!server_md5 || strcmp (client_md5, server_md5) != 0) { debug_printf (1, " client/server data mismatch: %s vs %s\n", client_md5, server_md5 ? server_md5 : "(null)"); errors++; } g_object_unref (msg); g_checksum_free (gtd.check); }
static void do_temporary_test (SoupSession *session, SoupURI *base_uri) { SoupMessage *msg; char *client_md5; const char *server_md5; debug_printf (1, "PUT w/ temporary buffers\n"); msg = soup_message_new_from_uri ("PUT", base_uri); soup_message_body_append (msg->request_body, SOUP_MEMORY_TEMPORARY, "one\r\n", 5); soup_message_body_append (msg->request_body, SOUP_MEMORY_STATIC, "two\r\n", 5); soup_message_body_set_accumulate (msg->request_body, FALSE); client_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, "one\r\ntwo\r\n", 10); g_signal_connect (msg, "wrote_chunk", G_CALLBACK (temp_test_wrote_chunk), session); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } server_md5 = soup_message_headers_get_one (msg->response_headers, "Content-MD5"); if (!server_md5 || strcmp (client_md5, server_md5) != 0) { debug_printf (1, " client/server data mismatch: %s vs %s\n", client_md5, server_md5 ? server_md5 : "(null)"); errors++; } g_free (client_md5); g_object_unref (msg); }
static void connect_to_server (SnraClient * client, const gchar * server, int port) { SoupMessage *msg; char *url = g_strdup_printf ("http://%s:%u/client/player_events", server, port); if (client->connecting == FALSE) { g_print ("Attemping to connect to server %s:%d\n", server, port); client->connecting = TRUE; } g_free (client->connected_server); client->connected_server = g_strdup (server); client->connected_port = port; msg = soup_message_new ("GET", url); soup_message_body_set_accumulate (msg->response_body, FALSE); g_signal_connect (msg, "got-chunk", (GCallback) handle_received_chunk, client); soup_session_queue_message (client->soup, msg, (SoupSessionCallback) handle_connection_closed_cb, client); g_free (url); }
/* executed in sub thread */ static void worker_got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk, ThreadData *thdata) { xmlDocPtr doc; gchar *data, *ptr; data = g_strndup (chunk->data, chunk->length); soup_message_body_set_accumulate (msg->response_body, FALSE); #ifdef DEBUG_WEB_PROV if (*data) g_print (">>>> WORKER\n%s\n<<<< WORKER\n", data); #endif if (!thdata->cdata->session_id) { ptr = strstr (data, "</reply>"); if (ptr) { gchar status; guint counter_id; ptr += 8; *ptr = 0; doc = decode_buffer_response (thdata->cnc, thdata->cdata, chunk, &status, &counter_id); if (!doc || (status != 'O')) { /* this cannot happen at the moment */ g_assert_not_reached (); if (doc) xmlFreeDoc (doc); } else { g_rec_mutex_lock (& (thdata->cdata->mutex)); g_assert (thdata->cdata->worker_counter == counter_id); g_rec_mutex_unlock (& (thdata->cdata->mutex)); xmlFreeDoc (doc); } } } g_free (data); }
RygelHTTPResponse* rygel_http_response_construct (GType object_type, SoupServer* server, SoupMessage* msg, gboolean partial, GCancellable* cancellable) { #line 127 "rygel-http-response_seekable-response.c" RygelHTTPResponse * self; SoupMessage* _tmp0_; #line 34 "rygel-http-response_seekable-response.vala" g_return_val_if_fail (server != NULL, NULL); #line 34 "rygel-http-response_seekable-response.vala" g_return_val_if_fail (msg != NULL, NULL); #line 34 "rygel-http-response_seekable-response.vala" self = (RygelHTTPResponse*) g_object_new (object_type, NULL); #line 38 "rygel-http-response_seekable-response.vala" rygel_http_response_set_server (self, server); #line 39 "rygel-http-response_seekable-response.vala" self->msg = (_tmp0_ = _g_object_ref0 (msg), _g_object_unref0 (self->msg), _tmp0_); #line 40 "rygel-http-response_seekable-response.vala" rygel_state_machine_set_cancellable ((RygelStateMachine*) self, cancellable); #line 42 "rygel-http-response_seekable-response.vala" if (partial) { #line 43 "rygel-http-response_seekable-response.vala" soup_message_set_status (self->msg, (guint) SOUP_STATUS_PARTIAL_CONTENT); #line 146 "rygel-http-response_seekable-response.c" } else { #line 45 "rygel-http-response_seekable-response.vala" soup_message_set_status (self->msg, (guint) SOUP_STATUS_OK); #line 150 "rygel-http-response_seekable-response.c" } #line 48 "rygel-http-response_seekable-response.vala" soup_message_body_set_accumulate (self->msg->response_body, FALSE); #line 50 "rygel-http-response_seekable-response.vala" if (rygel_state_machine_get_cancellable ((RygelStateMachine*) self) != NULL) { #line 51 "rygel-http-response_seekable-response.vala" g_signal_connect_object (rygel_state_machine_get_cancellable ((RygelStateMachine*) self), "cancelled", (GCallback) _rygel_http_response_on_cancelled_g_cancellable_cancelled, self, 0); #line 158 "rygel-http-response_seekable-response.c" } return self; }
static void do_request_test (SoupSession *session, SoupURI *base_uri, RequestTestFlags flags) { SoupURI *uri = base_uri; PutTestData ptd; SoupMessage *msg; const char *client_md5, *server_md5; GChecksum *check; int i, length; debug_printf (1, "PUT"); if (flags & HACKY_STREAMING) debug_printf (1, " w/ hacky streaming"); else if (flags & PROPER_STREAMING) debug_printf (1, " w/ proper streaming"); if (flags & RESTART) { debug_printf (1, " and restart"); uri = soup_uri_copy (base_uri); soup_uri_set_path (uri, "/redirect"); } debug_printf (1, "\n"); ptd.session = session; setup_request_body (&ptd); ptd.streaming = flags & (HACKY_STREAMING | PROPER_STREAMING); check = g_checksum_new (G_CHECKSUM_MD5); length = 0; for (i = 0; i < 3; i++) { g_checksum_update (check, (guchar *)ptd.chunks[i]->data, ptd.chunks[i]->length); length += ptd.chunks[i]->length; } client_md5 = g_checksum_get_string (check); msg = soup_message_new_from_uri ("PUT", uri); soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED); soup_message_body_set_accumulate (msg->request_body, FALSE); soup_message_set_chunk_allocator (msg, error_chunk_allocator, NULL, NULL); if (flags & HACKY_STREAMING) { g_signal_connect (msg, "wrote_chunk", G_CALLBACK (write_next_chunk_streaming_hack), &ptd); if (flags & RESTART) { g_signal_connect (msg, "restarted", G_CALLBACK (restarted_streaming_hack), &ptd); } } else { g_signal_connect (msg, "wrote_chunk", G_CALLBACK (write_next_chunk), &ptd); } if (flags & PROPER_STREAMING) { soup_message_set_flags (msg, SOUP_MESSAGE_CAN_REBUILD); if (flags & RESTART) { g_signal_connect (msg, "restarted", G_CALLBACK (restarted_streaming), &ptd); } } g_signal_connect (msg, "wrote_headers", G_CALLBACK (write_next_chunk), &ptd); g_signal_connect (msg, "wrote_body_data", G_CALLBACK (wrote_body_data), &ptd); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } if (msg->request_body->data) { debug_printf (1, " msg->request_body set!\n"); errors++; } if (msg->request_body->length != length || length != ptd.nwrote) { debug_printf (1, " sent length mismatch: %d vs %d vs %d\n", (int)msg->request_body->length, length, ptd.nwrote); errors++; } server_md5 = soup_message_headers_get_one (msg->response_headers, "Content-MD5"); if (!server_md5 || strcmp (client_md5, server_md5) != 0) { debug_printf (1, " client/server data mismatch: %s vs %s\n", client_md5, server_md5 ? server_md5 : "(null)"); errors++; } g_object_unref (msg); g_checksum_free (check); if (uri != base_uri) soup_uri_free (uri); }
static void korva_upnp_file_server_handle_request (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data) { KorvaUPnPFileServer *self = KORVA_UPNP_FILE_SERVER (user_data); GMatchInfo *info; char *id; GFile *file; KorvaUPnPHostData *data; ServeData *serve_data; SoupRange *ranges = NULL; int length; const char *content_features; GError *error = NULL; goffset size; if (msg->method != SOUP_METHOD_HEAD && msg->method != SOUP_METHOD_GET) { soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); return; } g_debug ("Got %s request for uri: %s", msg->method, path); soup_message_headers_foreach (msg->request_headers, print_header, NULL); soup_server_pause_message (server, msg); soup_message_set_status (msg, SOUP_STATUS_OK); if (!g_regex_match (self->priv->path_regex, path, 0, &info)) { soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); g_match_info_free (info); goto out; } id = g_match_info_fetch (info, 1); g_match_info_free (info); file = g_hash_table_lookup (self->priv->id_map, id); g_free (id); if (file == NULL) { soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); goto out; } data = g_hash_table_lookup (self->priv->host_data, file); if (data == NULL) { soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); goto out; } if (!korva_upnp_host_data_valid_for_peer (data, soup_client_context_get_host (client))) { soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); goto out; } serve_data = g_slice_new0 (ServeData); serve_data->host_data = data; g_object_add_weak_pointer (G_OBJECT (data), (gpointer *) &(serve_data->host_data)); korva_upnp_host_data_add_request (data); size = korva_upnp_host_data_get_size (data); if (soup_message_headers_get_ranges (msg->request_headers, size, &ranges, &length)) { goffset start, end; start = ranges[0].start; end = ranges[0].end; if (start > size || start > end || end > size) { soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE); g_slice_free (ServeData, serve_data); goto out; } else { soup_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT); soup_message_headers_set_content_range (msg->response_headers, start, end, size); } serve_data->start = start; serve_data->end = end; } else { serve_data->start = 0; serve_data->end = size - 1; soup_message_set_status (msg, SOUP_STATUS_OK); } soup_message_headers_set_content_length (msg->response_headers, serve_data->end - serve_data->start + 1); soup_message_headers_set_content_type (msg->response_headers, korva_upnp_host_data_get_content_type (data), NULL); content_features = soup_message_headers_get_one (msg->request_headers, "getContentFeatures.dlna.org"); if (content_features != NULL && atol (content_features) == 1) { const GVariant *value; value = korva_upnp_host_data_lookup_meta_data (data, "DLNAProfile"); if (value == NULL) { soup_message_headers_append (msg->response_headers, "contentFeatures.dlna.org", "*"); } else { soup_message_headers_append (msg->response_headers, "contentFeatures.dlna.org", korva_upnp_host_data_get_protocol_info (data)); } } soup_message_headers_append (msg->response_headers, "Connection", "close"); g_debug ("Response headers:"); soup_message_headers_foreach (msg->response_headers, print_header, NULL); if (g_ascii_strcasecmp (msg->method, "HEAD") == 0) { g_debug ("Handled HEAD request of %s: %d", path, msg->status_code); g_slice_free (ServeData, serve_data); goto out; } soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CONTENT_LENGTH); soup_message_body_set_accumulate (msg->response_body, FALSE); serve_data->stream = G_INPUT_STREAM (g_file_read (file, NULL, &error)); serve_data->server = server; if (error != NULL) { g_warning ("Failed to MMAP file %s: %s", path, error->message); g_error_free (error); g_slice_free (ServeData, serve_data); soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } g_seekable_seek (G_SEEKABLE (serve_data->stream), serve_data->start, G_SEEK_SET, NULL, NULL); /* Drop timeout until the message is done */ korva_upnp_host_data_cancel_timeout (data); g_signal_connect (msg, "wrote-chunk", G_CALLBACK (korva_upnp_file_server_on_wrote_chunk), serve_data); g_signal_connect (msg, "wrote-headers", G_CALLBACK (korva_upnp_file_server_on_wrote_chunk), serve_data); g_signal_connect (msg, "finished", G_CALLBACK (korva_upnp_file_server_on_finished), serve_data); out: if (ranges != NULL) { soup_message_headers_free_ranges (msg->request_headers, ranges); } soup_server_unpause_message (server, msg); }
// same stuff as net_get_* but without accumulating headers // push all donwloads to a customizable length queue gboolean download_unblocking( gchar *url, NetStatusCallback cb, gpointer data, gpointer cb2, gpointer cbdata2, guint track, GError **err) { SoupMessage *msg; CallbackInfo *info = NULL; SoupSession *soup_sess; gchar *agstr; STNET *stnet; soup_sess = soup_session_async_new(); #if LIBSOUP_VERSION > 2024000 if (rss_soup_jar) { soup_session_add_feature(soup_sess, SOUP_SESSION_FEATURE(rss_soup_jar)); } #endif if (cb && data) { info = g_new0(CallbackInfo, 1); info->user_cb = cb; info->user_data = data; info->current = 0; info->total = 0; info->ss = soup_sess; } g_signal_connect (soup_sess, "authenticate", G_CALLBACK (authenticate), (gpointer)url); #if LIBSOUP_VERSION < 2003000 g_signal_connect (soup_sess, "reauthenticate", G_CALLBACK (reauthenticate), (gpointer)url); #endif /* Queue an async HTTP request */ msg = soup_message_new ("GET", url); if (!msg) { g_free(info); g_set_error(err, NET_ERROR, NET_ERROR_GENERIC, "%s", soup_status_get_phrase(2)); //invalid url return FALSE; } if (track) { //we want to be able to abort this session by calling //abort_all_soup g_hash_table_insert(rf->session, soup_sess, msg); g_hash_table_insert(rf->abort_session, soup_sess, msg); g_hash_table_insert(rf->key_session, data, soup_sess); } agstr = g_strdup_printf("Evolution/%s; Evolution-RSS/%s", EVOLUTION_VERSION_STRING, VERSION); #if LIBSOUP_VERSION < 2003000 soup_message_add_header (msg->request_headers, "User-Agent", agstr); #else soup_message_headers_append (msg->request_headers, "User-Agent", agstr); #endif g_free(agstr); if (info) { g_signal_connect(G_OBJECT(msg), "got_chunk", G_CALLBACK(got_chunk_cb), info); //FIXME Find a way to free this maybe weak_ref soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT); soup_message_add_header_handler (msg, "got_body", "Location", G_CALLBACK (redirect_handler), info); } soup_message_body_set_accumulate (msg->response_body, FALSE); stnet = g_new0(STNET, 1); stnet->ss = soup_sess; stnet->sm = msg; stnet->cb2 = cb2; stnet->cbdata2 = cbdata2; stnet->url = url; stnet->callback = idle_callback; stnet->data = stnet; if (!net_qid) net_qid = g_idle_add((GSourceFunc)net_queue_dispatcher, NULL); stnet->callback(stnet->data); //// g_object_add_weak_pointer (G_OBJECT(msg), (gpointer)info); g_object_weak_ref (G_OBJECT(msg), unblock_free, soup_sess); // g_object_weak_ref (G_OBJECT(soup_sess), unblock_free, soup_sess); // GMainLoop *mainloop = g_main_loop_new (g_main_context_default (), FALSE); // g_timeout_add (10 * 1000, &conn_mainloop_quit, mainloop); return TRUE; }
void aws_s3_client_read_async (AwsS3Client *client, const gchar *bucket, const gchar *path, AwsS3ClientDataHandler handler, gpointer handler_data, GDestroyNotify handler_notify, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { AwsS3ClientPrivate *priv = aws_s3_client_get_instance_private (client); g_autoptr(GTask) task = NULL; g_autofree gchar *auth = NULL; g_autofree gchar *date_str = NULL; g_autofree gchar *signature = NULL; g_autofree gchar *uri = NULL; g_autoptr(SoupDate) date = NULL; g_autoptr(GString) str = NULL; g_autoptr(SoupMessage) message = NULL; ReadState *state; guint16 port; g_return_if_fail (AWS_IS_S3_CLIENT(client)); g_return_if_fail (bucket); g_return_if_fail (path); g_return_if_fail (g_utf8_validate(bucket, -1, NULL)); g_return_if_fail (g_utf8_validate(path, -1, NULL)); g_return_if_fail (handler != NULL); task = g_task_new (client, cancellable, callback, user_data); g_task_set_source_tag (task, aws_s3_client_read_async); state = read_state_new (handler, handler_data, handler_notify); g_task_set_task_data (task, state, read_state_free); /* * Strip leading '/' from the path. */ while (g_utf8_get_char (path) == '/') path = g_utf8_next_char (path); /* * Determine our connection port. */ port = priv->port_set ? priv->port : (priv->secure ? 443 : 80); /* * Build our HTTP request message. */ uri = g_strdup_printf ("%s://%s:%d/%s/%s", priv->secure ? "https" : "http", priv->host, port, bucket, path); message = soup_message_new (SOUP_METHOD_GET, uri); soup_message_body_set_accumulate (message->response_body, FALSE); g_signal_connect_object (message, "got-chunk", G_CALLBACK (aws_s3_client_read_got_chunk), task, 0); g_signal_connect_object (message, "got-headers", G_CALLBACK (aws_s3_client_read_got_headers), task, 0); /* * Set the Host header for systems that may be proxying. */ if (priv->host != NULL) soup_message_headers_append (message->request_headers, "Host", priv->host); /* * Add the Date header which we need for signing. */ date = soup_date_new_from_now (0); date_str = soup_date_to_string (date, SOUP_DATE_HTTP); soup_message_headers_append (message->request_headers, "Date", date_str); /* * Sign our request. */ str = g_string_new ("GET\n\n\n"); g_string_append_printf (str, "%s\n", date_str); g_string_append_printf (str, "/%s/%s", bucket, path); signature = aws_credentials_sign (priv->creds, str->str, str->len, G_CHECKSUM_SHA1); /* * Attach request signature to our headers. */ auth = g_strdup_printf ("AWS %s:%s", aws_credentials_get_access_key (priv->creds), signature); soup_message_headers_append (message->request_headers, "Authorization", auth); /* * Submit our request to the target. */ soup_session_queue_message (SOUP_SESSION (client), g_steal_pointer (&message), aws_s3_client_read_cb, g_steal_pointer (&task)); }
static void do_fully_async_test (SoupSession *session, const char *base_uri, const char *sub_uri, gboolean fast_request, guint expected_status) { GMainLoop *loop; FullyAsyncData ad; SoupMessage *msg; char *uri; loop = g_main_loop_new (NULL, FALSE); uri = g_build_filename (base_uri, sub_uri, NULL); debug_printf (1, "GET %s\n", uri); msg = soup_message_new (SOUP_METHOD_GET, uri); g_free (uri); ad.loop = loop; ad.session = session; ad.msg = msg; ad.chunks_ready = FALSE; ad.chunk_wanted = FALSE; ad.did_first_timeout = FALSE; ad.read_so_far = 0; ad.expected_status = expected_status; /* Since we aren't going to look at the final value of * msg->response_body, we tell libsoup to not even bother * generating it. */ soup_message_body_set_accumulate (msg->response_body, FALSE); /* Connect to "got_headers", from which we'll decide where to * go next. */ g_signal_connect (msg, "got_headers", G_CALLBACK (fully_async_got_headers), &ad); /* Queue the request */ soup_session_queue_message (session, msg, fully_async_finished, &ad); /* In a real program, we'd probably just return at this point. * Eventually the caller would return all the way to the main * loop, and then eventually, some event would cause the * application to request a chunk of data from the message * response. * * In our test program, there is no "real" main loop, so we * had to create our own. We use a timeout to represent the * event that causes the app to decide to request another body * chunk. We use short timeouts in one set of tests, and long * ones in another, to test both the * chunk-requested-before-its-been-read and * chunk-read-before-its-been-requested cases. */ ad.timeout = g_timeout_add (fast_request ? 0 : 100, fully_async_request_chunk, &ad); g_main_loop_run (ad.loop); g_main_loop_unref (ad.loop); }
static void do_synchronously_async_test (SoupSession *session, const char *base_uri, const char *sub_uri, guint expected_status) { SoupMessage *msg; char *uri; gsize read_so_far; SoupBuffer *chunk; uri = g_build_filename (base_uri, sub_uri, NULL); debug_printf (1, "GET %s\n", uri); msg = soup_message_new (SOUP_METHOD_GET, uri); g_free (uri); /* As in the fully-async case, we turn off accumulate, as an * optimization. */ soup_message_body_set_accumulate (msg->response_body, FALSE); /* Send the message, get back headers */ sync_async_send (session, msg); if (sync_async_is_finished (msg) && expected_status == SOUP_STATUS_OK) { debug_printf (1, " finished without reading response!\n"); errors++; } else if (!sync_async_is_finished (msg) && expected_status != SOUP_STATUS_OK) { debug_printf (1, " request failed to fail!\n"); errors++; } /* Now we're ready to read the response body (though we could * put that off until later if we really wanted). */ read_so_far = 0; while ((chunk = sync_async_read_chunk (msg))) { debug_printf (2, " read chunk from %lu - %lu\n", (unsigned long) read_so_far, (unsigned long) read_so_far + chunk->length); if (read_so_far + chunk->length > correct_response->length) { debug_printf (1, " read too far! (%lu > %lu)\n", (unsigned long) read_so_far + chunk->length, (unsigned long) correct_response->length); errors++; } else if (memcmp (chunk->data, correct_response->data + read_so_far, chunk->length) != 0) { debug_printf (1, " data mismatch in block starting at %lu\n", (unsigned long) read_so_far); errors++; } read_so_far += chunk->length; soup_buffer_free (chunk); } if (!sync_async_is_finished (msg) || (msg->status_code == SOUP_STATUS_OK && read_so_far != correct_response->length)) { debug_printf (1, " loop ended before message was fully read!\n"); errors++; } else if (msg->status_code != expected_status) { debug_printf (1, " unexpected final status: %d %s !\n", msg->status_code, msg->reason_phrase); errors++; } sync_async_cleanup (msg); g_object_unref (msg); }
static void send_chunked_file (SoupServer * server, SoupMessage * message, DAAPRecord * record, guint64 filesize, guint64 offset, const gchar * transcode_mimetype) { gchar *format = NULL; gchar *location = NULL; GInputStream *stream = NULL; gboolean has_video; GError *error = NULL; ChunkData *cd = NULL; cd = g_new (ChunkData, 1); if (NULL == cd) { g_warning ("Error allocating chunk\n"); goto _error; } g_object_get (record, "location", &location, "has-video", &has_video, NULL); if (NULL == location) { g_warning ("Error getting location from record\n"); goto _error; } /* FIXME: This crashes on powerpc-440fp-linux-gnu: * g_debug ("Sending %s chunked from offset %" G_GUINT64_FORMAT ".", location, offset); */ cd->server = server; stream = G_INPUT_STREAM (daap_record_read (record, &error)); if (error != NULL) { g_warning ("Couldn't open %s: %s.", location, error->message); goto _error; } g_object_get (record, "format", &format, NULL); if (NULL == format) { g_warning ("Error getting format from record\n"); goto _error; } // Not presently transcoding videos (see also same comments elsewhere). if (should_transcode (format, has_video, transcode_mimetype)) { #ifdef HAVE_GSTREAMERAPP cd->stream = dmap_gst_input_stream_new (transcode_mimetype, stream); #else g_warning ("Transcode format %s not supported", transcode_mimetype); cd->stream = stream; #endif /* HAVE_GSTREAMERAPP */ } else { g_debug ("Not transcoding %s", location); cd->stream = stream; } if (cd->stream == NULL) { g_warning ("Could not set up input stream"); goto _error; } if (offset != 0) { if (g_seekable_seek (G_SEEKABLE (cd->stream), offset, G_SEEK_SET, NULL, &error) == FALSE) { g_warning ("Error seeking: %s.", error->message); goto _error; } filesize -= offset; } /* Free memory after each chunk sent out over network. */ soup_message_body_set_accumulate (message->response_body, FALSE); if (! should_transcode (format, has_video, transcode_mimetype)) { /* NOTE: iTunes seems to require this or it stops reading * video data after about 2.5MB. Perhaps this is so iTunes * knows how much data to buffer. */ g_debug ("Using HTTP 1.1 content length encoding."); soup_message_headers_set_encoding (message->response_headers, SOUP_ENCODING_CONTENT_LENGTH); /* NOTE: iTunes 8 (and other versions?) will not seek * properly without a Content-Length header. */ g_debug ("Content length is %" G_GUINT64_FORMAT ".", filesize); soup_message_headers_set_content_length (message->response_headers, filesize); } else if (soup_message_get_http_version (message) == SOUP_HTTP_1_0) { /* NOTE: Roku clients support only HTTP 1.0. */ #ifdef HAVE_ENCODING_EOF g_debug ("Using HTTP 1.0 encoding."); soup_message_headers_set_encoding (message->response_headers, SOUP_ENCODING_EOF); #else g_warning ("Received HTTP 1.0 request, but not built with HTTP 1.0 support"); soup_message_headers_set_encoding (message->response_headers, SOUP_ENCODING_CHUNKED); #endif } else { /* NOTE: Can not provide Content-Length when performing * real-time transcoding. */ g_debug ("Using HTTP 1.1 chunked encoding."); soup_message_headers_set_encoding (message->response_headers, SOUP_ENCODING_CHUNKED); } soup_message_headers_append (message->response_headers, "Connection", "Close"); soup_message_headers_append (message->response_headers, "Content-Type", "application/x-dmap-tagged"); g_signal_connect (message, "wrote_headers", G_CALLBACK (dmap_write_next_chunk), cd); g_signal_connect (message, "wrote_chunk", G_CALLBACK (dmap_write_next_chunk), cd); g_signal_connect (message, "finished", G_CALLBACK (dmap_chunked_message_finished), cd); /* NOTE: cd g_free'd by chunked_message_finished(). */ return; _error: soup_message_set_status (message, SOUP_STATUS_INTERNAL_SERVER_ERROR); if (NULL != cd) { g_free (cd); } if (NULL != format) { g_free (format); } if (NULL != location) { g_free (location); } if (NULL != error) { g_error_free (error); } if (NULL != cd->stream) { g_input_stream_close (cd->stream, NULL, NULL); } if (NULL != stream) { g_input_stream_close (cd->stream, NULL, NULL); } return; }
static bool startHttp(ResourceHandle* handle) { ASSERT(handle); SoupSession* session = handle->defaultSession(); ensureSessionIsInitialized(session); ResourceHandleInternal* d = handle->getInternal(); ResourceRequest request(handle->request()); KURL url(request.url()); url.removeFragmentIdentifier(); request.setURL(url); d->m_msg = request.toSoupMessage(); if (!d->m_msg) return false; if(!handle->shouldContentSniff()) soup_message_disable_feature(d->m_msg, SOUP_TYPE_CONTENT_SNIFFER); g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle); g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle); g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle); g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), handle); g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(handle)); FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { size_t numElements = httpBody->elements().size(); // handle the most common case (i.e. no file upload) if (numElements < 2) { Vector<char> body; httpBody->flatten(body); soup_message_set_request(d->m_msg, d->m_request.httpContentType().utf8().data(), SOUP_MEMORY_COPY, body.data(), body.size()); } else { /* * we have more than one element to upload, and some may * be (big) files, which we will want to mmap instead of * copying into memory; TODO: support upload of non-local * (think sftp://) files by using GIO? */ soup_message_body_set_accumulate(d->m_msg->request_body, FALSE); for (size_t i = 0; i < numElements; i++) { const FormDataElement& element = httpBody->elements()[i]; if (element.m_type == FormDataElement::data) soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size()); else { /* * mapping for uploaded files code inspired by technique used in * libsoup's simple-httpd test */ GError* error = 0; gchar* fileName = filenameFromString(element.m_filename); GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error); g_free(fileName); if (error) { g_error_free(error); g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, handle); g_object_unref(d->m_msg); d->m_msg = 0; return false; } SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping), g_mapped_file_get_length(fileMapping), fileMapping, #if GLIB_CHECK_VERSION(2, 21, 3) reinterpret_cast<GDestroyNotify>(g_mapped_file_unref)); #else reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); #endif soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer); soup_buffer_free(soupBuffer); } } } }
static void do_request_test (SoupSession *session, SoupURI *base_uri, int test) { SoupURI *uri = base_uri; PutTestData ptd; SoupMessage *msg; const char *client_md5, *server_md5; GChecksum *check; int i, length; gboolean streaming = FALSE; switch (test) { case 0: debug_printf (1, "PUT\n"); break; case 1: debug_printf (1, "PUT w/ streaming\n"); streaming = TRUE; break; case 2: debug_printf (1, "PUT w/ streaming and restart\n"); streaming = TRUE; uri = soup_uri_copy (base_uri); soup_uri_set_path (uri, "/redirect"); break; } ptd.session = session; make_put_chunk (&ptd.chunks[0], "one\r\n"); make_put_chunk (&ptd.chunks[1], "two\r\n"); make_put_chunk (&ptd.chunks[2], "three\r\n"); ptd.next = ptd.nwrote = ptd.nfreed = 0; ptd.streaming = streaming; check = g_checksum_new (G_CHECKSUM_MD5); length = 0; for (i = 0; i < 3; i++) { g_checksum_update (check, (guchar *)ptd.chunks[i]->data, ptd.chunks[i]->length); length += ptd.chunks[i]->length; } client_md5 = g_checksum_get_string (check); msg = soup_message_new_from_uri ("PUT", uri); soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED); soup_message_body_set_accumulate (msg->request_body, FALSE); soup_message_set_chunk_allocator (msg, error_chunk_allocator, NULL, NULL); if (streaming) { g_signal_connect (msg, "wrote_chunk", G_CALLBACK (write_next_chunk_streaming_hack), &ptd); g_signal_connect (msg, "restarted", G_CALLBACK (restarted_streaming_hack), &ptd); } else { g_signal_connect (msg, "wrote_chunk", G_CALLBACK (write_next_chunk), &ptd); } g_signal_connect (msg, "wrote_headers", G_CALLBACK (write_next_chunk), &ptd); g_signal_connect (msg, "wrote_body_data", G_CALLBACK (wrote_body_data), &ptd); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } if (msg->request_body->data) { debug_printf (1, " msg->request_body set!\n"); errors++; } if (msg->request_body->length != length || length != ptd.nwrote) { debug_printf (1, " sent length mismatch: %d vs %d vs %d\n", (int)msg->request_body->length, length, ptd.nwrote); errors++; } server_md5 = soup_message_headers_get_one (msg->response_headers, "Content-MD5"); if (!server_md5 || strcmp (client_md5, server_md5) != 0) { debug_printf (1, " client/server data mismatch: %s vs %s\n", client_md5, server_md5 ? server_md5 : "(null)"); errors++; } g_object_unref (msg); g_checksum_free (check); if (uri != base_uri) soup_uri_free (uri); }