static void handle_signout_request (LiaWebview *self, EvdHttpConnection *conn, EvdHttpRequest *request, AuthData *auth_data) { SoupMessageHeaders *headers; gchar *cookie; if (auth_data != NULL) g_hash_table_remove (self->priv->auth_sessions, auth_data->session_id); headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE); cookie = g_strdup_printf ("%s=; Expires=Sat, 01 Jan 2000 00:00:00 GMT", self->priv->sid_cookie_name); soup_message_headers_append (headers, "Set-Cookie", cookie); g_free (cookie); evd_web_service_respond (self->priv->web_service, conn, SOUP_STATUS_OK, headers, NULL, 0, NULL); soup_message_headers_free (headers); }
static void on_auth_response (GObject *obj, GAsyncResult *res, gpointer user_data) { LoginData *data = user_data; GError *error = NULL; GVariant *result; gchar *user_id; gint16 _bus_type; LiaBusType bus_type; gchar *auth_token; const gchar *session_id; SoupMessageHeaders *headers; gchar *cookie; result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (obj), res, &error); if (! result) { /* @TODO: Authentication failed */ g_debug ("Error, authentication failed: %s", error->message); respond_login_failed (data, error); g_error_free (error); goto out; } g_variant_get (result, "(ssn)", &user_id, &auth_token, &_bus_type); g_variant_unref (result); /* save session! */ bus_type = (LiaBusType) _bus_type; session_id = new_auth_session_data (data->self, user_id, bus_type, auth_token); headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE); cookie = g_strdup_printf ("%s=%s; path=%s; Secure; HttpOnly", data->self->priv->sid_cookie_name, session_id, data->self->priv->base_path); soup_message_headers_append (headers, "Set-Cookie", cookie); g_free (cookie); evd_web_service_respond (data->self->priv->web_service, data->conn, SOUP_STATUS_OK, headers, NULL, 0, NULL); soup_message_headers_free (headers); out: free_login_data (data); }
/** * youtube_proxy_upload_async: * @self: a #YoutubeProxy * @filename: filename * @fields: fields * @incomplete: incomplete * @callback: (scope async): callback to invoke upon completion * @weak_object: an object instance used to tie the life cycle of the proxy to * @user_data: user data to pass to the callback * @error: a #GError pointer, or %NULL * * Upload a file. * * Returns: %TRUE, or %FALSE if the file could not be opened */ gboolean youtube_proxy_upload_async (YoutubeProxy *self, const gchar *filename, GHashTable *fields, gboolean incomplete, YoutubeProxyUploadCallback callback, GObject *weak_object, gpointer user_data, GError **error) { SoupMultipart *mp; SoupMessage *message; SoupMessageHeaders *part_headers; SoupBuffer *sb; gchar *content_type; gchar *atom_xml; GMappedFile *map; YoutubeProxyUploadClosure *closure; map = g_mapped_file_new (filename, FALSE, error); if (*error != NULL) { g_warning ("Error opening file %s: %s", filename, (*error)->message); return FALSE; } mp = soup_multipart_new ("multipart/related"); atom_xml = _construct_upload_atom_xml (fields, incomplete); sb = soup_buffer_new_with_owner (atom_xml, strlen(atom_xml), atom_xml, (GDestroyNotify) g_free); part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART); soup_message_headers_append (part_headers, "Content-Type", "application/atom+xml; charset=UTF-8"); soup_multipart_append_part (mp, part_headers, sb); soup_buffer_free (sb); content_type = g_content_type_guess ( filename, (const guchar*) g_mapped_file_get_contents (map), g_mapped_file_get_length (map), NULL); sb = soup_buffer_new_with_owner (g_mapped_file_get_contents (map), g_mapped_file_get_length (map), map, (GDestroyNotify) g_mapped_file_unref); soup_message_headers_replace (part_headers, "Content-Type", content_type); soup_multipart_append_part (mp, part_headers, sb); soup_buffer_free (sb); soup_message_headers_free (part_headers); message = soup_form_request_new_from_multipart (UPLOAD_URL, mp); soup_multipart_free (mp); _set_upload_headers (self, message->request_headers, filename); closure = _upload_async_closure_new (self, callback, message, weak_object, user_data); g_signal_connect (message, "wrote-body-data", (GCallback) _message_wrote_data_cb, closure); _rest_proxy_queue_message (REST_PROXY (self), message, _upload_completed_cb, closure); return TRUE; }
static void handle_partial_get (SoupMessage *msg) { SoupRange *ranges; int nranges; SoupBuffer *full_response; /* 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 * 200 OK (and in particular, NOT already 206 Partial * 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) != SOUP_ENCODING_CONTENT_LENGTH || msg->response_body->length == 0 || !soup_message_body_get_accumulate (msg->response_body)) return; /* Oh, and there has to have been a valid Range header on the * request, of course. */ if (!soup_message_headers_get_ranges (msg->request_headers, msg->response_body->length, &ranges, &nranges)) return; full_response = soup_message_body_flatten (msg->response_body); if (!full_response) { soup_message_headers_free_ranges (msg->request_headers, ranges); return; } soup_message_set_status (msg, SOUP_STATUS_PARTIAL_CONTENT); soup_message_body_truncate (msg->response_body); if (nranges == 1) { SoupBuffer *range_buf; /* Single range, so just set Content-Range and fix the body. */ soup_message_headers_set_content_range (msg->response_headers, ranges[0].start, ranges[0].end, full_response->length); range_buf = soup_buffer_new_subbuffer (full_response, ranges[0].start, ranges[0].end - ranges[0].start + 1); soup_message_body_append_buffer (msg->response_body, range_buf); soup_buffer_free (range_buf); } else { SoupMultipart *multipart; SoupMessageHeaders *part_headers; SoupBuffer *part_body; const char *content_type; int i; /* Multiple ranges, so build a multipart/byteranges response * to replace msg->response_body with. */ multipart = soup_multipart_new ("multipart/byteranges"); content_type = soup_message_headers_get_one (msg->response_headers, "Content-Type"); for (i = 0; i < nranges; i++) { part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART); if (content_type) { soup_message_headers_append (part_headers, "Content-Type", content_type); } soup_message_headers_set_content_range (part_headers, ranges[i].start, ranges[i].end, full_response->length); part_body = soup_buffer_new_subbuffer (full_response, ranges[i].start, ranges[i].end - ranges[i].start + 1); soup_multipart_append_part (multipart, part_headers, part_body); soup_message_headers_free (part_headers); soup_buffer_free (part_body); } soup_multipart_to_message (multipart, msg->response_headers, msg->response_body); soup_multipart_free (multipart); } soup_buffer_free (full_response); soup_message_headers_free_ranges (msg->request_headers, ranges); }
static void post_photo_file_buffer_ready_cb (void **buffer, gsize count, GError *error, gpointer user_data) { PicasaWebService *self = user_data; OAuthAccount *account; GthFileData *file_data; SoupMultipart *multipart; const char *filename; char *value; GObject *metadata; DomDocument *doc; DomElement *entry; char *entry_buffer; gsize entry_len; SoupMessageHeaders *headers; SoupBuffer *body; void *resized_buffer; gsize resized_count; char *url; SoupMessage *msg; if (error != NULL) { post_photos_done (self, error); return; } account = web_service_get_current_account (WEB_SERVICE (self)); file_data = self->priv->post_photos->current->data; multipart = soup_multipart_new ("multipart/related"); /* the metadata part */ doc = dom_document_new (); entry = dom_document_create_element (doc, "entry", "xmlns", "http://www.w3.org/2005/Atom", "xmlns:gphoto", "http://schemas.google.com/photos/2007", "xmlns:media", "http://search.yahoo.com/mrss/", NULL); filename = g_file_info_get_display_name (file_data->info); dom_element_append_child (entry, dom_document_create_element_with_text (doc, filename, "title", NULL)); value = gth_file_data_get_attribute_as_string (file_data, "general::description"); if (value == NULL) value = gth_file_data_get_attribute_as_string (file_data, "general::title"); dom_element_append_child (entry, dom_document_create_element_with_text (doc, value, "summary", NULL)); value = gth_file_data_get_attribute_as_string (file_data, "general::location"); if (value != NULL) dom_element_append_child (entry, dom_document_create_element_with_text (doc, value, "gphoto:location", NULL)); metadata = g_file_info_get_attribute_object (file_data->info, "general::tags"); if (metadata != NULL) value = gth_string_list_join (GTH_STRING_LIST (gth_metadata_get_string_list (GTH_METADATA (metadata))), ", "); if (value != NULL) { DomElement *group; group = dom_document_create_element (doc, "media:group", NULL); dom_element_append_child (group, dom_document_create_element_with_text (doc, value, "media:keywords", NULL)); dom_element_append_child (entry, group); g_free (value); } dom_element_append_child (entry, dom_document_create_element (doc, "category", "scheme", "http://schemas.google.com/g/2005#kind", "term", "http://schemas.google.com/photos/2007#photo", NULL)); dom_element_append_child (DOM_ELEMENT (doc), entry); entry_buffer = dom_document_dump (doc, &entry_len); headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); soup_message_headers_append (headers, "Content-Type", "application/atom+xml"); body = soup_buffer_new (SOUP_MEMORY_TAKE, entry_buffer, entry_len); soup_multipart_append_part (multipart, headers, body); soup_buffer_free (body); soup_message_headers_free (headers); g_object_unref (doc); /* the file part */ if (_g_buffer_resize_image (*buffer, count, file_data, self->priv->post_photos->max_width, self->priv->post_photos->max_height, &resized_buffer, &resized_count, self->priv->post_photos->cancellable, &error)) { body = soup_buffer_new (SOUP_MEMORY_TAKE, resized_buffer, resized_count); } else if (error == NULL) { body = soup_buffer_new (SOUP_MEMORY_TEMPORARY, *buffer, count); } else { soup_multipart_free (multipart); post_photos_done (self, error); return; } soup_multipart_append_form_file (multipart, "file", NULL, gth_file_data_get_mime_type (file_data), body); soup_buffer_free (body); /* send the file */ self->priv->post_photos->wrote_body_data_size = 0; url = g_strconcat ("https://picasaweb.google.com/data/feed/api/user/", account->id, "/albumid/", self->priv->post_photos->album->id, NULL); msg = soup_form_request_new_from_multipart (url, multipart); g_signal_connect (msg, "wrote-body-data", (GCallback) upload_photo_wrote_body_data_cb, self); _picasa_web_service_add_headers (self, msg); _web_service_send_message (WEB_SERVICE (self), msg, self->priv->post_photos->cancellable, self->priv->post_photos->callback, self->priv->post_photos->user_data, picasa_web_service_post_photos, post_photo_ready_cb, self); g_free (url); soup_multipart_free (multipart); }
SoupMessageHeaders * dmap_connection_get_headers (DMAPConnection * connection, const gchar * uri) { DMAPConnectionPrivate *priv = connection->priv; SoupMessageHeaders *headers = NULL; char hash[33] = { 0 }; char *norb_daap_uri = (char *) uri; char *request_id; priv->request_id++; if (g_ascii_strncasecmp (uri, "daap://", 7) == 0) { norb_daap_uri = strstr (uri, "/data"); } dmap_hash_generate ((short) floorf (priv->dmap_version), (const guchar *) norb_daap_uri, 2, (guchar *) hash, priv->request_id); headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); soup_message_headers_append (headers, "Accept", "*/*"); soup_message_headers_append (headers, "Cache-Control", "no-cache"); soup_message_headers_append (headers, "Accept-Language", "en-us, en;q=5.0"); soup_message_headers_append (headers, "Client-DAAP-Access-Index", "2"); soup_message_headers_append (headers, "Client-DAAP-Version", "3.0"); soup_message_headers_append (headers, "Client-DAAP-Validation", hash); request_id = g_strdup_printf ("%d", priv->request_id); soup_message_headers_append (headers, "Client-DAAP-Request-ID", request_id); g_free (request_id); if (priv->password_protected) { char *h; char *user_pass; char *token; if (priv->username == NULL || priv->password == NULL) { g_debug ("No username or no password provided"); } else { user_pass = g_strdup_printf ("%s:%s", priv->username, priv->password); token = g_base64_encode ((guchar *) user_pass, strlen (user_pass)); h = g_strdup_printf ("Basic %s", token); g_free (token); g_free (user_pass); soup_message_headers_append (headers, "Authentication", h); g_free (h); } } return headers; }
static gboolean send_request (const gchar *method, const gchar *path, const gchar *content, const gchar *macaroon, gchar **discharges, guint *status_code, gchar **reason_phrase, gchar **response_type, gchar **response, gsize *response_length, GCancellable *cancellable, GError **error) { g_autoptr (GSocket) socket = NULL; g_autoptr (GString) request = NULL; gssize n_written; g_autoptr (GByteArray) buffer = NULL; gsize data_length = 0, header_length; gchar *body = NULL; g_autoptr (SoupMessageHeaders) headers = NULL; gsize chunk_length = 0, n_required; guint8 *chunk_start = NULL; guint code; // NOTE: Would love to use libsoup but it doesn't support unix sockets // https://bugzilla.gnome.org/show_bug.cgi?id=727563 socket = open_snapd_socket (cancellable, error); if (socket == NULL) return FALSE; request = g_string_new (""); g_string_append_printf (request, "%s %s HTTP/1.1\r\n", method, path); g_string_append (request, "Host:\r\n"); if (macaroon != NULL) { gint i; g_string_append_printf (request, "Authorization: Macaroon root=\"%s\"", macaroon); for (i = 0; discharges[i] != NULL; i++) g_string_append_printf (request, ",discharge=\"%s\"", discharges[i]); g_string_append (request, "\r\n"); } if (content) g_string_append_printf (request, "Content-Length: %zu\r\n", strlen (content)); g_string_append (request, "\r\n"); if (content) g_string_append (request, content); g_debug ("begin snapd request: %s", request->str); /* send HTTP request */ n_written = g_socket_send (socket, request->str, request->len, cancellable, error); if (n_written < 0) return FALSE; /* read HTTP headers */ buffer = g_byte_array_new (); while (body == NULL) { if (!read_from_snapd (socket, buffer, &data_length, 1024, cancellable, error)) return FALSE; body = strstr (buffer->data, "\r\n\r\n"); } if (body == NULL) { g_set_error_literal (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "Unable to find header separator in snapd response"); return FALSE; } /* body starts after header divider */ body += 4; header_length = (gsize) ((guint8 *) body - buffer->data); /* parse headers */ headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE); if (!soup_headers_parse_response (buffer->data, (gint) header_length, headers, NULL, &code, reason_phrase)) { g_set_error_literal (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "snapd response HTTP headers not parseable"); return FALSE; } if (status_code != NULL) *status_code = code; /* read content */ switch (soup_message_headers_get_encoding (headers)) { case SOUP_ENCODING_EOF: while (TRUE) { gsize n_read = data_length; if (!read_from_snapd (socket, buffer, &data_length, 1024, cancellable, error)) return FALSE; if (n_read == data_length) break; chunk_length += data_length - n_read; } break; case SOUP_ENCODING_CHUNKED: // FIXME: support multiple chunks while (TRUE) { chunk_start = strstr (body, "\r\n"); if (chunk_start) break; if (!read_from_snapd (socket, buffer, &data_length, 1024, cancellable, error)) return FALSE; } if (!chunk_start) { g_set_error_literal (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "Unable to find chunk header in " "snapd response"); return FALSE; } chunk_length = strtoul (body, NULL, 16); chunk_start += 2; /* check if enough space to read chunk */ n_required = (chunk_start - buffer->data) + chunk_length; while (data_length < n_required) if (!read_from_snapd (socket, buffer, &data_length, n_required - data_length, cancellable, error)) return FALSE; break; case SOUP_ENCODING_CONTENT_LENGTH: chunk_length = soup_message_headers_get_content_length (headers); chunk_start = body; n_required = header_length + chunk_length; while (data_length < n_required) { if (!read_from_snapd (socket, buffer, &data_length, n_required - data_length, cancellable, error)) return FALSE; } break; default: g_set_error_literal (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "Unable to determine content " "length of snapd response"); return FALSE; } if (response_type) *response_type = g_strdup (soup_message_headers_get_content_type (headers, NULL)); if (response != NULL && chunk_start != NULL) { *response = g_malloc (chunk_length + 2); memcpy (*response, chunk_start, chunk_length + 1); (*response)[chunk_length + 1] = '\0'; g_debug ("snapd status %u: %s", code, *response); } if (response_length) *response_length = chunk_length; return TRUE; }