示例#1
0
void
restraint_append_message (SoupSession *session,
                          SoupMessage *msg,
                          gpointer msg_data,
                          MessageFinishCallback finish_callback,
                          GCancellable *cancellable,
                          gpointer user_data)
{
    ClientData *client_data = (ClientData *) msg_data;
    time_t result;
    result = time(NULL);
    static time_t transaction_id = 0;
    // calculate the transaction id. base it off of epoch
    // incase the host reboots we shouldn't collide
    if (transaction_id == 0) {
        transaction_id = result;
    }
    MessageData *message_data;
    message_data = g_slice_new0 (MessageData);
    message_data->msg = msg;
    message_data->user_data = user_data;
    message_data->finish_callback = finish_callback;

    if (client_data != NULL) {
        GString *body = g_string_new("");
        SoupURI *uri = soup_message_get_uri (msg);
        soup_message_headers_foreach (msg->request_headers, append_header,
                                      body);
        // if we are doing a POST transaction
        // increment transaction_id and add it to headers
        // populate Location header in msg->reponse_headers
        const gchar *path = soup_uri_get_path (uri);
        if (g_strcmp0 (msg->method, "POST") == 0) {
            g_string_append_printf (body,
                                    "transaction-id: %jd\n", (intmax_t) transaction_id);
            gchar *location_url = g_strdup_printf ("%s%jd", path, (intmax_t) transaction_id);
            soup_message_headers_append (msg->response_headers, "Location", location_url);
            g_free (location_url);
            transaction_id++;
        }
        soup_message_set_status (msg, SOUP_STATUS_OK);
        g_string_append_printf (body,
                                "rstrnt-path: %s\n"
                                "rstrnt-method: %s\n"
                                "Content-Length: %d\r\n\r\n",
                                path,
                                msg->method,
                                (guint) msg->request_body->length);
        SoupBuffer *request = soup_message_body_flatten (msg->request_body);
        body = g_string_append_len (body, request->data,
                                          request->length);
        g_string_append_printf (body,
                           "\r\n--cut-here\n");

        soup_buffer_free (request);

        soup_message_body_append (client_data->client_msg->response_body,
                                  SOUP_MEMORY_TAKE,
                                  body->str, body->len);

        g_string_free (body, FALSE);

        soup_server_unpause_message (client_data->server, client_data->client_msg);
    }

    if (finish_callback) {
        g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
                         message_finish,
                         message_data,
                         message_destroy);
    } else {
        g_object_unref (msg);
        message_destroy (message_data);
    }
}
static void
do_get (SoupMessage * msg, const char *path)
{
  gboolean send_error_doc = FALSE;
  char *uri;

  int buflen = 4096;

  SoupStatus status = SOUP_STATUS_OK;

  uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
  GST_DEBUG ("request: \"%s\"", uri);

  if (!strcmp (path, "/301"))
    status = SOUP_STATUS_MOVED_PERMANENTLY;
  else if (!strcmp (path, "/302"))
    status = SOUP_STATUS_MOVED_TEMPORARILY;
  else if (!strcmp (path, "/307"))
    status = SOUP_STATUS_TEMPORARY_REDIRECT;
  else if (!strcmp (path, "/403"))
    status = SOUP_STATUS_FORBIDDEN;
  else if (!strcmp (path, "/404"))
    status = SOUP_STATUS_NOT_FOUND;
  else if (!strcmp (path, "/404-with-data")) {
    status = SOUP_STATUS_NOT_FOUND;
    send_error_doc = TRUE;
  }

  if (SOUP_STATUS_IS_REDIRECTION (status)) {
    char *redir_uri;

    redir_uri = g_strdup_printf ("%s-redirected", uri);
    soup_message_headers_append (msg->response_headers, "Location", redir_uri);
    g_free (redir_uri);
  }
  if (status != (SoupStatus) SOUP_STATUS_OK && !send_error_doc)
    goto leave;

  if (msg->method == SOUP_METHOD_GET) {
    char *buf;

    buf = g_malloc (buflen);
    memset (buf, 0, buflen);
    soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE,
        buf, buflen);
  } else {                      /* msg->method == SOUP_METHOD_HEAD */

    char *length;

    /* We could just use the same code for both GET and
     * HEAD. But we'll optimize and avoid the extra
     * malloc.
     */
    length = g_strdup_printf ("%lu", (gulong) buflen);
    soup_message_headers_append (msg->response_headers,
        "Content-Length", length);
    g_free (length);
  }

