static void do_content_length_framing_test (void) { SoupSession *session; SoupMessage *msg; SoupURI *request_uri; goffset declared_length; debug_printf (1, "\nInvalid Content-Length framing tests\n"); session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL); debug_printf (1, " Content-Length larger than message body length\n"); request_uri = soup_uri_new_with_base (base_uri, "/content-length/long"); msg = soup_message_new_from_uri ("GET", request_uri); soup_session_send_message (session, msg); if (msg->status_code != SOUP_STATUS_OK) { debug_printf (1, " Unexpected response: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } else { declared_length = soup_message_headers_get_content_length (msg->response_headers); debug_printf (2, " Content-Length: %lu, body: %s\n", (gulong)declared_length, msg->response_body->data); if (msg->response_body->length >= declared_length) { debug_printf (1, " Body length %lu >= declared length %lu\n", (gulong)msg->response_body->length, (gulong)declared_length); errors++; } } soup_uri_free (request_uri); g_object_unref (msg); debug_printf (1, " Server claims 'Connection: close' but doesn't\n"); request_uri = soup_uri_new_with_base (base_uri, "/content-length/noclose"); msg = soup_message_new_from_uri ("GET", request_uri); soup_session_send_message (session, msg); if (msg->status_code != SOUP_STATUS_OK) { debug_printf (1, " Unexpected response: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } else { declared_length = soup_message_headers_get_content_length (msg->response_headers); debug_printf (2, " Content-Length: %lu, body: %s\n", (gulong)declared_length, msg->response_body->data); if (msg->response_body->length != declared_length) { debug_printf (1, " Body length %lu != declared length %lu\n", (gulong)msg->response_body->length, (gulong)declared_length); errors++; } } soup_uri_free (request_uri); g_object_unref (msg); soup_test_session_abort_unref (session); }
static void do_response_test (SoupSession *session, SoupURI *base_uri) { GetTestData gtd; SoupMessage *msg; const char *client_md5, *server_md5; debug_printf (1, "GET\n"); gtd.current_chunk = NULL; gtd.length = 0; gtd.check = g_checksum_new (G_CHECKSUM_MD5); msg = soup_message_new_from_uri ("GET", base_uri); soup_message_body_set_accumulate (msg->response_body, FALSE); G_GNUC_BEGIN_IGNORE_DEPRECATIONS; soup_message_set_chunk_allocator (msg, chunk_allocator, >d, NULL); G_GNUC_END_IGNORE_DEPRECATIONS; g_signal_connect (msg, "got_chunk", G_CALLBACK (got_chunk), >d); soup_session_send_message (session, msg); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " message failed: %d %s\n", msg->status_code, msg->reason_phrase); errors++; } if (msg->response_body->data) { debug_printf (1, " msg->response_body set!\n"); errors++; } if (soup_message_headers_get_content_length (msg->response_headers) != gtd.length) { debug_printf (1, " received length mismatch: %d vs %d\n", (int)soup_message_headers_get_content_length (msg->response_headers), gtd.length); errors++; } client_md5 = g_checksum_get_string (gtd.check); server_md5 = soup_message_headers_get_one (msg->response_headers, "Content-MD5"); if (!server_md5 || strcmp (client_md5, server_md5) != 0) { debug_printf (1, " client/server data mismatch: %s vs %s\n", client_md5, server_md5 ? server_md5 : "(null)"); errors++; } g_object_unref (msg); g_checksum_free (gtd.check); }
void ResourceResponse::updateFromSoupMessage(SoupMessage* soupMessage) { SoupURI* soupURI = soup_message_get_uri(soupMessage); GOwnPtr<gchar> uri(soup_uri_to_string(soupURI, FALSE)); m_url = KURL(KURL(), String::fromUTF8(uri.get())); m_httpStatusCode = soupMessage->status_code; SoupMessageHeadersIter headersIter; const char* headerName; const char* headerValue; soup_message_headers_iter_init(&headersIter, soupMessage->response_headers); while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); m_soupFlags = soup_message_get_flags(soupMessage); String contentType = soup_message_headers_get_one(soupMessage->response_headers, "Content-Type"); setMimeType(extractMIMETypeFromMediaType(contentType)); setTextEncodingName(extractCharsetFromMediaType(contentType)); setExpectedContentLength(soup_message_headers_get_content_length(soupMessage->response_headers)); setHTTPStatusText(soupMessage->reason_phrase); setSuggestedFilename(filenameFromHTTPContentDisposition(httpHeaderField("Content-Disposition"))); }
static goffset soup_request_http_get_content_length (SoupRequest *request) { SoupRequestHTTP *http = SOUP_REQUEST_HTTP (request); return soup_message_headers_get_content_length (http->priv->msg->response_headers); }
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 void update_media_progress (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data) { CbMedia *media = user_data; if (msg->response_headers == NULL) return; double chunk_percent = chunk->length / (double)soup_message_headers_get_content_length (msg->response_headers); cb_media_update_progress (media, media->percent_loaded + chunk_percent); }
void gotheaders(SoupMessage *msg, GtkTreeRowReference *ref) { GtkTreeIter iter; GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(builder, "downloads")); gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, gtk_tree_row_reference_get_path(ref)); if(SOUP_ENCODING_CONTENT_LENGTH == soup_message_headers_get_encoding(msg->response_headers)) { gint64 content_length = soup_message_headers_get_content_length(msg->response_headers); printf("got content_length %lld\n", content_length); gtk_list_store_set(store, &iter, 2, content_length, 3, (gint64)0, -1); } else { printf("got content_length -1\n"); gtk_list_store_set(store, &iter, 2, -1, -1); } }
static void on_got_headers (SoupMessage *message, gpointer user_data) { GDownloadable *download = G_DOWNLOADABLE (user_data); g_assert (download != NULL); if (message->status_code != SOUP_STATUS_OK) { rookie_debug ("status code = %d\n", message->status_code); } // soup_message_headers_foreach (message->response_headers, foreach_header, NULL); g_downloadable_set_status (download, G_DOWNLOADABLE_DOWNLOADING); if (download->priv->size == 0) download->priv->size = soup_message_headers_get_content_length (message->response_headers); }
static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) { SoupMessageHeadersIter iter; const char* name = NULL; const char* value = NULL; soup_message_headers_iter_init(&iter, msg->response_headers); while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); String contentType = soup_message_headers_get(msg->response_headers, "Content-Type"); char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE); response->setUrl(KURL(uri)); g_free(uri); response->setMimeType(extractMIMETypeFromMediaType(contentType)); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers)); response->setHTTPStatusCode(msg->status_code); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); }
void ResourceResponse::updateFromSoupMessageHeaders(const SoupMessageHeaders* messageHeaders) { SoupMessageHeaders* headers = const_cast<SoupMessageHeaders*>(messageHeaders); SoupMessageHeadersIter headersIter; const char* headerName; const char* headerValue; // updateFromSoupMessage could be called several times for the same ResourceResponse object, // thus, we need to clear old header values and update m_httpHeaderFields from soupMessage headers. m_httpHeaderFields.clear(); soup_message_headers_iter_init(&headersIter, headers); while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) { String headerNameString = String::fromUTF8WithLatin1Fallback(headerName, strlen(headerName)); HTTPHeaderMap::const_iterator it = m_httpHeaderFields.find(headerNameString); if (it == m_httpHeaderFields.end() || (it != m_httpHeaderFields.end() && it->value.isEmpty())) m_httpHeaderFields.set(headerNameString, String::fromUTF8WithLatin1Fallback(headerValue, strlen(headerValue))); else { StringBuilder builder; builder.append(it->value); builder.appendLiteral(", "); builder.append(String::fromUTF8WithLatin1Fallback(headerValue, strlen(headerValue))); m_httpHeaderFields.set(headerNameString, builder.toString()); } } String contentType; const char* officialType = soup_message_headers_get_one(headers, "Content-Type"); if (!m_sniffedContentType.isEmpty() && m_sniffedContentType != officialType) contentType = m_sniffedContentType; else contentType = officialType; setMimeType(extractMIMETypeFromMediaType(contentType)); setTextEncodingName(extractCharsetFromMediaType(contentType)); setExpectedContentLength(soup_message_headers_get_content_length(headers)); setSuggestedFilename(filenameFromHTTPContentDisposition(httpHeaderField("Content-Disposition")));}
static void get_response_headers (SoupMessage *msg, GString *headers, SoupEncoding *encoding, gpointer user_data) { SoupEncoding claimed_encoding; SoupMessageHeadersIter iter; const char *name, *value; handle_partial_get (msg); g_string_append_printf (headers, "HTTP/1.%c %d %s\r\n", soup_message_get_http_version (msg) == SOUP_HTTP_1_0 ? '0' : '1', msg->status_code, msg->reason_phrase); claimed_encoding = soup_message_headers_get_encoding (msg->response_headers); if ((msg->method == SOUP_METHOD_HEAD || msg->status_code == SOUP_STATUS_NO_CONTENT || msg->status_code == SOUP_STATUS_NOT_MODIFIED || SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) || (msg->method == SOUP_METHOD_CONNECT && SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))) *encoding = SOUP_ENCODING_NONE; else *encoding = claimed_encoding; if (claimed_encoding == SOUP_ENCODING_CONTENT_LENGTH && !soup_message_headers_get_content_length (msg->response_headers)) { soup_message_headers_set_content_length (msg->response_headers, msg->response_body->length); } soup_message_headers_iter_init (&iter, msg->response_headers); while (soup_message_headers_iter_next (&iter, &name, &value)) g_string_append_printf (headers, "%s: %s\r\n", name, value); g_string_append (headers, "\r\n"); }
/* Attempts to push forward the writing side of @msg's I/O. Returns * %TRUE if it manages to make some progress, and it is likely that * further progress can be made. Returns %FALSE if it has reached a * stopping point of some sort (need input from the application, * socket not writable, write is complete, etc). */ static gboolean io_write (SoupMessage *msg, gboolean blocking, GCancellable *cancellable, GError **error) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; SoupBuffer *chunk; gssize nwrote; if (io->async_close_error) { g_propagate_error (error, io->async_close_error); io->async_close_error = NULL; return FALSE; } else if (io->async_close_wait) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, _("Operation would block")); return FALSE; } switch (io->write_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: if (io->mode == SOUP_MESSAGE_IO_SERVER && io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING && msg->status_code == 0) { /* Client requested "Expect: 100-continue", and * server did not set an error. */ soup_message_set_status (msg, SOUP_STATUS_CONTINUE); } if (!io->write_buf->len) { io->get_headers_cb (msg, io->write_buf, &io->write_encoding, io->header_data); } while (io->written < io->write_buf->len) { nwrote = g_pollable_stream_write (io->ostream, io->write_buf->str + io->written, io->write_buf->len - io->written, blocking, cancellable, error); if (nwrote == -1) return FALSE; io->written += nwrote; } io->written = 0; g_string_truncate (io->write_buf, 0); if (io->mode == SOUP_MESSAGE_IO_SERVER && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { if (msg->status_code == SOUP_STATUS_CONTINUE) { /* Stop and wait for the body now */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START; } else { /* We just wrote a 1xx response * header, so stay in STATE_HEADERS. * (The caller will pause us from the * wrote_informational callback if he * is not ready to send the final * response.) */ } soup_message_wrote_informational (msg); /* If this was "101 Switching Protocols", then * the server probably stole the connection... */ if (io != priv->io_data) return FALSE; soup_message_cleanup_response (msg); break; } if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) { SoupMessageHeaders *hdrs = (io->mode == SOUP_MESSAGE_IO_CLIENT) ? msg->request_headers : msg->response_headers; io->write_length = soup_message_headers_get_content_length (hdrs); } if (io->mode == SOUP_MESSAGE_IO_CLIENT && soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { /* Need to wait for the Continue response */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; } else { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START; /* If the client was waiting for a Continue * but we sent something else, then they're * now done writing. */ if (io->mode == SOUP_MESSAGE_IO_SERVER && io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->read_state = SOUP_MESSAGE_IO_STATE_DONE; } soup_message_wrote_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: io->body_ostream = soup_body_output_stream_new (io->ostream, io->write_encoding, io->write_length); io->write_state = SOUP_MESSAGE_IO_STATE_BODY; break; case SOUP_MESSAGE_IO_STATE_BODY: if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF && io->write_encoding != SOUP_ENCODING_CHUNKED) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } if (!io->write_chunk) { io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset); if (!io->write_chunk) { g_return_val_if_fail (!io->item || !io->item->new_api, FALSE); soup_message_io_pause (msg); return FALSE; } if (!io->write_chunk->length) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } } nwrote = g_pollable_stream_write (io->body_ostream, io->write_chunk->data + io->written, io->write_chunk->length - io->written, blocking, cancellable, error); if (nwrote == -1) return FALSE; chunk = soup_buffer_new_subbuffer (io->write_chunk, io->written, nwrote); io->written += nwrote; if (io->write_length) io->write_length -= nwrote; if (io->written == io->write_chunk->length) io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA; soup_message_wrote_body_data (msg, chunk); soup_buffer_free (chunk); break; case SOUP_MESSAGE_IO_STATE_BODY_DATA: io->written = 0; if (io->write_chunk->length == 0) { io->write_state = SOUP_MESSAGE_IO_STATE_BODY_FLUSH; break; } if (io->mode == SOUP_MESSAGE_IO_SERVER || priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD) soup_message_body_wrote_chunk (io->write_body, io->write_chunk); io->write_body_offset += io->write_chunk->length; soup_buffer_free (io->write_chunk); io->write_chunk = NULL; io->write_state = SOUP_MESSAGE_IO_STATE_BODY; soup_message_wrote_chunk (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_FLUSH: if (io->body_ostream) { if (blocking || io->write_encoding != SOUP_ENCODING_CHUNKED) { if (!g_output_stream_close (io->body_ostream, cancellable, error)) return FALSE; g_clear_object (&io->body_ostream); } else { io->async_close_wait = g_cancellable_new (); if (io->async_context) g_main_context_push_thread_default (io->async_context); g_output_stream_close_async (io->body_ostream, G_PRIORITY_DEFAULT, cancellable, closed_async, g_object_ref (msg)); if (io->async_context) g_main_context_pop_thread_default (io->async_context); } } io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; break; case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; soup_message_wrote_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: io->write_state = SOUP_MESSAGE_IO_STATE_DONE; if (io->mode == SOUP_MESSAGE_IO_CLIENT) io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; break; default: g_return_val_if_reached (FALSE); } return TRUE; }
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 void get_request_headers (SoupMessage *req, GString *header, SoupEncoding *encoding, gpointer user_data) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (req); gboolean proxy = GPOINTER_TO_UINT (user_data); SoupURI *uri = soup_message_get_uri (req); char *uri_host; char *uri_string; SoupMessageHeadersIter iter; const char *name, *value; if (strchr (uri->host, ':')) uri_host = g_strdup_printf ("[%s]", uri->host); else uri_host = uri->host; if (req->method == SOUP_METHOD_CONNECT) { /* CONNECT URI is hostname:port for tunnel destination */ uri_string = g_strdup_printf ("%s:%d", uri_host, uri->port); } else { /* Proxy expects full URI to destination. Otherwise * just the path. */ uri_string = soup_uri_to_string (uri, !proxy); } if (priv->http_version == SOUP_HTTP_1_0) { g_string_append_printf (header, "%s %s HTTP/1.0\r\n", req->method, uri_string); } else { g_string_append_printf (header, "%s %s HTTP/1.1\r\n", req->method, uri_string); if (!soup_message_headers_get_one (req->request_headers, "Host")) { if (soup_uri_uses_default_port (uri)) { g_string_append_printf (header, "Host: %s\r\n", uri_host); } else { g_string_append_printf (header, "Host: %s:%d\r\n", uri_host, uri->port); } } } g_free (uri_string); if (uri_host != uri->host) g_free (uri_host); *encoding = soup_message_headers_get_encoding (req->request_headers); if ((*encoding == SOUP_ENCODING_CONTENT_LENGTH || *encoding == SOUP_ENCODING_NONE) && (req->request_body->length > 0 || soup_message_headers_get_one (req->request_headers, "Content-Type")) && !soup_message_headers_get_content_length (req->request_headers)) { *encoding = SOUP_ENCODING_CONTENT_LENGTH; soup_message_headers_set_content_length (req->request_headers, req->request_body->length); } soup_message_headers_iter_init (&iter, req->request_headers); while (soup_message_headers_iter_next (&iter, &name, &value)) g_string_append_printf (header, "%s: %s\r\n", name, value); g_string_append (header, "\r\n"); }
static void io_read (SoupSocket *sock, SoupMessage *msg) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; guint status; read_more: switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_NOT_STARTED: return; case SOUP_MESSAGE_IO_STATE_HEADERS: if (!read_metadata (msg, TRUE)) return; /* We need to "rewind" io->read_meta_buf back one line. * That SHOULD be two characters (CR LF), but if the * web server was stupid, it might only be one. */ if (io->read_meta_buf->len < 3 || io->read_meta_buf->data[io->read_meta_buf->len - 2] == '\n') io->read_meta_buf->len--; else io->read_meta_buf->len -= 2; io->read_meta_buf->data[io->read_meta_buf->len] = '\0'; status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data, io->read_meta_buf->len, &io->read_encoding, io->user_data); g_byte_array_set_size (io->read_meta_buf, 0); if (status != SOUP_STATUS_OK) { /* Either we couldn't parse the headers, or they * indicated something that would mean we wouldn't * be able to parse the body. (Eg, unknown * Transfer-Encoding.). Skip the rest of the * reading, and make sure the connection gets * closed when we're done. */ soup_message_set_status (msg, status); soup_message_headers_append (msg->request_headers, "Connection", "close"); io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; break; } if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) { SoupMessageHeaders *hdrs = (io->mode == SOUP_MESSAGE_IO_CLIENT) ? msg->response_headers : msg->request_headers; io->read_length = soup_message_headers_get_content_length (hdrs); } if (io->mode == SOUP_MESSAGE_IO_CLIENT && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { if (msg->status_code == SOUP_STATUS_CONTINUE && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) { /* Pause the reader, unpause the writer */ io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->write_state = io_body_state (io->write_encoding); } else { /* Just stay in HEADERS */ io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; } } else if (io->mode == SOUP_MESSAGE_IO_SERVER && soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { /* The client requested a Continue response. The * got_headers handler may change this to something * else though. */ soup_message_set_status (msg, SOUP_STATUS_CONTINUE); io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; } else { io->read_state = io_body_state (io->read_encoding); /* If the client was waiting for a Continue * but got something else, then it's done * writing. */ if (io->mode == SOUP_MESSAGE_IO_CLIENT && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; } if (io->mode == SOUP_MESSAGE_IO_CLIENT && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_got_informational (msg); soup_message_cleanup_response (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; } else { SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_got_headers (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; } break; case SOUP_MESSAGE_IO_STATE_BLOCKING: io_write (sock, msg); /* As in the io_write case, we *must* return here. */ return; case SOUP_MESSAGE_IO_STATE_BODY: if (!read_body_chunk (msg)) return; got_body: if (!io_handle_sniffing (msg, TRUE)) { /* If the message was paused (as opposed to * cancelled), we need to make sure we wind up * back here when it's unpaused, even if it * was doing a chunked or EOF-terminated read * before. */ if (io == priv->io_data) { io->read_state = SOUP_MESSAGE_IO_STATE_BODY; io->read_encoding = SOUP_ENCODING_CONTENT_LENGTH; io->read_length = 0; } return; } io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_got_body (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; break; case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE: if (!read_metadata (msg, FALSE)) return; io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16); g_byte_array_set_size (io->read_meta_buf, 0); if (io->read_length > 0) io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK; else io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS; break; case SOUP_MESSAGE_IO_STATE_CHUNK: if (!read_body_chunk (msg)) return; io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END; break; case SOUP_MESSAGE_IO_STATE_CHUNK_END: if (!read_metadata (msg, FALSE)) return; g_byte_array_set_size (io->read_meta_buf, 0); io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE; break; case SOUP_MESSAGE_IO_STATE_TRAILERS: if (!read_metadata (msg, FALSE)) return; if (io->read_meta_buf->len <= SOUP_MESSAGE_IO_EOL_LEN) goto got_body; /* FIXME: process trailers */ g_byte_array_set_size (io->read_meta_buf, 0); break; case SOUP_MESSAGE_IO_STATE_FINISHING: if (io->read_tag) { g_signal_handler_disconnect (io->sock, io->read_tag); io->read_tag = 0; } io->read_state = SOUP_MESSAGE_IO_STATE_DONE; if (io->mode == SOUP_MESSAGE_IO_SERVER) { io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; io_write (sock, msg); } else soup_message_io_finished (msg); return; case SOUP_MESSAGE_IO_STATE_DONE: default: g_return_if_reached (); } goto read_more; }
static void io_write (SoupSocket *sock, SoupMessage *msg) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; write_more: switch (io->write_state) { case SOUP_MESSAGE_IO_STATE_NOT_STARTED: return; case SOUP_MESSAGE_IO_STATE_HEADERS: if (!io->write_buf->len) { io->get_headers_cb (msg, io->write_buf, &io->write_encoding, io->user_data); if (!io->write_buf->len) { soup_message_io_pause (msg); return; } } if (!write_data (msg, io->write_buf->str, io->write_buf->len, FALSE)) return; g_string_truncate (io->write_buf, 0); if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) { SoupMessageHeaders *hdrs = (io->mode == SOUP_MESSAGE_IO_CLIENT) ? msg->request_headers : msg->response_headers; io->write_length = soup_message_headers_get_content_length (hdrs); } if (io->mode == SOUP_MESSAGE_IO_SERVER && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { if (msg->status_code == SOUP_STATUS_CONTINUE) { /* Stop and wait for the body now */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->read_state = io_body_state (io->read_encoding); } else { /* We just wrote a 1xx response * header, so stay in STATE_HEADERS. * (The caller will pause us from the * wrote_informational callback if he * is not ready to send the final * response.) */ } } else if (io->mode == SOUP_MESSAGE_IO_CLIENT && soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { /* Need to wait for the Continue response */ io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; } else { io->write_state = io_body_state (io->write_encoding); /* If the client was waiting for a Continue * but we sent something else, then they're * now done writing. */ if (io->mode == SOUP_MESSAGE_IO_SERVER && io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; } SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { soup_message_wrote_informational (msg); soup_message_cleanup_response (msg); } else soup_message_wrote_headers (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; break; case SOUP_MESSAGE_IO_STATE_BLOCKING: io_read (sock, msg); /* If io_read reached a point where we could write * again, it would have recursively called io_write. * So (a) we don't need to try to keep writing, and * (b) we can't anyway, because msg may have been * destroyed. */ return; case SOUP_MESSAGE_IO_STATE_BODY: if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) { wrote_body: io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_wrote_body (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; break; } if (!io->write_chunk) { io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset); if (!io->write_chunk) { soup_message_io_pause (msg); return; } if (io->write_chunk->length > io->write_length && io->write_encoding != SOUP_ENCODING_EOF) { /* App is trying to write more than it * claimed it would; we have to truncate. */ SoupBuffer *truncated = soup_buffer_new_subbuffer (io->write_chunk, 0, io->write_length); soup_buffer_free (io->write_chunk); io->write_chunk = truncated; } else if (io->write_encoding == SOUP_ENCODING_EOF && !io->write_chunk->length) goto wrote_body; } if (!write_data (msg, io->write_chunk->data, io->write_chunk->length, TRUE)) return; if (io->mode == SOUP_MESSAGE_IO_SERVER) soup_message_body_wrote_chunk (io->write_body, io->write_chunk); io->write_body_offset += io->write_chunk->length; soup_buffer_free (io->write_chunk); io->write_chunk = NULL; SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_wrote_chunk (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; break; case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE: if (!io->write_chunk) { io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset); if (!io->write_chunk) { soup_message_io_pause (msg); return; } g_string_append_printf (io->write_buf, "%lx\r\n", (unsigned long) io->write_chunk->length); io->write_body_offset += io->write_chunk->length; } if (!write_data (msg, io->write_buf->str, io->write_buf->len, FALSE)) return; g_string_truncate (io->write_buf, 0); if (io->write_chunk->length == 0) { /* The last chunk has no CHUNK_END... */ io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS; break; } io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK; /* fall through */ case SOUP_MESSAGE_IO_STATE_CHUNK: if (!write_data (msg, io->write_chunk->data, io->write_chunk->length, TRUE)) return; if (io->mode == SOUP_MESSAGE_IO_SERVER) soup_message_body_wrote_chunk (io->write_body, io->write_chunk); soup_buffer_free (io->write_chunk); io->write_chunk = NULL; io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END; SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_wrote_chunk (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; /* fall through */ case SOUP_MESSAGE_IO_STATE_CHUNK_END: if (!write_data (msg, SOUP_MESSAGE_IO_EOL, SOUP_MESSAGE_IO_EOL_LEN, FALSE)) return; io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE; break; case SOUP_MESSAGE_IO_STATE_TRAILERS: if (!write_data (msg, SOUP_MESSAGE_IO_EOL, SOUP_MESSAGE_IO_EOL_LEN, FALSE)) return; io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK; soup_message_wrote_body (msg); SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED; /* fall through */ case SOUP_MESSAGE_IO_STATE_FINISHING: if (io->write_tag) { g_signal_handler_disconnect (io->sock, io->write_tag); io->write_tag = 0; } io->write_state = SOUP_MESSAGE_IO_STATE_DONE; if (io->mode == SOUP_MESSAGE_IO_CLIENT) { io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; io_read (sock, msg); } else soup_message_io_finished (msg); return; case SOUP_MESSAGE_IO_STATE_DONE: default: g_return_if_reached (); } goto write_more; }
/* Attempts to push forward the reading side of @msg's I/O. Returns * %TRUE if it manages to make some progress, and it is likely that * further progress can be made. Returns %FALSE if it has reached a * stopping point of some sort (need input from the application, * socket not readable, read is complete, etc). */ static gboolean io_read (SoupMessage *msg, gboolean blocking, GCancellable *cancellable, GError **error) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; guchar *stack_buf = NULL; gssize nread; SoupBuffer *buffer; guint status; switch (io->read_state) { case SOUP_MESSAGE_IO_STATE_HEADERS: if (!read_headers (msg, blocking, cancellable, error)) return FALSE; status = io->parse_headers_cb (msg, (char *)io->read_header_buf->data, io->read_header_buf->len, &io->read_encoding, io->header_data, error); g_byte_array_set_size (io->read_header_buf, 0); if (status != SOUP_STATUS_OK) { /* Either we couldn't parse the headers, or they * indicated something that would mean we wouldn't * be able to parse the body. (Eg, unknown * Transfer-Encoding.). Skip the rest of the * reading, and make sure the connection gets * closed when we're done. */ soup_message_set_status (msg, status); soup_message_headers_append (msg->request_headers, "Connection", "close"); io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; break; } if (io->mode == SOUP_MESSAGE_IO_CLIENT && SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) { if (msg->status_code == SOUP_STATUS_CONTINUE && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) { /* Pause the reader, unpause the writer */ io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START; } else { /* Just stay in HEADERS */ io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS; } /* Informational responses have no bodies, so * bail out here rather than parsing encoding, etc */ soup_message_got_informational (msg); /* If this was "101 Switching Protocols", then * the session may have stolen the connection... */ if (io != priv->io_data) return FALSE; soup_message_cleanup_response (msg); break; } else if (io->mode == SOUP_MESSAGE_IO_SERVER && soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) { /* We must return a status code and response * headers to the client; either an error to * be set by a got-headers handler below, or * else %SOUP_STATUS_CONTINUE otherwise. */ io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING; } else { io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START; /* If the client was waiting for a Continue * but got something else, then it's done * writing. */ if (io->mode == SOUP_MESSAGE_IO_CLIENT && io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING; } if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) { SoupMessageHeaders *hdrs = (io->mode == SOUP_MESSAGE_IO_CLIENT) ? msg->response_headers : msg->request_headers; io->read_length = soup_message_headers_get_content_length (hdrs); if (io->mode == SOUP_MESSAGE_IO_CLIENT && !soup_message_is_keepalive (msg)) { /* Some servers suck and send * incorrect Content-Length values, so * allow EOF termination in this case * (iff the message is too short) too. */ io->read_encoding = SOUP_ENCODING_EOF; } } else io->read_length = -1; soup_message_got_headers (msg); break; case SOUP_MESSAGE_IO_STATE_BODY_START: if (!io->body_istream) { GInputStream *body_istream = soup_body_input_stream_new (G_INPUT_STREAM (io->istream), io->read_encoding, io->read_length); /* TODO: server-side messages do not have a io->item. This means * that we cannot use content processors for them right now. */ if (io->mode == SOUP_MESSAGE_IO_CLIENT) { io->body_istream = soup_message_setup_body_istream (body_istream, msg, io->item->session, SOUP_STAGE_MESSAGE_BODY); g_object_unref (body_istream); } else { io->body_istream = body_istream; } } if (priv->sniffer) { SoupContentSnifferStream *sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (io->body_istream); const char *content_type; GHashTable *params; if (!soup_content_sniffer_stream_is_ready (sniffer_stream, blocking, cancellable, error)) return FALSE; content_type = soup_content_sniffer_stream_sniff (sniffer_stream, ¶ms); soup_message_content_sniffed (msg, content_type, params); } io->read_state = SOUP_MESSAGE_IO_STATE_BODY; break; case SOUP_MESSAGE_IO_STATE_BODY: if (priv->chunk_allocator) { buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data); if (!buffer) { g_return_val_if_fail (!io->item || !io->item->new_api, FALSE); soup_message_io_pause (msg); return FALSE; } } else { if (!stack_buf) stack_buf = alloca (RESPONSE_BLOCK_SIZE); buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY, stack_buf, RESPONSE_BLOCK_SIZE); } nread = g_pollable_stream_read (io->body_istream, (guchar *)buffer->data, buffer->length, blocking, cancellable, error); if (nread > 0) { buffer->length = nread; soup_message_body_got_chunk (io->read_body, buffer); soup_message_got_chunk (msg, buffer); soup_buffer_free (buffer); break; } soup_buffer_free (buffer); if (nread == -1) return FALSE; /* else nread == 0 */ io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE; break; case SOUP_MESSAGE_IO_STATE_BODY_DONE: io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING; soup_message_got_body (msg); break; case SOUP_MESSAGE_IO_STATE_FINISHING: io->read_state = SOUP_MESSAGE_IO_STATE_DONE; if (io->mode == SOUP_MESSAGE_IO_SERVER) io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS; break; default: g_return_val_if_reached (FALSE); } return TRUE; }
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 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); } }