/** * Change scheme and port of soup messages uri if the host is a known and * valid hsts host. * * This logic should be implemented in request_queued function but the changes * that are done there to the uri do not appear in webkit_web_view_get_uri(). * If a valid hsts host is requested via http and the url is changed to https * vimb would still show the http uri in url bar. This seems to be a * missbehaviour in webkit, but for now we provide this function to put in the * logic in the scope of the navigation-policy-decision-requested event of the * webview. * * Returns newly allocated string with new URI if the URI was change to * fullfill HSTS, else NULL. */ char *hsts_get_changed_uri(SoupSession* session, SoupMessage *msg) { SoupSessionFeature *feature; HSTSProvider *provider; SoupURI *uri; if (!msg) { return NULL; } feature = soup_session_get_feature_for_message(session, HSTS_TYPE_PROVIDER, msg); uri = soup_message_get_uri(msg); if (!feature || !uri) { return NULL; } provider = HSTS_PROVIDER(feature); /* if URI uses still https we don't nee to rewrite it */ if (uri->scheme != SOUP_URI_SCHEME_HTTPS && should_secure_host(provider, uri->host) ) { /* the ports is set by soup uri if scheme is changed */ soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS); return soup_uri_to_string(uri, false); } return NULL; }
static void run_queue (SoupSessionAsync *sa) { SoupSession *session = SOUP_SESSION (sa); SoupMessageQueue *queue = soup_session_get_queue (session); SoupMessageQueueItem *item; SoupProxyURIResolver *proxy_resolver; SoupMessage *msg; SoupConnection *conn; gboolean try_pruning = TRUE, should_prune = FALSE; soup_session_cleanup_connections (session, FALSE); try_again: for (item = soup_message_queue_first (queue); item && !should_prune; item = soup_message_queue_next (queue, item)) { msg = item->msg; /* CONNECT messages are handled specially */ if (msg->method == SOUP_METHOD_CONNECT) continue; if (soup_message_io_in_progress (msg)) continue; if (!item->resolved_proxy_addr) { proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, msg); if (proxy_resolver) { resolve_proxy_addr (item, proxy_resolver); continue; } else item->resolved_proxy_addr = TRUE; } conn = soup_session_get_connection (session, item, &should_prune); if (!conn) continue; if (soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) { soup_connection_connect_async (conn, got_connection, session); } else soup_session_send_queue_item (session, item, conn); } if (item) soup_message_queue_item_unref (item); if (try_pruning && should_prune) { /* There is at least one message in the queue that * could be sent if we pruned an idle connection from * some other server. */ if (soup_session_cleanup_connections (session, TRUE)) { try_pruning = should_prune = FALSE; goto try_again; } } }
static void conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_data) { ConditionalHelper *helper = (ConditionalHelper *)user_data; GSimpleAsyncResult *simple; SoupHTTPInputStream *httpstream; simple = g_simple_async_result_new (G_OBJECT (helper->req), helper->callback, helper->user_data, conditional_get_ready_cb); if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) { SoupCache *cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE); httpstream = (SoupHTTPInputStream *)soup_cache_send_response (cache, msg); if (httpstream) { g_simple_async_result_set_op_res_gpointer (simple, httpstream, g_object_unref); soup_message_got_headers (helper->original); if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, helper->original)) { const char *content_type = soup_message_headers_get_content_type (msg->response_headers, NULL); soup_message_content_sniffed (helper->original, content_type, NULL); } g_simple_async_result_complete (simple); soup_message_finished (helper->original); g_object_unref (simple); } else { /* Ask again for the resource, somehow the cache cannot locate it */ httpstream = soup_http_input_stream_new (session, helper->original); soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT, helper->cancellable, sent_async, simple); } } else { /* It is in the cache but it was modified remotely */ httpstream = soup_http_input_stream_new (session, helper->original); soup_http_input_stream_send_async (httpstream, G_PRIORITY_DEFAULT, helper->cancellable, sent_async, simple); } g_object_unref (helper->req); g_object_unref (helper->original); g_slice_free (ConditionalHelper, helper); }
/** * Change scheme and port of soup messages uri if the host is a known and * valid hsts host. * This logic should be implemented in request_queued function but the changes * that are done there to the uri do not appear in webkit_web_view_get_uri(). * If a valid hsts host is requested via http and the url is changed to https * vimb would still show the http uri in url bar. This seems to be a * missbehaviour in webkit, but for now we provide this function to put in the * logic in the scope of the resource-request-starting event of the webview. */ void hsts_prepare_message(SoupSession* session, SoupMessage *msg) { SoupSessionFeature *feature; HSTSProvider *provider; SoupURI *uri; feature = soup_session_get_feature_for_message(session, HSTS_TYPE_PROVIDER, msg); uri = soup_message_get_uri(msg); if (!feature || !uri) { return; } provider = HSTS_PROVIDER(feature); if (should_secure_host(provider, uri->host)) { /* the ports is set by soup uri if scheme is changed */ soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS); } }
static void auth_required (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying) { SoupSessionFeature *password_manager; password_manager = soup_session_get_feature_for_message ( session, SOUP_TYPE_PASSWORD_MANAGER, msg); if (password_manager) { soup_session_pause_message (session, msg); g_object_ref (auth); soup_password_manager_get_passwords_async ( SOUP_PASSWORD_MANAGER (password_manager), msg, auth, retrying, soup_session_get_async_context (session), NULL, /* FIXME cancellable */ got_passwords, session); } else { SOUP_SESSION_CLASS (soup_session_async_parent_class)-> auth_required (session, msg, auth, retrying); } }
static gboolean send_async_cb (gpointer data) { GSimpleAsyncResult *simple; SoupSession *session; SendAsyncHelper *helper = (SendAsyncHelper *)data; session = soup_request_get_session (SOUP_REQUEST (helper->http)); simple = g_simple_async_result_new (G_OBJECT (helper->http), helper->callback, helper->user_data, soup_request_http_send_async); g_simple_async_result_set_op_res_gpointer (simple, helper->httpstream, g_object_unref); /* Update message status */ soup_message_set_status (helper->http->priv->msg, SOUP_STATUS_OK); /* Issue signals */ soup_message_got_headers (helper->http->priv->msg); if (soup_session_get_feature_for_message (session, SOUP_TYPE_CONTENT_SNIFFER, helper->http->priv->msg)) { const char *content_type = soup_message_headers_get_content_type (helper->http->priv->msg->response_headers, NULL); soup_message_content_sniffed (helper->http->priv->msg, content_type, NULL); } g_simple_async_result_complete (simple); soup_message_finished (helper->http->priv->msg); g_object_unref (simple); g_object_unref (helper->http); g_slice_free (SendAsyncHelper, helper); return FALSE; }
static void process_queue_item (SoupMessageQueueItem *item, gboolean *should_prune, gboolean loop) { SoupSession *session = item->session; SoupProxyURIResolver *proxy_resolver; do { switch (item->state) { case SOUP_MESSAGE_STARTING: proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, item->msg); if (!proxy_resolver) { item->state = SOUP_MESSAGE_AWAITING_CONNECTION; break; } resolve_proxy_addr (item, proxy_resolver); return; case SOUP_MESSAGE_AWAITING_CONNECTION: if (!soup_session_get_connection (session, item, should_prune)) return; if (soup_connection_get_state (item->conn) != SOUP_CONNECTION_NEW) { item->state = SOUP_MESSAGE_READY; break; } item->state = SOUP_MESSAGE_CONNECTING; soup_message_queue_item_ref (item); g_object_ref (session); soup_connection_connect_async (item->conn, item->cancellable, got_connection, item); return; case SOUP_MESSAGE_READY: item->state = SOUP_MESSAGE_RUNNING; soup_session_send_queue_item (session, item, message_completed); break; case SOUP_MESSAGE_RESTARTING: item->state = SOUP_MESSAGE_STARTING; soup_message_restarted (item->msg); break; case SOUP_MESSAGE_FINISHING: item->state = SOUP_MESSAGE_FINISHED; soup_message_finished (item->msg); if (item->state != SOUP_MESSAGE_FINISHED) break; g_object_ref (session); soup_session_unqueue_item (session, item); if (item->callback) item->callback (session, item->msg, item->callback_data); g_object_unref (item->msg); do_idle_run_queue (session); g_object_unref (session); return; default: /* Nothing to do with this message in any * other state. */ return; } } while (loop && item->state != SOUP_MESSAGE_FINISHED); }