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); } } } }
/** * 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); } } } }
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; } }
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); }