Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
/**
 * 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);
}
Exemplo n.º 4
0
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, &gtd, NULL);
	G_GNUC_END_IGNORE_DEPRECATIONS;
	g_signal_connect (msg, "got_chunk",
			  G_CALLBACK (got_chunk), &gtd);
	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);
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
/* 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);
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
// 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;
}
Exemplo n.º 12
0
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));
}
Exemplo n.º 13
0
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);
}
Exemplo n.º 14
0
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);
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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);
                }
            }
        }
    }
Exemplo n.º 17
0
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);
}