// // Callback that's invoked each time that an user image has been downloaded. // // This function sets the buddy's icon based on the downloaded image, that is // assuming that the picture was successfully downloaded. // // This function always invokes a next iteration within the current worker. // static void budicons_got_image_response (SoupSession *session, SoupMessage *message, gpointer data) { PurpleBuddy *buddy = (PurpleBuddy *) data; char *url = soup_uri_to_string(soup_message_get_uri(message), FALSE); g_print("Soup: [%-3d] %s\n", message->status_code, url); g_free(url); if (! SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) { return; } const char *mime = soup_message_headers_get_content_type(message->response_headers, NULL); if (g_ascii_strncasecmp(mime, "image/", strlen("image/"))) { // Wrong mime-type, this isn't an image g_print("Soup: content-type '%s' doesn't correspond to an image\n", mime); return; } // Set the icon of the buddy const char *content = message->response_body->data; gsize length = (gsize) message->response_body->length; char *icon = g_memdup(content, length); purple_buddy_icons_set_for_user( buddy->account, buddy->name, icon, length, NULL ); }
static const char * soup_request_http_get_content_type (SoupRequest *request) { SoupRequestHTTP *http = SOUP_REQUEST_HTTP (request); return soup_message_headers_get_content_type (http->priv->msg->response_headers, NULL); }
/** * soup_form_decode_multipart: * @msg: a #SoupMessage containing a "multipart/form-data" request body * @file_control_name: the name of the HTML file upload control, or %NULL * @filename: (out): return location for the name of the uploaded file * @content_type: (out): return location for the MIME type of the uploaded file * @file: (out): return location for the uploaded file data * * Decodes the "multipart/form-data" request in @msg; this is a * convenience method for the case when you have a single file upload * control in a form. (Or when you don't have any file upload * controls, but are still using "multipart/form-data" anyway.) Pass * the name of the file upload control in @file_control_name, and * soup_form_decode_multipart() will extract the uploaded file data * into @filename, @content_type, and @file. All of the other form * control data will be returned (as strings, as with * soup_form_decode()) in the returned #GHashTable. * * You may pass %NULL for @filename and/or @content_type if you do not * care about those fields. soup_form_decode_multipart() may also * return %NULL in those fields if the client did not provide that * information. You must free the returned filename and content-type * with g_free(), and the returned file data with soup_buffer_free(). * * If you have a form with more than one file upload control, you will * need to decode it manually, using soup_multipart_new_from_message() * and soup_multipart_get_part(). * * Return value: (element-type utf8 utf8) (transfer full): a hash * table containing the name/value pairs (other than * @file_control_name) from @msg, which you can free with * g_hash_table_destroy(). On error, it will return %NULL. * * Since: 2.26 **/ GHashTable * soup_form_decode_multipart (SoupMessage *msg, const char *file_control_name, char **filename, char **content_type, SoupBuffer **file) { SoupMultipart *multipart; GHashTable *form_data_set, *params; SoupMessageHeaders *part_headers; SoupBuffer *part_body; char *disposition, *name; int i; multipart = soup_multipart_new_from_message (msg->request_headers, msg->request_body); if (!multipart) return NULL; if (filename) *filename = NULL; if (content_type) *content_type = NULL; *file = NULL; form_data_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); for (i = 0; i < soup_multipart_get_length (multipart); i++) { soup_multipart_get_part (multipart, i, &part_headers, &part_body); if (!soup_message_headers_get_content_disposition ( part_headers, &disposition, ¶ms)) continue; name = g_hash_table_lookup (params, "name"); if (g_ascii_strcasecmp (disposition, "form-data") != 0 || !name) { g_free (disposition); g_hash_table_destroy (params); continue; } if (!strcmp (name, file_control_name)) { if (filename) *filename = g_strdup (g_hash_table_lookup (params, "filename")); if (content_type) *content_type = g_strdup (soup_message_headers_get_content_type (part_headers, NULL)); if (file) *file = soup_buffer_copy (part_body); } else { g_hash_table_insert (form_data_set, g_strdup (name), g_strndup (part_body->data, part_body->length)); } g_free (disposition); g_hash_table_destroy (params); } soup_multipart_free (multipart); return form_data_set; }
/** * ephy_download_get_content_type: * @download: an #EphyDownload * * Gets content-type information for @download. If the file is already * present on the filesystem and readable, uses GIO to get the * content-type. Otherwise it uses WebKit and Soup. * * Returns: content-type for @download, must be freed with g_free() **/ char * ephy_download_get_content_type (EphyDownload *download) { #ifdef HAVE_WEBKIT2 WebKitURIResponse *response; #else WebKitNetworkResponse *response; SoupMessage *message; #endif char *content_type = NULL; GError *error = NULL; if (download->priv->destination) { GFile *destination; GFileInfo *info; destination = g_file_new_for_uri (download->priv->destination); info = g_file_query_info (destination, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); if (info) { content_type = g_strdup (g_file_info_get_content_type (info)); LOG ("ephy_download_get_content_type: GIO: %s", content_type); g_object_unref (info); } else { LOG ("ephy_download_get_content_type: error getting file " "content-type: %s", error->message); g_error_free (error); } g_object_unref (destination); } if (content_type) return content_type; /* Fallback to Soup */ #ifdef HAVE_WEBKIT2 response = webkit_download_get_response (download->priv->download); if (response) content_type = g_strdup (webkit_uri_response_get_mime_type (response)); #else response = webkit_download_get_network_response (download->priv->download); message = webkit_network_response_get_message (response); if (message != NULL) content_type = g_strdup (soup_message_headers_get_content_type (message->response_headers, NULL)); #endif LOG ("ephy_download_get_content_type: Soup: %s", content_type); LOG ("ephy_download_get_content_type: %s", content_type); return content_type; }
static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) { SoupMessageHeadersIter iter; const char* name = 0; const char* value = 0; soup_message_headers_iter_init(&iter, msg->response_headers); while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); GHashTable* contentTypeParameters = 0; String contentType = soup_message_headers_get_content_type(msg->response_headers, &contentTypeParameters); // When the server sends multiple Content-Type headers, soup will // give us their values concatenated with commas as a separator; // we need to handle this and use only one value. We use the first // value, and add all the parameters, afterwards, if any. Vector<String> contentTypes; contentType.split(',', true, contentTypes); contentType = contentTypes[0]; if (contentTypeParameters) { GString* parametersString = g_string_new(0); GHashTableIter hashTableIter; const char* hashKey; const char* hashValue; g_hash_table_iter_init(&hashTableIter, contentTypeParameters); while (g_hash_table_iter_next(&hashTableIter, reinterpret_cast<void**>(const_cast<char**>(&hashKey)), reinterpret_cast<void**>(const_cast<char**>(&hashValue)))) { // Work-around bug in soup which causes a crash; // See http://bugzilla.gnome.org/show_bug.cgi?id=577728 if (!hashValue) hashValue = ""; g_string_append(parametersString, "; "); soup_header_g_string_append_param(parametersString, hashKey, hashValue); } contentType += String(parametersString->str); g_string_free(parametersString, true); g_hash_table_destroy(contentTypeParameters); } response->setMimeType(extractMIMETypeFromMediaType(contentType)); char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); response->setURL(KURL(KURL(), uri)); g_free(uri); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers)); response->setHTTPStatusCode(msg->status_code); response->setHTTPStatusText(msg->reason_phrase); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); }
static GDataFeed * gdata_access_handler_real_get_rules (GDataAccessHandler *self, GDataService *service, GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error) { GDataAccessHandlerIface *iface; GDataAuthorizationDomain *domain = NULL; GDataFeed *feed; GDataLink *_link; SoupMessage *message; SoupMessageHeaders *headers; const gchar *content_type; _link = gdata_entry_look_up_link (GDATA_ENTRY (self), GDATA_LINK_ACCESS_CONTROL_LIST); g_assert (_link != NULL); iface = GDATA_ACCESS_HANDLER_GET_IFACE (self); if (iface->get_authorization_domain != NULL) { domain = iface->get_authorization_domain (self); } message = _gdata_service_query (service, domain, gdata_link_get_uri (_link), NULL, cancellable, error); if (message == NULL) { return NULL; } g_assert (message->response_body->data != NULL); headers = message->response_headers; content_type = soup_message_headers_get_content_type (headers, NULL); if (g_strcmp0 (content_type, "application/json") == 0) { /* Definitely JSON. */ g_debug("JSON content type detected."); feed = _gdata_feed_new_from_json (GDATA_TYPE_FEED, message->response_body->data, message->response_body->length, GDATA_TYPE_ACCESS_RULE, progress_callback, progress_user_data, error); } else { /* Potentially XML. Don't bother checking the Content-Type, since the parser * will fail gracefully if the response body is not valid XML. */ g_debug("XML content type detected."); feed = _gdata_feed_new_from_xml (GDATA_TYPE_FEED, message->response_body->data, message->response_body->length, GDATA_TYPE_ACCESS_RULE, progress_callback, progress_user_data, error); } g_object_unref (message); return feed; }
static char* sniff (SoupContentSniffer *sniffer, SoupMessage *msg, SoupBuffer *buffer, GHashTable **params) { const char *content_type_with_params; const char *content_type; content_type = soup_message_headers_get_content_type (msg->response_headers, params); content_type_with_params = soup_message_headers_get_one (msg->response_headers, "Content-Type"); /* These comparisons are done in an ASCII-case-insensitive * manner because the spec requires it */ if ((content_type == NULL) || !g_ascii_strcasecmp (content_type, "unknown/unknown") || !g_ascii_strcasecmp (content_type, "application/unknown") || !g_ascii_strcasecmp (content_type, "*/*")) return sniff_unknown (sniffer, msg, buffer, FALSE); if (g_str_has_suffix (content_type, "+xml") || !g_ascii_strcasecmp (content_type, "text/xml") || !g_ascii_strcasecmp (content_type, "application/xml")) return g_strdup (content_type); /* 2.7.5 Content-Type sniffing: image * The spec says: * * If the resource's official type is "image/svg+xml", then * the sniffed type of the resource is its official type (an * XML type) * * The XML case is handled by the if above; if you refactor * this code, keep this in mind. */ if (!g_ascii_strncasecmp (content_type, "image/", 6)) return sniff_images (sniffer, msg, buffer, content_type); /* If we got text/plain, use text_or_binary */ if (g_str_equal (content_type_with_params, "text/plain") || g_str_equal (content_type_with_params, "text/plain; charset=ISO-8859-1") || g_str_equal (content_type_with_params, "text/plain; charset=iso-8859-1") || g_str_equal (content_type_with_params, "text/plain; charset=UTF-8")) { return sniff_text_or_binary (sniffer, msg, buffer); } if (!g_ascii_strcasecmp (content_type, "text/html")) return sniff_feed_or_html (sniffer, msg, buffer); return g_strdup (content_type); }
static void md5_post_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { const char *content_type; GHashTable *params; const char *fmt; char *filename, *md5sum, *redirect_uri; SoupBuffer *file; SoupURI *uri; content_type = soup_message_headers_get_content_type (msg->request_headers, NULL); if (!content_type || strcmp (content_type, "multipart/form-data") != 0) { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); return; } params = soup_form_decode_multipart (msg, "file", &filename, NULL, &file); if (!params) { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); return; } fmt = g_hash_table_lookup (params, "fmt"); md5sum = g_compute_checksum_for_data (G_CHECKSUM_MD5, (gpointer)file->data, file->length); soup_buffer_free (file); uri = soup_uri_copy (soup_message_get_uri (msg)); soup_uri_set_query_from_fields (uri, "file", filename ? filename : "", "md5sum", md5sum, "fmt", fmt ? fmt : "html", NULL); redirect_uri = soup_uri_to_string (uri, FALSE); soup_message_set_status (msg, SOUP_STATUS_SEE_OTHER); soup_message_headers_replace (msg->response_headers, "Location", redirect_uri); g_free (redirect_uri); soup_uri_free (uri); g_free (md5sum); g_free (filename); g_hash_table_destroy (params); }
static void conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_data) { ConditionalHelper *helper = (ConditionalHelper *)user_data; GSimpleAsyncResult *simple; SoupHTTPInputStream *httpstream; simple = g_simple_async_result_new (G_OBJECT (helper->req), helper->callback, helper->user_data, conditional_get_ready_cb); if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) { SoupCache *cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE); httpstream = (SoupHTTPInputStream *)soup_cache_send_response (cache, msg); if (httpstream) { g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref); soup_message_got_headers (helper->original); if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, helper->original)) { const char *content_type = soup_message_headers_get_content_type (msg->response_headers, NULL); soup_message_content_sniffed (helper->original, content_type, NULL); } g_simple_async_result_complete (simple); soup_message_finished (helper->original); g_object_unref (simple); } else { /* Ask again for the resource, somehow the cache cannot locate it */ httpstream = soup_http_input_stream_new (session, helper->original); soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT, helper->cancellable, sent_async, simple); } } else { /* It is in the cache but it was modified remotely */ httpstream = soup_http_input_stream_new (session, helper->original); soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT, helper->cancellable, sent_async, simple); } g_object_unref (helper->req); g_object_unref (helper->original); g_slice_free (ConditionalHelper, helper); }
static void network_process_callback (SoupSession *session, SoupMessage *msg, gpointer user_data) { updateJobPtr job = (updateJobPtr)user_data; SoupDate *last_modified; const gchar *tmp = NULL; job->result->source = soup_uri_to_string (soup_message_get_uri(msg), FALSE); if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) { job->result->returncode = msg->status_code; job->result->httpstatus = 0; } else { job->result->httpstatus = msg->status_code; job->result->returncode = 0; } debug1 (DEBUG_NET, "download status code: %d", msg->status_code); debug1 (DEBUG_NET, "source after download: >>>%s<<<", job->result->source); job->result->data = g_memdup (msg->response_body->data, msg->response_body->length+1); job->result->size = (size_t)msg->response_body->length; debug1 (DEBUG_NET, "%d bytes downloaded", job->result->size); job->result->contentType = g_strdup (soup_message_headers_get_content_type (msg->response_headers, NULL)); /* Update last-modified date */ tmp = soup_message_headers_get_one (msg->response_headers, "Last-Modified"); if (tmp) { /* The string may be badly formatted, which will make * soup_date_new_from_string() return NULL */ last_modified = soup_date_new_from_string (tmp); if (last_modified) { job->result->updateState->lastModified = soup_date_to_time_t (last_modified); soup_date_free (last_modified); } } /* Update ETag value */ tmp = soup_message_headers_get_one (msg->response_headers, "ETag"); if (tmp) { job->result->updateState->etag = g_strdup(tmp); } update_process_finished_job (job); }
static gboolean send_async_cb (gpointer data) { GSimpleAsyncResult *simple; SoupSession *session; SendAsyncHelper *helper = (SendAsyncHelper *)data; session = soup_request_get_session (SOUP_REQUEST (helper->http)); simple = g_simple_async_result_new (G_OBJECT (helper->http), helper->callback, helper->user_data, soup_request_http_send_async); g_simple_async_result_set_op_res_gpointer (simple, helper->httpstream, g_object_unref); /* Update message status */ soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK); /* Issue signals */ soup_message_got_headers (helper->http->priv->msg); if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, helper->http->priv->msg)) { const char *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); } g_simple_async_result_complete (simple); soup_message_finished (helper->http->priv->msg); g_object_unref (simple); g_object_unref (helper->http); g_slice_free (SendAsyncHelper, helper); return FALSE; }
static void test_multipart (int headers_expected, int sniffed_expected, MultipartMode multipart_mode) { GError* error = NULL; SoupRequest* request = soup_session_request (session, base_uri_string, &error); SoupMessage *msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request)); GMainLoop *loop = g_main_loop_new (NULL, TRUE); int headers_count = 0; int sniffed_count = 0; GHashTable *params; const char *content_type; gboolean message_is_multipart = FALSE; debug_printf (1, "test_multipart(%s)\n", multipart_mode_to_string (multipart_mode)); /* This is used to track the number of parts. */ passes = 0; /* Force the server to close the connection. */ soup_message_headers_append (msg->request_headers, "Connection", "close"); g_signal_connect (msg, "got_headers", G_CALLBACK (got_headers), &headers_count); g_signal_connect (msg, "content-sniffed", G_CALLBACK (content_sniffed), &sniffed_count); if (multipart_mode == ASYNC_MULTIPART) soup_request_send_async (request, NULL, multipart_handling_cb, loop); else if (multipart_mode == ASYNC_MULTIPART_SMALL_READS) { g_object_set_data (G_OBJECT (request), "multipart-small-reads", GINT_TO_POINTER(1)); soup_request_send_async (request, NULL, multipart_handling_cb, loop); } else if (multipart_mode == SYNC_MULTIPART) soup_request_send_async (request, NULL, sync_multipart_handling_cb, loop); else soup_request_send_async (request, NULL, no_multipart_handling_cb, loop); g_main_loop_run (loop); content_type = soup_message_headers_get_content_type (msg->response_headers, ¶ms); if (content_type && g_str_has_prefix (content_type, "multipart/") && g_hash_table_lookup (params, "boundary")) { message_is_multipart = TRUE; } g_clear_pointer (¶ms, g_hash_table_unref); if (!message_is_multipart) { debug_printf (1, " Header does not indicate a multipart message!\n"); errors++; } if (headers_count != headers_expected) { debug_printf (1, " expected got_header %d times, got %d!\n", headers_expected, headers_count); errors++; } if (sniffed_count != sniffed_expected) { debug_printf (1, " expected content_sniffed %d times, got %d!\n", sniffed_expected, sniffed_count); errors++; } g_object_unref (msg); g_object_unref (request); g_main_loop_unref (loop); }
static void file_info_from_message (SoupMessage *msg, GFileInfo *info, GFileAttributeMatcher *matcher) { const char *text; GHashTable *params; char *basename; char *ed_name; basename = ed_name = NULL; /* prefer the filename from the Content-Disposition (rfc2183) header if one if present. See bug 551298. */ if (soup_message_headers_get_content_disposition (msg->response_headers, NULL, ¶ms)) { const char *name = g_hash_table_lookup (params, "filename"); if (name) basename = g_strdup (name); g_hash_table_destroy (params); } if (basename == NULL) { const SoupURI *uri; uri = soup_message_get_uri (msg); basename = http_uri_get_basename (uri->path); } g_debug ("basename:%s\n", basename); /* read http/1.1 rfc, until then we copy the local files * behaviour */ if (basename != NULL && (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME) || g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME))) ed_name = gvfs_file_info_populate_names_as_local (info, basename); g_free (basename); g_free (ed_name); if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH) { goffset start, end, length; gboolean ret; ret = soup_message_headers_get_content_range (msg->response_headers, &start, &end, &length); if (ret && length != -1) { g_file_info_set_size (info, length); } else if (!ret) { length = soup_message_headers_get_content_length (msg->response_headers); g_file_info_set_size (info, length); } } g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR); text = soup_message_headers_get_content_type (msg->response_headers, NULL); if (text) { GIcon *icon; g_file_info_set_content_type (info, text); g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, text); icon = g_content_type_get_icon (text); g_file_info_set_icon (info, icon); g_object_unref (icon); icon = g_content_type_get_symbolic_icon (text); g_file_info_set_symbolic_icon (info, icon); g_object_unref (icon); } text = soup_message_headers_get_one (msg->response_headers, "Last-Modified"); if (text) { SoupDate *sd; GTimeVal tv; sd = soup_date_new_from_string(text); if (sd) { soup_date_to_timeval (sd, &tv); g_file_info_set_modification_time (info, &tv); soup_date_free (sd); } } text = soup_message_headers_get_one (msg->response_headers, "ETag"); if (text) { g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, text); } }
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; }
static gboolean send_review_request (GsPlugin *plugin, const gchar *method, const gchar *path, JsonBuilder *request, gboolean do_sign, guint *status_code, JsonParser **result, GCancellable *cancellable, GError **error) { g_autofree gchar *uri = NULL; g_autoptr(SoupMessage) msg = NULL; uri = g_strdup_printf ("%s%s", UBUNTU_REVIEWS_SERVER, path); msg = soup_message_new (method, uri); if (request != NULL) { g_autoptr(JsonGenerator) generator = NULL; gchar *data; gsize length; generator = json_generator_new (); json_generator_set_root (generator, json_builder_get_root (request)); data = json_generator_to_data (generator, &length); soup_message_set_request (msg, "application/json", SOUP_MEMORY_TAKE, data, length); } if (do_sign) sign_message (msg, OA_PLAINTEXT, gs_plugin_get_auth_by_id (plugin, "ubuntuone")); *status_code = soup_session_send_message (gs_plugin_get_soup_session (plugin), msg); if (*status_code == SOUP_STATUS_UNAUTHORIZED) { g_set_error_literal (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_REQUIRED, "Requires authentication with @ubuntuone"); return FALSE; } if (result != NULL) { g_autoptr(JsonParser) parser = NULL; const gchar *content_type; content_type = soup_message_headers_get_content_type (msg->response_headers, NULL); if (g_strcmp0 (content_type, "application/json") != 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Got unknown content type %s from reviews.ubuntu.com", content_type); return FALSE; } parser = json_parser_new (); if (!json_parser_load_from_data (parser, msg->response_body->data, -1, error)) { return FALSE; } *result = g_steal_pointer (&parser); } return TRUE; }
// // Callback that's invoked once the main JSON file is downloaded. // // If the SoupMessage returns a successful response then this callback will // trigger the processing of the users asynchronously. It will also register a // a callback that will process all new buddies that are added while Pidgin is // running. // static void budicons_got_json_response (SoupSession *session, SoupMessage *message, gpointer data) { BudiconsPlugin *plugin = (BudiconsPlugin *) data; { char *url = soup_uri_to_string(soup_message_get_uri(message), FALSE); g_print("Downloaded URL %s: %d\n", url, message->status_code); g_free(url); } if (! SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) { g_print("SOUP Message was not successful (%d)\n", message->status_code); return; } const char *buffer = message->response_body->data; gsize length = (gsize) message->response_body->length; const char *mime = soup_message_headers_get_content_type(message->response_headers, NULL); if (! (EQ(mime, "application/json") || EQ(mime, "text/plain"))) { g_print("Got the wrong mime type (%s) for the JSON file\n", mime); return; } // Parse the JSON file GError *error = NULL; plugin->users = budicons_json_parse_users(buffer, length, &error); if (plugin->users == NULL) { char *url = soup_uri_to_string(soup_message_get_uri(message), FALSE); g_print("Failed to parse URL %s: %s\n", url, error->message); g_free(url); g_error_free(error); return; } // Register a callback for every new buddy added purple_signal_connect( purple_blist_get_handle(), "buddy-added", plugin->purple, PURPLE_CALLBACK(budicons_buddy_added_callback), plugin ); // Collect the buddies to process PurpleBuddyList *list = purple_get_blist(); if (list == NULL) {return;} plugin->buddies = NULL; for (PurpleBlistNode *group = list->root; group; group = group->next) { if (! PURPLE_BLIST_NODE_IS_GROUP(group)) {continue;} for (PurpleBlistNode *contact = group->child; contact; contact = contact->next) { if (! PURPLE_BLIST_NODE_IS_CONTACT(contact)) {continue;} for (PurpleBlistNode *blist = contact->child; blist; blist = blist->next) { if (! PURPLE_BLIST_NODE_IS_BUDDY(blist)) {continue;} PurpleBuddy *buddy = (PurpleBuddy *) blist; plugin->buddies = g_slist_prepend(plugin->buddies, buddy); } } } // Start a few workers that will process the buddies registered so far plugin->buddy_iter = plugin->buddies; guint workers = budicons_prefs_get_workers(); for (guint i = 0; i < workers; ++i) { // No more buddies to process if (plugin->buddy_iter == NULL) {break;} // Create a new worker BudiconsWorker *worker = g_new0(BudiconsWorker, 1); worker->plugin = plugin; worker->id = i; g_print("[%d] Started a new worker\n", worker->id); budicons_worker_iter(worker); } }
static void gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src) { const char *value; GstTagList *tag_list; GstBaseSrc *basesrc; guint64 newsize; GHashTable *params = NULL; GST_DEBUG_OBJECT (src, "got headers:"); soup_message_headers_foreach (msg->response_headers, gst_soup_http_src_headers_foreach, src); if (msg->status_code == 407 && src->proxy_id && src->proxy_pw) return; if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) { GST_DEBUG_OBJECT (src, "%u redirect to \"%s\"", msg->status_code, soup_message_headers_get_one (msg->response_headers, "Location")); return; } if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) return; src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING; /* Parse Content-Length. */ if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH) { newsize = src->request_position + soup_message_headers_get_content_length (msg->response_headers); if (!src->have_size || (src->content_size != newsize)) { src->content_size = newsize; src->have_size = TRUE; src->seekable = TRUE; GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->content_size); basesrc = GST_BASE_SRC_CAST (src); gst_segment_set_duration (&basesrc->segment, GST_FORMAT_BYTES, src->content_size); gst_element_post_message (GST_ELEMENT (src), gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_BYTES, src->content_size)); } } /* Icecast stuff */ tag_list = gst_tag_list_new (); if ((value = soup_message_headers_get_one (msg->response_headers, "icy-metaint")) != NULL) { gint icy_metaint = atoi (value); GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value, icy_metaint); if (icy_metaint > 0) { if (src->src_caps) gst_caps_unref (src->src_caps); src->src_caps = gst_caps_new_simple ("application/x-icy", "metadata-interval", G_TYPE_INT, icy_metaint, NULL); } } if ((value = soup_message_headers_get_content_type (msg->response_headers, ¶ms)) != NULL) { GST_DEBUG_OBJECT (src, "Content-Type: %s", value); if (g_ascii_strcasecmp (value, "audio/L16") == 0) { gint channels = 2; gint rate = 44100; char *param; if (src->src_caps) gst_caps_unref (src->src_caps); param = g_hash_table_lookup (params, "channels"); if (param != NULL) channels = atol (param); param = g_hash_table_lookup (params, "rate"); if (param != NULL) rate = atol (param); src->src_caps = gst_caps_new_simple ("audio/x-raw-int", "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL); } else { /* Set the Content-Type field on the caps */ if (src->src_caps) gst_caps_set_simple (src->src_caps, "content-type", G_TYPE_STRING, value, NULL); } } if (params != NULL) g_hash_table_destroy (params); if ((value = soup_message_headers_get_one (msg->response_headers, "icy-name")) != NULL) { g_free (src->iradio_name); src->iradio_name = gst_soup_http_src_unicodify (value); if (src->iradio_name) { g_object_notify (G_OBJECT (src), "iradio-name"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, src->iradio_name, NULL); } } if ((value = soup_message_headers_get_one (msg->response_headers, "icy-genre")) != NULL) { g_free (src->iradio_genre); src->iradio_genre = gst_soup_http_src_unicodify (value); if (src->iradio_genre) { g_object_notify (G_OBJECT (src), "iradio-genre"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, src->iradio_genre, NULL); } } if ((value = soup_message_headers_get_one (msg->response_headers, "icy-url")) != NULL) { g_free (src->iradio_url); src->iradio_url = gst_soup_http_src_unicodify (value); if (src->iradio_url) { g_object_notify (G_OBJECT (src), "iradio-url"); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, src->iradio_url, NULL); } } if (!gst_tag_list_is_empty (tag_list)) { GST_DEBUG_OBJECT (src, "calling gst_element_found_tags with %" GST_PTR_FORMAT, tag_list); gst_element_found_tags (GST_ELEMENT_CAST (src), tag_list); } else { gst_tag_list_free (tag_list); } /* Handle HTTP errors. */ gst_soup_http_src_parse_status (msg, src); /* Check if Range header was respected. */ if (src->ret == GST_FLOW_CUSTOM_ERROR && src->read_position && msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) { src->seekable = FALSE; GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (_("Server does not support seeking.")), ("Server does not accept Range HTTP header, URL: %s", src->location)); src->ret = GST_FLOW_ERROR; } }
static void control_callback (G_GNUC_UNUSED SoupServer * soup, SoupMessage * msg, const char *path, GHashTable * query, G_GNUC_UNUSED SoupClientContext * client, SnraManager * manager) { gchar **parts = g_strsplit (path, "/", 3); guint n_parts = g_strv_length (parts); SnraControlEvent event_type; GHashTable *post_params = NULL; const gchar *content_type; if (n_parts < 3 || !g_str_equal ("control", parts[1])) goto done; /* Invalid request */ event_type = str_to_control_event_type (parts[2]); content_type = soup_message_headers_get_content_type (msg->request_headers, NULL); if (g_str_equal (msg->method, "POST") && content_type && g_str_equal (content_type, SOUP_FORM_MIME_TYPE_URLENCODED)) post_params = soup_form_decode (msg->request_body->data); switch (event_type) { case SNRA_CONTROL_NEXT:{ gchar *id_str = find_param_str ("id", query, post_params); guint resource_id; if (id_str == NULL || !sscanf (id_str, "%d", &resource_id)) { /* No or invalid resource id: skip to another random track */ resource_id = (guint) g_random_int_range (0, get_playlist_len (manager)) + 1; } else { resource_id = CLAMP (resource_id, 1, get_playlist_len (manager)); } if (resource_id != 0) { manager->paused = FALSE; snra_manager_play_resource (manager, resource_id); } break; } case SNRA_CONTROL_PAUSE:{ if (!manager->paused) snra_manager_send_pause (manager, NULL); manager->paused = TRUE; break; } case SNRA_CONTROL_PLAY:{ if (manager->paused) { if (manager->current_resource == 0) { guint resource_id = g_random_int_range (0, get_playlist_len (manager) + 1); if (resource_id != 0) { manager->paused = FALSE; snra_manager_play_resource (manager, resource_id); } } else { manager->paused = FALSE; snra_manager_send_play (manager, NULL); } } break; } case SNRA_CONTROL_VOLUME:{ gchar *vol_str = find_param_str ("level", query, post_params); gchar *id_str = find_param_str ("client_id", query, post_params); guint client_id = 0; gdouble new_vol; if (id_str != NULL) sscanf (id_str, "%u", &client_id); if (vol_str && sscanf (vol_str, "%lf", &new_vol)) { new_vol = CLAMP (new_vol, 0.0, 10.0); if (client_id == 0) snra_manager_adjust_volume (manager, new_vol); else snra_manager_adjust_client_volume (manager, client_id, new_vol); } break; } case SNRA_CONTROL_CLIENT_SETTING:{ gchar *set_str = find_param_str ("enable", query, post_params); gchar *id_str = find_param_str ("client_id", query, post_params); guint client_id = 0; gint enable = 1; if (id_str != NULL) sscanf (id_str, "%u", &client_id); if (set_str && sscanf (set_str, "%d", &enable)) { if (client_id > 0) snra_manager_adjust_client_setting (manager, client_id, enable != 0); } break; } default: g_message ("Ignoring unknown/unimplemented control %s\n", parts[2]); soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); goto done; } soup_message_set_response (msg, "text/plain", SOUP_MEMORY_STATIC, " ", 1); soup_message_set_status (msg, SOUP_STATUS_OK); done: if (post_params) g_hash_table_destroy (post_params); g_strfreev (parts); }