leave:
  soup_message_set_status (msg, status);
  g_free (uri);
}
bool ResourceHandle::startHttp(String urlString)
{
    SoupSession* session = defaultSession();
    ensureSessionIsInitialized(session);

    d->m_msg = request().toSoupMessage();
    g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), this);
    g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), this);
    g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), this);
    g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), this);

    g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(this));

    FormData* httpBody = d->m_request.httpBody();
    if (httpBody && !httpBody->isEmpty()) {
        size_t numElements = httpBody->elements().size();

        // handle the most common case (i.e. no file upload)
        if (numElements < 2) {
            Vector<char> body;
            httpBody->flatten(body);
            soup_message_set_request(d->m_msg, d->m_request.httpContentType().utf8().data(),
                                     SOUP_MEMORY_COPY, body.data(), body.size());
        } else {
            /*
             * we have more than one element to upload, and some may
             * be (big) files, which we will want to mmap instead of
             * copying into memory; TODO: support upload of non-local
             * (think sftp://) files by using GIO?
             */
            soup_message_body_set_accumulate(d->m_msg->request_body, FALSE);
            for (size_t i = 0; i < numElements; i++) {
                const FormDataElement& element = httpBody->elements()[i];

                if (element.m_type == FormDataElement::data)
                    soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());
                else {
                    /*
                     * mapping for uploaded files code inspired by technique used in
                     * libsoup's simple-httpd test
                     */
                    GError* error = 0;
                    gchar* fileName = filenameFromString(element.m_filename);
                    GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error);

                    g_free(fileName);

                    if (error) {
                        ResourceError resourceError(g_quark_to_string(SOUP_HTTP_ERROR),
                                                    d->m_msg->status_code,
                                                    urlString,
                                                    String::fromUTF8(error->message));
                        g_error_free(error);

                        d->client()->didFail(this, resourceError);

                        g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA,
                                                             0, 0, 0, 0, this);
                        g_object_unref(d->m_msg);
                        d->m_msg = 0;

                        return false;
                    }

                    SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping),
                                                                        g_mapped_file_get_length(fileMapping),
                                                                        fileMapping,
#if GLIB_CHECK_VERSION(2, 21, 3)
                                                                        reinterpret_cast<GDestroyNotify>(g_mapped_file_unref));
#else
                                                                        reinterpret_cast<GDestroyNotify>(g_mapped_file_free));
#endif
                    soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer);
                    soup_buffer_free(soupBuffer);
                }
            }
        }
    }
示例#4
0
/**
 * soup_message_body_append_take:
 * @body: a #SoupMessageBody
 * @data: (array length=length) (transfer full): data to append
 * @length: length of @data
 *
 * Appends @length bytes from @data to @body.
 *
 * This function is exactly equivalent to soup_message_body_apppend()
 * with %SOUP_MEMORY_TAKE as second argument; it exists mainly for
 * convenience and simplifying language bindings.
 *
 * Since: 2.32
 * Rename to: soup_message_body_append
 **/
