Esempio n. 1
0
//
// 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
	);
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
/**
 * 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, &params))
			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;
}
Esempio n. 4
0
/**
 * 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")));
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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, &params);

    if (content_type &&
            g_str_has_prefix (content_type, "multipart/") &&
            g_hash_table_lookup (params, "boundary")) {
        message_is_multipart = TRUE;
    }
    g_clear_pointer (&params, 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);
}
Esempio n. 13
0
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, &params))
    {
      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);
    }
}
Esempio n. 14
0
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;
}
Esempio n. 16
0
//
// 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);
	}
}
Esempio n. 17
0
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,
              &params)) != 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;
  }
}
Esempio n. 18
0
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);
}