/** * soup_websocket_client_prepare_handshake: * @msg: a #SoupMessage * @origin: (allow-none): the "Origin" header to set * @protocols: (allow-none) (array zero-terminated=1): list of * protocols to offer * * Adds the necessary headers to @msg to request a WebSocket * handshake. The message body and non-WebSocket-related headers are * not modified. * * This is a low-level function; if you use * soup_session_websocket_connect_async() to create a WebSocket * connection, it will call this for you. * * Since: 2.50 */ void soup_websocket_client_prepare_handshake (SoupMessage *msg, const char *origin, char **protocols) { guint32 raw[4]; char *key; soup_message_headers_replace (msg->request_headers, "Upgrade", "websocket"); soup_message_headers_append (msg->request_headers, "Connection", "Upgrade"); raw[0] = g_random_int (); raw[1] = g_random_int (); raw[2] = g_random_int (); raw[3] = g_random_int (); key = g_base64_encode ((const guchar *)raw, sizeof (raw)); soup_message_headers_replace (msg->request_headers, "Sec-WebSocket-Key", key); g_free (key); soup_message_headers_replace (msg->request_headers, "Sec-WebSocket-Version", "13"); if (origin) soup_message_headers_replace (msg->request_headers, "Origin", origin); if (protocols) { char *protocols_str; protocols_str = g_strjoinv (", ", protocols); soup_message_headers_replace (msg->request_headers, "Sec-WebSocket-Protocol", protocols_str); g_free (protocols_str); } }
SnraServerClient * snra_server_client_new (SoupServer * soup, SoupMessage * msg, SoupClientContext * context) { SnraServerClient *client = g_object_new (SNRA_TYPE_SERVER_CLIENT, NULL); const gchar *accept_challenge; gchar *accept_reply; client->soup = soup; client->event_pipe = msg; client->host = g_strdup (soup_client_context_get_host (context)); client->net_event_sig = g_signal_connect (msg, "network-event", G_CALLBACK (snra_server_client_network_event), client); client->disco_sig = g_signal_connect (msg, "finished", G_CALLBACK (snra_server_client_disconnect), client); if (!is_websocket_client (client)) { client->type = SNRA_SERVER_CLIENT_CHUNKED; client->need_body_complete = TRUE; soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CHUNKED); soup_message_set_status (msg, SOUP_STATUS_OK); return client; } /* Otherwise, it's a websocket client */ client->type = SNRA_SERVER_CLIENT_WEBSOCKET; client->need_body_complete = FALSE; client->socket = soup_client_context_get_socket (context); client->in_bufptr = client->in_buf = g_new0 (gchar, 1024); client->in_bufsize = 1024; client->in_bufavail = 0; accept_challenge = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key"); accept_reply = calc_websocket_challenge_reply (accept_challenge); soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_EOF); soup_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS); soup_message_headers_replace (msg->response_headers, "Upgrade", "websocket"); soup_message_headers_replace (msg->response_headers, "Connection", "Upgrade"); soup_message_headers_replace (msg->response_headers, "Sec-WebSocket-Accept", accept_reply); soup_message_headers_replace (msg->response_headers, "Sec-WebSocket-Protocol", "aurena"); g_free (accept_reply); client->wrote_info_sig = g_signal_connect (msg, "wrote-informational", G_CALLBACK (snra_server_client_wrote_headers), client); return client; }
void gss_adaptive_get_resource (GssTransaction * t, GssAdaptive * adaptive, const char *path) { gboolean failed; g_return_if_fail (t != NULL); g_return_if_fail (adaptive != NULL); g_return_if_fail (path != NULL); soup_message_headers_replace (t->msg->response_headers, "Access-Control-Allow-Origin", "*"); soup_message_headers_replace (t->msg->response_headers, "Access-Control-Allow-Headers", "origin,range"); soup_message_headers_replace (t->msg->response_headers, "Access-Control-Expose-Headers", "Server,range"); soup_message_headers_replace (t->msg->response_headers, "Access-Control-Allow-Methods", "GET, HEAD, OPTIONS"); failed = FALSE; switch (adaptive->stream_type) { case GSS_ADAPTIVE_STREAM_ISM: if (strcmp (path, "Manifest") == 0) { gss_adaptive_resource_get_manifest (t, adaptive); } else if (strcmp (path, "content") == 0) { gss_adaptive_resource_get_content (t, adaptive); } else { failed = TRUE; } break; case GSS_ADAPTIVE_STREAM_ISOFF_LIVE: if (strcmp (path, "manifest.mpd") == 0) { gss_adaptive_resource_get_dash_live_mpd (t, adaptive); } else if (strcmp (path, "content") == 0) { gss_adaptive_resource_get_content (t, adaptive); } else { failed = TRUE; } break; case GSS_ADAPTIVE_STREAM_ISOFF_ONDEMAND: if (strcmp (path, "manifest.mpd") == 0) { gss_adaptive_resource_get_dash_range_mpd (t, adaptive); } else if (strncmp (path, "content/", 8) == 0) { gss_adaptive_resource_get_dash_range_fragment (t, adaptive, path); } else { failed = TRUE; } break; default: failed = TRUE; } if (failed) { gss_transaction_error_not_found (t, "invalid path for stream type"); } }
static void do_message_has_authorization_header_test (void) { SoupSession *session; SoupMessage *msg; SoupAuthManager *manager; SoupAuth *auth = NULL; char *token; guint auth_id; char *uri; g_test_bug ("775882"); SOUP_TEST_SKIP_IF_NO_APACHE; session = soup_test_session_new (SOUP_TYPE_SESSION, NULL); uri = g_strconcat (base_uri, "Digest/realm1/", NULL); msg = soup_message_new ("GET", uri); auth_id = g_signal_connect (session, "authenticate", G_CALLBACK (has_authorization_header_authenticate), &auth); soup_session_send_message (session, msg); soup_test_assert_message_status (msg, SOUP_STATUS_OK); soup_test_assert (SOUP_IS_AUTH (auth), "Expected a SoupAuth"); token = soup_auth_get_authorization (auth, msg); g_object_unref (auth); g_object_unref (msg); g_signal_handler_disconnect (session, auth_id); manager = SOUP_AUTH_MANAGER (soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER)); soup_auth_manager_clear_cached_credentials (manager); msg = soup_message_new ("GET", uri); soup_message_headers_replace (msg->request_headers, "Authorization", token); auth_id = g_signal_connect (session, "authenticate", G_CALLBACK (has_authorization_header_authenticate_assert), NULL); soup_session_send_message (session, msg); soup_test_assert_message_status (msg, SOUP_STATUS_OK); g_object_unref (msg); /* Check that we can also provide our own Authorization header when not using credentials cache. */ soup_auth_manager_clear_cached_credentials (manager); msg = soup_message_new ("GET", uri); soup_message_headers_replace (msg->request_headers, "Authorization", token); soup_message_set_flags (msg, soup_message_get_flags (msg) | SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE); soup_session_send_message (session, msg); soup_test_assert_message_status (msg, SOUP_STATUS_OK); g_object_unref (msg); g_free (token); g_signal_handler_disconnect (session, auth_id); g_free (uri); soup_test_session_abort_unref (session); }
static void _picasa_web_service_add_headers (PicasaWebService *self, SoupMessage *msg) { if (self->priv->access_token != NULL) { char *value; value = g_strconcat ("Bearer ", self->priv->access_token, NULL); soup_message_headers_replace (msg->request_headers, "Authorization", value); g_free (value); } soup_message_headers_replace (msg->request_headers, "GData-Version", "2"); }
/** * Callback for web pages send-request signal. */ static gboolean on_web_page_send_request(WebKitWebPage *webpage, WebKitURIRequest *request, WebKitURIResponse *response, gpointer extension) { char *name, *value; SoupMessageHeaders *headers; GHashTableIter iter; if (!ext.headers) { return FALSE; } /* Change request headers according to the users preferences. */ headers = webkit_uri_request_get_http_headers(request); if (!headers) { return FALSE; } g_hash_table_iter_init(&iter, ext.headers); while (g_hash_table_iter_next(&iter, (gpointer*)&name, (gpointer*)&value)) { /* Null value is used to indicate that the header should be * removed completely. */ if (value == NULL) { soup_message_headers_remove(headers, name); } else { soup_message_headers_replace(headers, name, value); } } return FALSE; }
/** * soup_message_headers_set_ranges: * @hdrs: a #SoupMessageHeaders * @ranges: an array of #SoupRange * @length: the length of @range * * Sets @hdrs's Range header to request the indicated ranges. (If you * only want to request a single range, you can use * soup_message_headers_set_range().) * * Since: 2.26 **/ void soup_message_headers_set_ranges (SoupMessageHeaders *hdrs, SoupRange *ranges, int length) { GString *header; int i; header = g_string_new ("bytes="); for (i = 0; i < length; i++) { if (i > 0) g_string_append_c (header, ','); if (ranges[i].end >= 0) { g_string_append_printf (header, "%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT, ranges[i].start, ranges[i].end); } else if (ranges[i].start >= 0) { g_string_append_printf (header,"%" G_GINT64_FORMAT "-", ranges[i].start); } else { g_string_append_printf (header, "%" G_GINT64_FORMAT, ranges[i].start); } } soup_message_headers_replace (hdrs, "Range", header->str); g_string_free (header, TRUE); }
/** * soup_message_headers_set_encoding: * @hdrs: a #SoupMessageHeaders * @encoding: a #SoupEncoding * * Sets the message body encoding that @hdrs will declare. In particular, * you should use this if you are going to send a request or response in * chunked encoding. **/ void soup_message_headers_set_encoding (SoupMessageHeaders *hdrs, SoupEncoding encoding) { if (encoding == hdrs->encoding) return; switch (encoding) { case SOUP_ENCODING_NONE: case SOUP_ENCODING_EOF: soup_message_headers_remove (hdrs, "Transfer-Encoding"); soup_message_headers_remove (hdrs, "Content-Length"); break; case SOUP_ENCODING_CONTENT_LENGTH: soup_message_headers_remove (hdrs, "Transfer-Encoding"); break; case SOUP_ENCODING_CHUNKED: soup_message_headers_remove (hdrs, "Content-Length"); soup_message_headers_replace (hdrs, "Transfer-Encoding", "chunked"); break; default: g_return_if_reached (); } hdrs->encoding = encoding; }
/** * soup_message_headers_set_expectations: * @hdrs: a #SoupMessageHeaders * @expectations: the expectations to set * * Sets @hdrs's "Expect" header according to @expectations. * * Currently %SOUP_EXPECTATION_CONTINUE is the only known expectation * value. You should set this value on a request if you are sending a * large message body (eg, via POST or PUT), and want to give the * server a chance to reject the request after seeing just the headers * (eg, because it will require authentication before allowing you to * post, or because you're POSTing to a URL that doesn't exist). This * saves you from having to transmit the large request body when the * server is just going to ignore it anyway. **/ void soup_message_headers_set_expectations (SoupMessageHeaders *hdrs, SoupExpectation expectations) { g_return_if_fail ((expectations & ~SOUP_EXPECTATION_CONTINUE) == 0); if (expectations & SOUP_EXPECTATION_CONTINUE) soup_message_headers_replace (hdrs, "Expect", "100-continue"); else soup_message_headers_remove (hdrs, "Expect"); }
/** * soup_message_headers_set_content_length: * @hdrs: a #SoupMessageHeaders * @content_length: the message body length * * Sets the message body length that @hdrs will declare, and sets * @hdrs's encoding to %SOUP_ENCODING_CONTENT_LENGTH. * * You do not normally need to call this; if @hdrs is set to use * Content-Length encoding, libsoup will automatically set its * Content-Length header for you immediately before sending the * headers. One situation in which this method is useful is when * generating the response to a HEAD request; Calling * soup_message_headers_set_content_length() allows you to put the * correct content length into the response without needing to waste * memory by filling in a response body which won't actually be sent. **/ void soup_message_headers_set_content_length (SoupMessageHeaders *hdrs, goffset content_length) { char length[128]; snprintf (length, sizeof (length), "%" G_GUINT64_FORMAT, content_length); soup_message_headers_remove (hdrs, "Transfer-Encoding"); soup_message_headers_replace (hdrs, "Content-Length", length); }
void serverHandleJournal(SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data) { bool ok = false; if(strcmp(path, "/journal/journal.html") == 0) { GDBusProxy *journal = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.laptop.sugar.DataStore", "/org/laptop/sugar/DataStore", "org.laptop.sugar.DataStore", NULL, NULL); GVariant *params = g_variant_new("(a{sv}as)", NULL, NULL); GError *error = NULL; GVariant *result = g_dbus_proxy_call_sync( journal, "find", params, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if(error != NULL) {fprintf(stderr, "error: %d, %d, %s\n", error->domain, error->code, error->message);} if(result != NULL) { soup_message_headers_replace(msg->response_headers, "Content-Type", "text/html"); append(msg, "<html><body>"); GVariant *results = NULL; guint32 count = -1; g_variant_get(result, "(@aa{sv}u)", &results, &count); GVariant *dictionary = NULL; GVariantIter results_iter; g_variant_iter_init(&results_iter, results); while (g_variant_iter_loop(&results_iter, "@a{sv}", &dictionary)) { append(msg, "<p><a href='"); append(msg, lookup(dictionary, "uid", "invalid object id")); append(msg, "'>"); append(msg, lookup(dictionary, "title", "invalid title")); append(msg, "</a></p>"); } append(msg, "</body></html>"); soup_message_set_status(msg, 200); fprintf(stderr, "GET: %s\n", path); ok = true; } } if(!ok) { soup_message_set_status(msg, 404); fprintf(stderr, "ERROR: %s\n", path); } }
static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { if (g_str_equal (path, "/index.html")) { soup_message_headers_replace (msg->response_headers, "Set-Cookie", "foo=bar"); } else if (g_str_equal (path, "/foo.jpg")) { soup_message_headers_replace (msg->response_headers, "Set-Cookie", "baz=qux"); } else if (soup_message_headers_get_one (msg->request_headers, "Echo-Set-Cookie")) { soup_message_headers_replace (msg->response_headers, "Set-Cookie", soup_message_headers_get_one (msg->request_headers, "Echo-Set-Cookie")); } soup_message_set_status (msg, SOUP_STATUS_OK); }
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); }
void video_server (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data) { const gchar *contents = "dummy_video_content"; gsize length = strlen (contents); gchar *mime_type = NULL; if (!g_strcmp0 (path, "/video/dummy_mp4")) mime_type = "video/mp4"; else if (!g_strcmp0 (path, "/video/dummy_mov")) mime_type = "video/mov"; if (mime_type) { soup_message_set_status (msg, SOUP_STATUS_OK); if (g_strcmp0 (msg->method, "HEAD")) soup_message_set_response (msg, mime_type, SOUP_MEMORY_COPY, contents, length); return; } if (!g_strcmp0 (path, "/video/youtube")) { gchar *page_contents; gsize length; if (!g_file_get_contents (BASEFILEPATH "/watch?v=SiYurfwzyuY", &page_contents, &length, NULL)) { g_error ("Couldn't serve video file"); } soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_set_response (msg, "text/html", SOUP_MEMORY_COPY, page_contents, length); return; } if (!g_strcmp0 (path, "/video/file_with_slash")) { gchar *page_contents = "dummy"; gsize length = g_utf8_strlen ("dummy", -1); soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_set_response (msg, "video/none", SOUP_MEMORY_COPY, page_contents, length); soup_message_headers_replace (msg->response_headers, "Content-Disposition", "attachment; filename=\"dir/file.vid\";"); return; } soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); }
/** * soup_message_headers_set_content_range: * @hdrs: a #SoupMessageHeaders * @start: the start of the range * @end: the end of the range * @total_length: the total length of the resource, or -1 if unknown * * Sets @hdrs's Content-Range header according to the given values. * (Note that @total_length is the total length of the entire resource * that this is a range of, not simply @end - @start + 1.) * * Since: 2.26 **/ void soup_message_headers_set_content_range (SoupMessageHeaders *hdrs, goffset start, goffset end, goffset total_length) { char *header; if (total_length >= 0) { header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, start, end, total_length); } else { header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "/*", start, end); } soup_message_headers_replace (hdrs, "Content-Range", header); g_free (header); }
static void set_content_foo (SoupMessageHeaders *hdrs, const char *header_name, const char *foo, GHashTable *params) { GString *str; GHashTableIter iter; gpointer key, value; str = g_string_new (foo); if (params) { g_hash_table_iter_init (&iter, params); while (g_hash_table_iter_next (&iter, &key, &value)) { g_string_append (str, "; "); soup_header_g_string_append_param (str, key, value); } } soup_message_headers_replace (hdrs, header_name, str->str); g_string_free (str, TRUE); }
/* Host header handling: client must be able to override the default * value, server must be able to recognize different Host values. * #539803. */ static void do_host_test (void) { SoupSession *session; SoupMessage *one, *two; debug_printf (1, "Host handling\n"); session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL); one = soup_message_new_from_uri ("GET", base_uri); two = soup_message_new_from_uri ("GET", base_uri); soup_message_headers_replace (two->request_headers, "Host", "foo"); soup_session_send_message (session, one); soup_session_send_message (session, two); soup_test_session_abort_unref (session); if (!SOUP_STATUS_IS_SUCCESSFUL (one->status_code)) { debug_printf (1, " Message 1 failed: %d %s\n", one->status_code, one->reason_phrase); errors++; } else if (strcmp (one->response_body->data, "index") != 0) { debug_printf (1, " Unexpected response to message 1: '%s'\n", one->response_body->data); errors++; } g_object_unref (one); if (!SOUP_STATUS_IS_SUCCESSFUL (two->status_code)) { debug_printf (1, " Message 2 failed: %d %s\n", two->status_code, two->reason_phrase); errors++; } else if (strcmp (two->response_body->data, "foo-index") != 0) { debug_printf (1, " Unexpected response to message 2: '%s'\n", two->response_body->data); errors++; } g_object_unref (two); }
static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { SoupMessageBody *md5_body; char *md5; if (g_str_has_prefix (path, "/redirect")) { soup_message_set_status (msg, SOUP_STATUS_FOUND); soup_message_headers_replace (msg->response_headers, "Location", "/"); return; } if (msg->method == SOUP_METHOD_GET) { soup_message_set_response (msg, "text/plain", SOUP_MEMORY_STATIC, "three\r\ntwo\r\none\r\n", strlen ("three\r\ntwo\r\none\r\n")); soup_buffer_free (soup_message_body_flatten (msg->response_body)); md5_body = msg->response_body; soup_message_set_status (msg, SOUP_STATUS_OK); } else if (msg->method == SOUP_METHOD_PUT) { soup_message_set_status (msg, SOUP_STATUS_CREATED); md5_body = msg->request_body; } else { soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED); return; } md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5, (guchar *)md5_body->data, md5_body->length); soup_message_headers_append (msg->response_headers, "Content-MD5", md5); g_free (md5); }
void soup_session_send_queue_item (SoupSession *session, SoupMessageQueueItem *item, SoupConnection *conn) { SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); if (item->conn) { if (item->conn != conn) { g_object_unref (item->conn); item->conn = g_object_ref (conn); } } else item->conn = g_object_ref (conn); if (priv->user_agent) { soup_message_headers_replace (item->msg->request_headers, "User-Agent", priv->user_agent); } g_signal_emit (session, signals[REQUEST_STARTED], 0, item->msg, soup_connection_get_socket (conn)); soup_connection_send_request (conn, item->msg); }
/** * soup_websocket_server_process_handshake: * @msg: #SoupMessage containing the client side of a WebSocket handshake * @expected_origin: (allow-none): expected Origin header * @protocols: (allow-none) (array zero-terminated=1): allowed WebSocket * protocols. * * Examines the method and request headers in @msg and (assuming @msg * contains a valid handshake request), fills in the handshake * response. * * If @expected_origin is non-%NULL, then only requests containing a matching * "Origin" header will be accepted. If @protocols is non-%NULL, then * only requests containing a compatible "Sec-WebSocket-Protocols" * header will be accepted. * * This is a low-level function; if you use * soup_server_add_websocket_handler() to handle accepting WebSocket * connections, it will call this for you. * * Returns: %TRUE if @msg contained a valid WebSocket handshake * request and was updated to contain a handshake response. %FALSE if not. * * Since: 2.50 */ gboolean soup_websocket_server_process_handshake (SoupMessage *msg, const char *expected_origin, char **protocols) { const char *chosen_protocol = NULL; const char *key; char *accept_key; GError *error = NULL; if (!soup_websocket_server_check_handshake (msg, expected_origin, protocols, &error)) { if (g_error_matches (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_ORIGIN)) respond_handshake_forbidden (msg); else respond_handshake_bad (msg, error->message); g_error_free (error); return FALSE; } soup_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS); soup_message_headers_replace (msg->response_headers, "Upgrade", "websocket"); soup_message_headers_append (msg->response_headers, "Connection", "Upgrade"); key = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key"); accept_key = compute_accept_key (key); soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Accept", accept_key); g_free (accept_key); choose_subprotocol (msg, (const char **) protocols, &chosen_protocol); if (chosen_protocol) soup_message_headers_append (msg->response_headers, "Sec-WebSocket-Protocol", chosen_protocol); return TRUE; }
static void request_started(SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg, SoupSocket *socket) { (void) session; (void) socket; SoupCookieJar *sj = SOUP_COOKIE_JAR(feature); SoupURI *uri = soup_message_get_uri(msg); lua_State *L = globalconf.L; /* give user a chance to add cookies from other instances into the jar */ gchar *str = soup_uri_to_string(uri, FALSE); lua_pushstring(L, str); g_free(str); signal_object_emit(L, soupconf.signals, "request-started", 1, 0); /* generate cookie header */ gchar *header = soup_cookie_jar_get_cookies(sj, uri, TRUE); if (header) { soup_message_headers_replace(msg->request_headers, "Cookie", header); g_free(header); } else soup_message_headers_remove(msg->request_headers, "Cookie"); }
static void gss_adaptive_resource_get_dash_live_mpd (GssTransaction * t, GssAdaptive * adaptive) { GString *s = g_string_new (""); int i; ManifestQuery mq; parse_manifest_query (&mq, t); t->s = s; soup_message_headers_replace (t->msg->response_headers, "Content-Type", "application/octet-stream"); GSS_P ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); GSS_A ("<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"); if (adaptive->drm_type == GSS_DRM_PLAYREADY) { GSS_A (" xmlns:mspr=\"urn:microsoft:playready\"\n"); } GSS_P (" xsi:schemaLocation=\"urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd\"\n" " type=\"static\"\n" " mediaPresentationDuration=\"PT%dS\"\n" " minBufferTime=\"PT10S\"\n" " profiles=\"urn:mpeg:dash:profile:isoff-live:2011\">\n", (int) (adaptive->duration / GSS_ISM_SECOND)); GSS_P (" <Period>\n"); GSS_A (" <AdaptationSet " "id=\"1\" " "profiles=\"ccff\" " "bitstreamSwitching=\"true\" " "segmentAlignment=\"true\" " "contentType=\"audio\" " "mimeType=\"audio/mp4\" " "lang=\"en\">\n"); append_content_protection (t, adaptive, mq.auth_token); GSS_A (" <SegmentTemplate timescale=\"10000000\" " "media=\"content?stream=audio&bitrate=$Bandwidth$&start_time=$Time$\" " "initialization=\"content?stream=audio&bitrate=$Bandwidth$&start_time=init\">\n"); GSS_A (" <SegmentTimeline>\n"); { GssAdaptiveLevel *level = &adaptive->audio_levels[0]; for (i = 0; i < level->n_fragments; i++) { GssIsomFragment *fragment; fragment = gss_isom_track_get_fragment (level->track, i); GSS_P (" <S d=\"%" G_GUINT64_FORMAT "\" />\n", (guint64) fragment->duration); } } GSS_A (" </SegmentTimeline>\n"); GSS_A (" </SegmentTemplate>\n"); for (i = 0; i < adaptive->n_audio_levels; i++) { GssAdaptiveLevel *level = &adaptive->audio_levels[i]; GSS_P (" <Representation id=\"a%d\" codecs=\"%s\" " "bandwidth=\"%d\" audioSamplingRate=\"%d\"/>\n", i, level->codec, level->bitrate, level->audio_rate); } GSS_A (" </AdaptationSet>\n"); GSS_P (" <AdaptationSet " "id=\"2\" " "profiles=\"ccff\" " "bitstreamSwitching=\"true\" " "segmentAlignment=\"true\" " "contentType=\"video\" " "mimeType=\"video/mp4\" " "maxWidth=\"1920\" " "maxHeight=\"1080\" " "startWithSAP=\"1\">\n"); append_content_protection (t, adaptive, mq.auth_token); GSS_A (" <SegmentTemplate timescale=\"10000000\" " "media=\"content?stream=video&bitrate=$Bandwidth$&start_time=$Time$\" " "initialization=\"content?stream=video&bitrate=$Bandwidth$&start_time=init\">\n"); GSS_A (" <SegmentTimeline>\n"); { GssAdaptiveLevel *level = &adaptive->video_levels[0]; for (i = 0; i < level->n_fragments; i++) { GssIsomFragment *fragment; fragment = gss_isom_track_get_fragment (level->track, i); GSS_P (" <S d=\"%" G_GUINT64_FORMAT "\" />\n", (guint64) fragment->duration); } } GSS_A (" </SegmentTimeline>\n"); GSS_A (" </SegmentTemplate>\n"); for (i = 0; i < adaptive->n_video_levels; i++) { GssAdaptiveLevel *level = &adaptive->video_levels[i]; if (manifest_query_check_video (&mq, level)) { GSS_P (" <Representation id=\"v%d\" bandwidth=\"%d\" " "codecs=\"%s\" width=\"%d\" height=\"%d\"/>\n", i, level->bitrate, level->codec, level->video_width, level->video_height); } } GSS_A (" </AdaptationSet>\n"); GSS_A (" </Period>\n"); GSS_A ("</MPD>\n"); GSS_A ("\n"); }
static void got_headers (SoupMessage *req, SoupClientContext *client) { SoupServer *server = client->server; SoupServerPrivate *priv = SOUP_SERVER_GET_PRIVATE (server); SoupURI *uri; SoupDate *date; char *date_string; SoupAuthDomain *domain; GSList *iter; gboolean rejected = FALSE; char *auth_user; if (!priv->raw_paths) { char *decoded_path; uri = soup_message_get_uri (req); decoded_path = soup_uri_decode (uri->path); soup_uri_set_path (uri, decoded_path); g_free (decoded_path); } /* Add required response headers */ date = soup_date_new_from_now (0); date_string = soup_date_to_string (date, SOUP_DATE_HTTP); soup_message_headers_replace (req->response_headers, "Date", date_string); g_free (date_string); soup_date_free (date); /* Now handle authentication. (We do this here so that if * the request uses "Expect: 100-continue", we can reject it * immediately rather than waiting for the request body to * be sent. */ for (iter = priv->auth_domains; iter; iter = iter->next) { domain = iter->data; if (soup_auth_domain_covers (domain, req)) { auth_user = soup_auth_domain_accepts (domain, req); if (auth_user) { client->auth_domain = g_object_ref (domain); client->auth_user = auth_user; return; } rejected = TRUE; } } /* If no auth domain rejected it, then it's ok. */ if (!rejected) return; for (iter = priv->auth_domains; iter; iter = iter->next) { domain = iter->data; if (soup_auth_domain_covers (domain, req)) soup_auth_domain_challenge (domain, req); } }
/** * youtube_proxy_upload_async: * @self: a #YoutubeProxy * @filename: filename * @fields: fields * @incomplete: incomplete * @callback: (scope async): callback to invoke upon completion * @weak_object: an object instance used to tie the life cycle of the proxy to * @user_data: user data to pass to the callback * @error: a #GError pointer, or %NULL * * Upload a file. * * Returns: %TRUE, or %FALSE if the file could not be opened */ gboolean youtube_proxy_upload_async (YoutubeProxy *self, const gchar *filename, GHashTable *fields, gboolean incomplete, YoutubeProxyUploadCallback callback, GObject *weak_object, gpointer user_data, GError **error) { SoupMultipart *mp; SoupMessage *message; SoupMessageHeaders *part_headers; SoupBuffer *sb; gchar *content_type; gchar *atom_xml; GMappedFile *map; YoutubeProxyUploadClosure *closure; map = g_mapped_file_new (filename, FALSE, error); if (*error != NULL) { g_warning ("Error opening file %s: %s", filename, (*error)->message); return FALSE; } mp = soup_multipart_new ("multipart/related"); atom_xml = _construct_upload_atom_xml (fields, incomplete); sb = soup_buffer_new_with_owner (atom_xml, strlen(atom_xml), atom_xml, (GDestroyNotify) g_free); part_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART); soup_message_headers_append (part_headers, "Content-Type", "application/atom+xml; charset=UTF-8"); soup_multipart_append_part (mp, part_headers, sb); soup_buffer_free (sb); content_type = g_content_type_guess ( filename, (const guchar*) g_mapped_file_get_contents (map), g_mapped_file_get_length (map), NULL); sb = soup_buffer_new_with_owner (g_mapped_file_get_contents (map), g_mapped_file_get_length (map), map, (GDestroyNotify) g_mapped_file_unref); soup_message_headers_replace (part_headers, "Content-Type", content_type); soup_multipart_append_part (mp, part_headers, sb); soup_buffer_free (sb); soup_message_headers_free (part_headers); message = soup_form_request_new_from_multipart (UPLOAD_URL, mp); soup_multipart_free (mp); _set_upload_headers (self, message->request_headers, filename); closure = _upload_async_closure_new (self, callback, message, weak_object, user_data); g_signal_connect (message, "wrote-body-data", (GCallback) _message_wrote_data_cb, closure); _rest_proxy_queue_message (REST_PROXY (self), message, _upload_completed_cb, closure); return TRUE; }
static void gss_server_resource_callback (SoupServer * soupserver, SoupMessage * msg, const char *path, GHashTable * query, SoupClientContext * client, gpointer user_data) { GssServer *server = (GssServer *) user_data; GssTransaction *t; GssSession *session; t = gss_transaction_new (server, soupserver, msg, path, query, client); t->resource = gss_server_lookup_resource (server, path); if (!t->resource) { gss_transaction_error_not_found (t, "resource not found"); return; } if (t->resource->flags & GSS_RESOURCE_UI) { if (!server->enable_public_interface && soupserver == server->server) { gss_transaction_error_not_found (t, "public interface disabled"); return; } } if (t->resource->flags & GSS_RESOURCE_HTTPS_ONLY) { if (soupserver != server->ssl_server) { gss_transaction_error_not_found (t, "resource https only"); return; } } session = gss_session_get_session (query); if (session && soupserver != server->ssl_server) { gss_session_invalidate (session); session = NULL; } if (t->resource->flags & GSS_RESOURCE_USER) { if (session == NULL) { gss_transaction_error_not_found (t, "resource requires login"); return; } } t->session = session; if (t->resource->flags & GSS_RESOURCE_ADMIN) { if (session == NULL || !session->is_admin || !gss_addr_range_list_check_address (server->admin_arl, soup_client_context_get_address (client))) { gss_html_error_401 (server, msg); return; } } if (t->resource->content_type) { soup_message_headers_replace (msg->response_headers, "Content-Type", t->resource->content_type); } if (t->resource->etag) { const char *inm; soup_message_headers_append (msg->response_headers, "Cache-Control", "max-age=86400"); inm = soup_message_headers_get_one (msg->request_headers, "If-None-Match"); if (inm && !strcmp (inm, t->resource->etag)) { soup_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED); return; } } else { soup_message_headers_append (msg->response_headers, "Cache-Control", "must-revalidate"); } if (t->resource->flags & GSS_RESOURCE_HTTP_ONLY) { if (soupserver != server->server) { gss_resource_onetime_redirect (t); return; } } soup_message_set_status (msg, SOUP_STATUS_OK); if ((msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD) && t->resource->get_callback) { t->resource->get_callback (t); } else if (msg->method == SOUP_METHOD_PUT && t->resource->put_callback) { t->resource->put_callback (t); } else if (msg->method == SOUP_METHOD_POST && t->resource->post_callback) { t->resource->post_callback (t); } else if (msg->method == SOUP_METHOD_SOURCE && t->resource->put_callback) { t->resource->put_callback (t); } else if (msg->method == SOUP_METHOD_OPTIONS) { soup_message_headers_replace (msg->response_headers, "Access-Control-Allow-Origin", "*"); soup_message_headers_replace (msg->response_headers, "Access-Control-Allow-Headers", "origin,range,content-type"); soup_message_headers_replace (msg->response_headers, "Access-Control-Expose-Headers", "Server,range"); soup_message_headers_replace (msg->response_headers, "Access-Control-Allow-Methods", "GET, HEAD, OPTIONS"); } else { gss_html_error_405 (server, msg); } if (t->s) { int len; gchar *content; len = t->s->len; content = g_string_free (t->s, FALSE); soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE, content, len); } }
/* TODO: use .part extentions and continue even when using GRITS_ONCE */ gchar *grits_http_fetch(GritsHttp *http, const gchar *uri, const char *local, GritsCacheType mode, GritsChunkCallback callback, gpointer user_data) { g_debug("GritsHttp: fetch - %s mode=%d", local, mode); gchar *path = _get_cache_path(http, local); /* Unlink the file if we're refreshing it */ if (mode == GRITS_REFRESH) g_remove(path); /* Do the cache if necessasairy */ if (!(mode == GRITS_ONCE && g_file_test(path, G_FILE_TEST_EXISTS)) && mode != GRITS_LOCAL) { g_debug("GritsHttp: fetch - Caching file %s", local); /* Open the file for writting */ gchar *part = path; if (!g_file_test(path, G_FILE_TEST_EXISTS)) part = g_strdup_printf("%s.part", path); FILE *fp = fopen_p(part, "ab"); if (!fp) { g_warning("GritsHttp: fetch - error opening %s", path); return NULL; } fseek(fp, 0, SEEK_END); // "a" is broken on Windows, twice /* Make temp data */ struct _CacheInfo info = { .fp = fp, .path = path, .callback = callback, .user_data = user_data, }; /* Download the file */ SoupMessage *message = soup_message_new("GET", uri); if (message == NULL) g_error("message is null, cannot parse uri"); g_signal_connect(message, "got-chunk", G_CALLBACK(_chunk_cb), &info); //if (ftell(fp) > 0) soup_message_headers_set_range(message->request_headers, ftell(fp), -1); if (mode == GRITS_REFRESH) soup_message_headers_replace(message->request_headers, "Cache-Control", "max-age=0"); soup_session_send_message(http->soup, message); /* Close file */ fclose(fp); if (path != part) { if (SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) g_rename(part, path); g_free(part); } /* Finished */ guint status = message->status_code; g_object_unref(message); if (status == SOUP_STATUS_CANCELLED) { return NULL; } else if (status == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE) { /* Range unsatisfiable, file already complete */ } else if (!SOUP_STATUS_IS_SUCCESSFUL(status)) { g_warning("GritsHttp: done_cb - error copying file, status=%d\n" "\tsrc=%s\n" "\tdst=%s", status, uri, path); return NULL; } }
static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { const char *accept_encoding, *options; GSList *codings; char *file = NULL, *contents; gsize length; options = soup_message_headers_get_one (msg->request_headers, "X-Test-Options"); if (!options) options = ""; accept_encoding = soup_message_headers_get_list (msg->request_headers, "Accept-Encoding"); if (accept_encoding && !soup_header_contains (options, "force-encode")) codings = soup_header_parse_quality_list (accept_encoding, NULL); else codings = NULL; if (codings) { gboolean claim_deflate, claim_gzip; const char *file_path = NULL, *encoding = NULL; claim_deflate = g_slist_find_custom (codings, "deflate", (GCompareFunc)g_ascii_strcasecmp) != NULL; claim_gzip = g_slist_find_custom (codings, "gzip", (GCompareFunc)g_ascii_strcasecmp) != NULL; if (claim_gzip && (!claim_deflate || (!soup_header_contains (options, "prefer-deflate-zlib") && !soup_header_contains (options, "prefer-deflate-raw")))) { file_path = SRCDIR "/resources%s.gz"; encoding = "gzip"; } else if (claim_deflate) { if (soup_header_contains (options, "prefer-deflate-raw")) { file_path = SRCDIR "/resources%s.raw"; encoding = "deflate"; } else { file_path = SRCDIR "/resources%s.zlib"; encoding = "deflate"; } } if (file_path && encoding) { file = g_strdup_printf (file_path, path); if (g_file_test (file, G_FILE_TEST_EXISTS)) { soup_message_headers_append (msg->response_headers, "Content-Encoding", encoding); } else { g_free (file); file = NULL; } } } soup_header_free_list (codings); if (!file) file = g_strdup_printf (SRCDIR "/resources%s", path); if (!g_file_get_contents (file, &contents, &length, NULL)) { /* If path.gz exists but can't be read, we'll send back * the error with "Content-Encoding: gzip" but there's * no body, so, eh. */ g_free (file); soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); return; } g_free (file); if (soup_header_contains (options, "force-encode")) { const gchar *encoding = "gzip"; if (soup_header_contains (options, "prefer-deflate-zlib") || soup_header_contains (options, "prefer-deflate-raw")) encoding = "deflate"; soup_message_headers_replace (msg->response_headers, "Content-Encoding", encoding); } /* Content-Type matches the "real" format, not the sent format */ if (g_str_has_suffix (path, ".gz")) { soup_message_headers_append (msg->response_headers, "Content-Type", "application/gzip"); } else { soup_message_headers_append (msg->response_headers, "Content-Type", "text/plain"); } soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CHUNKED); if (!soup_header_contains (options, "empty")) { soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE, contents, length); } else g_free (contents); if (soup_header_contains (options, "trailing-junk")) { soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, options, strlen (options)); } soup_message_body_complete (msg->response_body); }
static void gss_adaptive_resource_get_content (GssTransaction * t, GssAdaptive * adaptive) { const char *stream; const char *start_time_str; const char *bitrate_str; guint64 start_time; guint64 bitrate; gboolean is_init; GssAdaptiveLevel *level; GssIsomFragment *fragment; gboolean ret; //GST_ERROR ("content request"); if (t->query == NULL) { gss_transaction_error_not_found (t, "no smooth streaming query"); return; } stream = g_hash_table_lookup (t->query, "stream"); if (stream == NULL) { gss_transaction_error_not_found (t, "missing stream parameterr"); return; } start_time_str = g_hash_table_lookup (t->query, "start_time"); if (start_time_str == NULL) { gss_transaction_error_not_found (t, "missing start_time parameter"); return; } bitrate_str = g_hash_table_lookup (t->query, "bitrate"); if (bitrate_str == NULL) { gss_transaction_error_not_found (t, "missing bitrate parameter"); return; } ret = parse_guint64 (bitrate_str, &bitrate); if (!ret) { gss_transaction_error_not_found (t, "bitrate is not a number"); return; } if (strcmp (start_time_str, "init") == 0) { is_init = TRUE; start_time = 0; } else { is_init = FALSE; ret = parse_guint64 (start_time_str, &start_time); if (!ret) { gss_transaction_error_not_found (t, "start_time is not a number or \"init\""); return; } } if (strcmp (stream, "audio") != 0 && strcmp (stream, "video") != 0) { gss_transaction_error_not_found (t, "stream is not \"audio\" or \"video\""); return; } level = gss_adaptive_get_level (adaptive, (stream[0] == 'v'), bitrate); if (level == NULL) { gss_transaction_error_not_found (t, "level not found for stream and bitrate"); return; } soup_message_headers_replace (t->msg->response_headers, "Content-Type", (stream[0] == 'v') ? "video/mp4" : "audio/mp4"); if (is_init) { soup_message_body_append (t->msg->response_body, SOUP_MEMORY_COPY, level->track->ccff_header_data, level->track->ccff_header_size); } else { GssAdaptiveQuery *query; fragment = gss_isom_track_get_fragment_by_timestamp (level->track, start_time); if (fragment == NULL) { gss_transaction_error_not_found (t, "fragment not found for start_time"); return; } //GST_ERROR ("frag %s %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, // level->filename, fragment->offset, fragment->size); soup_server_pause_message (t->soupserver, t->msg); query = g_malloc0 (sizeof (GssAdaptiveQuery)); query->adaptive = adaptive; query->level = level; query->fragment = fragment; gss_transaction_process_async (t, gss_adaptive_async_assemble_chunk, gss_adaptive_async_assemble_chunk_finish, query); } }
static void gss_adaptive_resource_get_dash_range_fragment (GssTransaction * t, GssAdaptive * adaptive, const char *path) { gboolean have_range; SoupRange *ranges; int n_ranges; int index; GssAdaptiveLevel *level; gsize start, end; /* skip over content/ */ path += 8; if (path[0] != 'a' && path[0] != 'v') { GST_ERROR ("bad path: %s", path); return; } index = strtoul (path + 1, NULL, 10); level = NULL; if (path[0] == 'a') { if (index < adaptive->n_audio_levels) { level = &adaptive->audio_levels[index]; } } else { if (index < adaptive->n_video_levels) { level = &adaptive->video_levels[index]; } } if (level == NULL) { GST_ERROR ("bad level: %c%d from path %s", path[0], index, path); return; } if (t->msg->method == SOUP_METHOD_HEAD) { GST_DEBUG ("%s: HEAD", path); soup_message_headers_set_content_length (t->msg->response_headers, level->track->dash_size); return; } have_range = soup_message_headers_get_ranges (t->msg->request_headers, level->track->dash_size, &ranges, &n_ranges); if (have_range) { if (n_ranges != 1) { GST_ERROR ("too many ranges"); } start = ranges[0].start; end = ranges[0].end + 1; } else { start = 0; end = level->track->dash_size; } GST_DEBUG ("%s: range: %ld-%ld", path, start, end); t->start = start; t->end = end; if (have_range) { soup_message_headers_set_content_range (t->msg->response_headers, ranges[0].start, ranges[0].end, level->track->dash_size); soup_message_set_status (t->msg, SOUP_STATUS_PARTIAL_CONTENT); soup_message_headers_free_ranges (t->msg->response_headers, ranges); } else { soup_message_set_status (t->msg, SOUP_STATUS_OK); } soup_message_headers_replace (t->msg->response_headers, "Content-Type", (path[0] == 'v') ? "video/mp4" : "audio/mp4"); { GssAdaptiveQuery *query; soup_server_pause_message (t->soupserver, t->msg); query = g_malloc0 (sizeof (GssAdaptiveQuery)); query->adaptive = adaptive; query->level = level; gss_transaction_process_async (t, gss_adaptive_dash_range_async, gss_adaptive_dash_range_async_finish, query); } }
static void gss_adaptive_resource_get_dash_range_mpd (GssTransaction * t, GssAdaptive * adaptive) { GString *s = g_string_new (""); int i; ManifestQuery mq; parse_manifest_query (&mq, t); t->s = s; soup_message_headers_replace (t->msg->response_headers, "Content-Type", "application/octet-stream"); GSS_A ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); GSS_A ("<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" " xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"); if (adaptive->drm_type == GSS_DRM_PLAYREADY) { GSS_A (" xmlns:mspr=\"urn:microsoft:playready\"\n"); } GSS_P (" xsi:schemaLocation=\"urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd\"\n" " type=\"static\"\n" " mediaPresentationDuration=\"PT%dS\"\n" " minBufferTime=\"PT10S\"\n" " profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\">\n", (int) (adaptive->duration / GSS_ISM_SECOND)); GSS_P (" <Period>\n"); GSS_A (" <AdaptationSet mimeType=\"audio/mp4\" " "lang=\"en\" " "segmentAlignment=\"true\" " "subsegmentAlignment=\"true\" " "subsegmentStartsWithSAP=\"1\">\n"); append_content_protection (t, adaptive, mq.auth_token); for (i = 0; i < adaptive->n_audio_levels; i++) { GssAdaptiveLevel *level = &adaptive->audio_levels[i]; GssIsomTrack *track = level->track; GSS_P (" <Representation id=\"a%d\" codecs=\"%s\" bandwidth=\"%d\">\n", i, level->codec, level->bitrate); GSS_P (" <BaseURL>content/a%d</BaseURL>\n", i); GSS_P (" <SegmentBase indexRange=\"%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT "\">" "<Initialization range=\"%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT "\" /></SegmentBase>\n", track->dash_header_size, track->dash_header_and_sidx_size - 1, (gsize) 0, track->dash_header_size - 1); GSS_A (" </Representation>\n"); break; } GSS_A (" </AdaptationSet>\n"); GSS_A (" <AdaptationSet mimeType=\"video/mp4\" " "segmentAlignment=\"true\" " "subsegmentAlignment=\"true\" " "subsegmentStartsWithSAP=\"1\">\n"); append_content_protection (t, adaptive, mq.auth_token); for (i = 0; i < adaptive->n_video_levels; i++) { GssAdaptiveLevel *level = &adaptive->video_levels[i]; GssIsomTrack *track = level->track; if (manifest_query_check_video (&mq, level)) { GSS_P (" <Representation id=\"v%d\" bandwidth=\"%d\" " "codecs=\"%s\" width=\"%d\" height=\"%d\">\n", i, level->bitrate, level->codec, level->video_width, level->video_height); GSS_P (" <BaseURL>content/v%d</BaseURL>\n", i); GSS_P (" <SegmentBase indexRange=\"%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT "\">" "<Initialization range=\"%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT "\" /></SegmentBase>\n", track->dash_header_size, track->dash_header_and_sidx_size - 1, (gsize) 0, track->dash_header_size - 1); GSS_A (" </Representation>\n"); } } GSS_A (" </AdaptationSet>\n"); GSS_A (" </Period>\n"); GSS_A ("</MPD>\n"); GSS_A ("\n"); }