void
soup_message_body_append_take (SoupMessageBody *body,
			       guchar *data, gsize length)
{
	soup_message_body_append(body, SOUP_MEMORY_TAKE, data, length);
}
static void
send_message_locked (GstSoupHttpClientSink * souphttpsink)
{
  GList *g;
  guint64 n;

  if (souphttpsink->queued_buffers == NULL || souphttpsink->message) {
    return;
  }

  /* If the URI went away, drop all these buffers */
  if (souphttpsink->location == NULL) {
    GST_DEBUG_OBJECT (souphttpsink, "URI went away, dropping queued buffers");
    g_list_free_full (souphttpsink->queued_buffers,
        (GDestroyNotify) gst_buffer_unref);
    souphttpsink->queued_buffers = NULL;
    return;
  }

  souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
  if (souphttpsink->message == NULL) {
    GST_WARNING_OBJECT (souphttpsink,
        "URI could not be parsed while creating message.");
    g_list_free_full (souphttpsink->queued_buffers,
        (GDestroyNotify) gst_buffer_unref);
    souphttpsink->queued_buffers = NULL;
    return;
  }

  soup_message_set_flags (souphttpsink->message,
      (souphttpsink->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));

  if (souphttpsink->cookies) {
    gchar **cookie;

    for (cookie = souphttpsink->cookies; *cookie != NULL; cookie++) {
      soup_message_headers_append (souphttpsink->message->request_headers,
          "Cookie", *cookie);
    }
  }

  n = 0;
  if (souphttpsink->offset == 0) {
    for (g = souphttpsink->streamheader_buffers; g; g = g_list_next (g)) {
      GstBuffer *buffer = g->data;
      GstMapInfo map;

      GST_DEBUG_OBJECT (souphttpsink, "queueing stream headers");
      gst_buffer_map (buffer, &map, GST_MAP_READ);
      /* Stream headers are updated whenever ::set_caps is called, so there's
       * no guarantees about their lifetime and we ask libsoup to copy them 
       * into the message body with SOUP_MEMORY_COPY. */
      soup_message_body_append (souphttpsink->message->request_body,
          SOUP_MEMORY_COPY, map.data, map.size);
      n += map.size;
      gst_buffer_unmap (buffer, &map);
    }
  }

  for (g = souphttpsink->queued_buffers; g; g = g_list_next (g)) {
    GstBuffer *buffer = g->data;
    if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) {
      GstMapInfo map;

      gst_buffer_map (buffer, &map, GST_MAP_READ);
      /* Queued buffers are only freed in the next iteration of the mainloop
       * after the message body has been written out, so we don't need libsoup
       * to copy those while appending to the body. However, if the buffer is
       * used elsewhere, it should be copied. Hence, SOUP_MEMORY_TEMPORARY. */
      soup_message_body_append (souphttpsink->message->request_body,
          SOUP_MEMORY_TEMPORARY, map.data, map.size);
      n += map.size;
      gst_buffer_unmap (buffer, &map);
    }
  }

  if (souphttpsink->offset != 0) {
    char *s;
    s = g_strdup_printf ("bytes %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/*",
        souphttpsink->offset, souphttpsink->offset + n - 1);
    soup_message_headers_append (souphttpsink->message->request_headers,
        "Content-Range", s);
    g_free (s);
  }

  if (n == 0) {
    GST_DEBUG_OBJECT (souphttpsink,
        "total size of buffers queued is 0, freeing everything");
    g_list_free_full (souphttpsink->queued_buffers,
        (GDestroyNotify) gst_buffer_unref);
    souphttpsink->queued_buffers = NULL;
    g_object_unref (souphttpsink->message);
    souphttpsink->message = NULL;
    return;
  }

  souphttpsink->sent_buffers = souphttpsink->queued_buffers;
  souphttpsink->queued_buffers = NULL;

  GST_DEBUG_OBJECT (souphttpsink,
      "queue message %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
      souphttpsink->offset, n);
  soup_session_queue_message (souphttpsink->session, souphttpsink->message,
      callback, souphttpsink);

  souphttpsink->offset += n;
}
static bool startHttp(ResourceHandle* handle)
{
    ASSERT(handle);

    SoupSession* session = handle->defaultSession();
    ensureSessionIsInitialized(session);

    ResourceHandleInternal* d = handle->getInternal();

    ResourceRequest request(handle->request());
    KURL url(request.url());
    url.removeFragmentIdentifier();
    request.setURL(url);

    d->m_msg = request.toSoupMessage();
    if (!d->m_msg)
        return false;

    if(!handle->shouldContentSniff())
        soup_message_disable_feature(d->m_msg, SOUP_TYPE_CONTENT_SNIFFER);

    g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle);
    g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle);
    g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle);
    g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), handle);

#ifdef HAVE_LIBSOUP_2_29_90
    String firstPartyString = request.firstPartyForCookies().string();
    if (!firstPartyString.isEmpty()) {
        GOwnPtr<SoupURI> firstParty(soup_uri_new(firstPartyString.utf8().data()));
        soup_message_set_first_party(d->m_msg, firstParty.get());
    }
#endif
    g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(handle));

    FormData* httpBody = d->m_request.httpBody();
    if (httpBody && !httpBody->isEmpty()) {
        size_t numElements = httpBody->elements().size();

        // handle the most common case (i.e. no file upload)
        if (numElements < 2) {
            Vector<char> body;
            httpBody->flatten(body);
            soup_message_set_request(d->m_msg, d->m_request.httpContentType().utf8().data(),
                                     SOUP_MEMORY_COPY, body.data(), body.size());
        } else {
            /*
             * we have more than one element to upload, and some may
             * be (big) files, which we will want to mmap instead of
             * copying into memory; TODO: support upload of non-local
             * (think sftp://) files by using GIO?
             */
            soup_message_body_set_accumulate(d->m_msg->request_body, FALSE);
            for (size_t i = 0; i < numElements; i++) {
                const FormDataElement& element = httpBody->elements()[i];

                if (element.m_type == FormDataElement::data)
                    soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());
                else {
                    /*
                     * mapping for uploaded files code inspired by technique used in
                     * libsoup's simple-httpd test
                     */
                    GError* error = 0;
                    gchar* fileName = filenameFromString(element.m_filename);
                    GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error);

                    g_free(fileName);

                    if (error) {
                        g_error_free(error);
                        g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA,
                                                             0, 0, 0, 0, handle);
                        g_object_unref(d->m_msg);
                        d->m_msg = 0;

                        return false;
                    }

                    SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping),
                                                                        g_mapped_file_get_length(fileMapping),
                                                                        fileMapping,
#if GLIB_CHECK_VERSION(2, 21, 3)
                                                                        reinterpret_cast<GDestroyNotify>(g_mapped_file_unref));
#else
                                                                        reinterpret_cast<GDestroyNotify>(g_mapped_file_free));
#endif
                    soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer);
                    soup_buffer_free(soupBuffer);
                }
            }
        }
    }
示例#7
0
static void
handle_received_chunk (SoupMessage * msg, SoupBuffer * chunk,
    AurClient * client)
{
  const gchar *ptr;
  gsize length;
  AurClientFlags flag = get_flag_from_msg (msg);
  JsonNode *root;
  GstStructure *s;
  GError *err = NULL;
  gchar *json_str = NULL;

  if (client->was_connected & flag) {
    g_print ("Successfully connected %s to server %s:%d\n",
        flag == AUR_CLIENT_PLAYER ? "player" : "controller",
        client->connected_server, client->connected_port);
    client->was_connected |= flag;
  }

  /* Set up or re-trigger 20 second idle timeout for ping messages */
  if (client->idle_timeout)
    g_source_remove (client->idle_timeout);
  client->idle_timeout = g_timeout_add_seconds (20,
      (GSourceFunc) conn_idle_timeout, client);

#if HAVE_AVAHI
  /* Successful server connection, stop avahi discovery */
  if (client->avahi_client) {
    avahi_client_free (client->avahi_client);
    client->avahi_sb = NULL;
    client->avahi_client = NULL;
  }
#endif

  if (client->json == NULL)
    client->json = json_parser_new ();

  ptr = memchr (chunk->data, '\0', chunk->length);
  if (!ptr)
    return;

  /* Save remaining portion */
  ptr += 1;
  length = (chunk->length - (ptr - chunk->data));

  chunk = soup_message_body_flatten (msg->response_body);

  // Ignore null string chunks
  if (chunk->length < 2)
    goto end;

  /* Workaround: Copy to a string to avoid stupid
   * UTF-8 validation bug in json-glib 1.0.2 */
  json_str = g_strndup (chunk->data, chunk->length);

#if 0
  g_print ("%s\n", json_str);
#endif

  if (!json_parser_load_from_data (client->json, json_str, -1,
          &err) || err != NULL)
    goto fail;

  root = json_parser_get_root (client->json);
  s = aur_json_to_gst_structure (root);

  if (s == NULL)
    goto fail;                  /* Invalid chunk */

  if (flag == AUR_CLIENT_PLAYER)
    handle_player_message (client, s);
  else
    handle_controller_message (client, s);

  gst_structure_free (s);

end:
  g_free (json_str);

  soup_message_body_truncate (msg->response_body);
  /* Put back remaining part */
  if (length)
    soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, ptr,
        length);
  return;

fail:{
    g_print ("Failed to parse message '%s'\n", json_str);
    if (err) {
      g_print ("Error: %s\n", err->message);
      g_error_free (err);
    }
    goto end;
  }
}
示例#8
0
static void
do_get (SoupServer *server, SoupMessage *msg, const char *path)
{
	char *slash;
	struct stat st;
	int fd;
	static char *path2 = NULL;

	if (!path2){g_free(path2); path2=NULL;}
	path2 = g_build_filename((const gchar *)global_get("htmlhome"), path, NULL);

	if (stat (path2, &st) == -1) {
		if (errno == EPERM)
			soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
		else if (errno == ENOENT)
			soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
		else
			soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
		return;
	}

	if (S_ISDIR (st.st_mode)) {
		char *index_path;

		slash = strrchr (path, '/');
		if (!slash || slash[1]) {
			char *uri, *redir_uri;

			uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
			redir_uri = g_strdup_printf ("%s/", uri);
			soup_message_headers_append (msg->response_headers,
						     "Location", redir_uri);
			soup_message_set_status (msg, SOUP_STATUS_MOVED_PERMANENTLY);
			g_free (redir_uri);
			g_free (uri);
			return;
		}

		index_path = g_strdup_printf ("%s/index.html", path);
		if (stat (index_path, &st) != -1) {
			do_get (server, msg, index_path);
			g_free (index_path);
			return;
		}

		char *buf = "<title>Forbidden</title><h1>Forbidden</h1>", len[10];
		sprintf(len, "%d", strlen(buf));

		soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE,
					  buf, strlen(buf));
        soup_message_headers_append (msg->response_headers,
                    "Content-Length", len);
		soup_message_set_status(msg, SOUP_STATUS_FORBIDDEN);
		return;
	}

	fd = open (path2, O_RDONLY);
	if (fd == -1) {
		soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
		return;
	}

	if (msg->method == SOUP_METHOD_GET) {
		char *buf;

		buf = g_malloc (st.st_size);
		read (fd, buf, st.st_size);
		close (fd);
		soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE,
					  buf, st.st_size);
	} else /* msg->method == SOUP_METHOD_HEAD */ {
		char *length;

		/* We could just use the same code for both GET and
		 * HEAD. But we'll optimize and avoid the extra
		 * malloc.
		 */
		length = g_strdup_printf ("%lu", (gulong)st.st_size);
		soup_message_headers_append (msg->response_headers,
					     "Content-Length", length);
		g_free (length);
	}

	soup_message_set_status (msg, SOUP_STATUS_OK);
}