static gboolean is_websocket_client (SnraServerClient * client) { /* Check for request headers. Example: * Upgrade: websocket * Connection: Upgrade, Keep-Alive * Sec-WebSocket-Key: XYZABC123 * Sec-WebSocket-Protocol: aurena * Sec-WebSocket-Version: 13 */ SoupMessage *msg = client->event_pipe; SoupMessageHeaders *req_hdrs = msg->request_headers; const gchar *val; gint protocol_ver = 0; if ((val = soup_message_headers_get_one (req_hdrs, "Upgrade")) == NULL) return FALSE; if (g_ascii_strcasecmp (val, "websocket") != 0) return FALSE; if ((val = soup_message_headers_get_list (req_hdrs, "Connection")) == NULL) return FALSE; /* Connection params list must request upgrade to websocket */ if (!http_list_contains_value (val, "upgrade")) return FALSE; if ((val = soup_message_headers_get_one (req_hdrs, "Sec-WebSocket-Key")) == NULL) return FALSE; if ((val = soup_message_headers_get_list (req_hdrs, "Sec-WebSocket-Protocol")) == NULL) return FALSE; if (!http_list_contains_value (val, "aurena")) return FALSE; /* Requested protocol version must be 13 or 8 */ if ((val = soup_message_headers_get_list (req_hdrs, "Sec-WebSocket-Version")) == NULL) return FALSE; if (http_list_contains_value (val, "13")) protocol_ver = 13; else if (http_list_contains_value (val, "8")) protocol_ver = 8; if (protocol_ver == 0) return FALSE; /* No supported version found */ g_print ("WebSocket connection with protocol %d\n", protocol_ver); client->websocket_protocol = protocol_ver; return TRUE; }
static inline const char * auth_header_for_message (SoupMessage *msg) { if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) { return soup_message_headers_get_list (msg->response_headers, "Proxy-Authenticate"); } else { return soup_message_headers_get_list (msg->response_headers, "WWW-Authenticate"); } }
static void select_auth_authenticate (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer data) { SelectAuthData *sad = data; const char *header, *basic, *digest; int round = retrying ? 1 : 0; header = soup_message_headers_get_list (msg->response_headers, "WWW-Authenticate"); basic = strstr (header, "Basic"); digest = strstr (header, "Digest"); if (basic && digest) { if (basic < digest) sad->round[round].headers = "Basic, Digest"; else sad->round[round].headers = "Digest, Basic"; } else if (basic) sad->round[round].headers = "Basic"; else if (digest) sad->round[round].headers = "Digest"; sad->round[round].response = soup_auth_get_scheme_name (auth); if (sad->password && !retrying) soup_auth_authenticate (auth, "user", sad->password); }
static void do_one_accept_language_test (const char *language, const char *expected_header) { SoupSession *session; SoupMessage *msg; const char *val; debug_printf (1, " LANGUAGE=%s\n", language); g_setenv ("LANGUAGE", language, TRUE); session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE, NULL); msg = soup_message_new_from_uri ("GET", base_uri); soup_session_send_message (session, msg); soup_test_session_abort_unref (session); if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, " Message failed? %d %s\n", msg->status_code, msg->reason_phrase); errors++; } val = soup_message_headers_get_list (msg->request_headers, "Accept-Language"); if (!val) { debug_printf (1, " No Accept-Language set!\n"); errors++; } else if (strcmp (val, expected_header) != 0) { debug_printf (1, " Wrong Accept-Language: expected '%s', got '%s'\n", expected_header, val); errors++; } g_object_unref (msg); }
static void t5_http_req_callback (SoupSession *session, SoupMessage *msg, gpointer data) { guint status_code; gchar *method; SoupURI *uri; const gchar *header; g_object_get (G_OBJECT (msg), "method", &method, "status-code", &status_code, "uri", &uri, NULL); GST_WARNING ("%s %s status code: %d, expected %d", method, soup_uri_get_path (uri), status_code, SOUP_STATUS_CANCELLED); BOOST_CHECK (status_code == SOUP_STATUS_CANCELLED); /* TODO: Check why soup_cookies_from_response does not work */ header = soup_message_headers_get_list (msg->response_headers, "Set-Cookie"); BOOST_CHECK (header != NULL); cookie = soup_cookie_parse (header, NULL); BOOST_CHECK (cookie != NULL); t5_send_get_request_2(); soup_uri_free (uri); g_free (method); }
static void t4_http_req_callback (SoupSession *session, SoupMessage *msg, gpointer data) { SoupKnownStatusCode *expected = (SoupKnownStatusCode *) data; guint status_code; gchar *method; SoupURI *uri; const gchar *cookie_str; g_object_get (G_OBJECT (msg), "method", &method, "status-code", &status_code, "uri", &uri, NULL); GST_DEBUG ("%s %s status code: %d, expected %d", method, soup_uri_get_path (uri), status_code, *expected); BOOST_CHECK (status_code == *expected); /* TODO: Check why soup_cookies_from_response does not work */ cookie_str = soup_message_headers_get_list (msg->response_headers, "Set-Cookie"); BOOST_CHECK (cookie_str != NULL); if (++counted == urls_registered) g_main_loop_quit (loop); soup_uri_free (uri); g_free (method); }
static void challenge_check (SoupMessage *msg, gpointer user_data) { NTLMState *state = user_data; const char *header; header = soup_message_headers_get_list (msg->response_headers, "WWW-Authenticate"); if (header && !strncmp (header, "NTLM ", 5)) state->got_ntlm_challenge = TRUE; }
static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { const char *accept_encoding, *junk; GSList *codings; char *file = NULL, *contents; gsize length; accept_encoding = soup_message_headers_get_list (msg->request_headers, "Accept-Encoding"); if (accept_encoding) codings = soup_header_parse_quality_list (accept_encoding, NULL); else codings = NULL; if (codings && g_slist_find_custom (codings, "gzip", (GCompareFunc)g_ascii_strcasecmp)) { file = g_strdup_printf (SRCDIR "/resources%s.gz", path); if (g_file_test (file, G_FILE_TEST_EXISTS)) { soup_message_headers_append (msg->response_headers, "Content-Encoding", "gzip"); } else { g_free (file); file = NULL; } } 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. */ soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); return; } soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE, contents, length); junk = soup_message_headers_get_one (msg->request_headers, "X-Trailing-Junk"); if (junk) { soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY, junk, strlen (junk)); } }
static void wrote_headers_callback (SoupMessage *msg, gpointer data) { const char *header; header = soup_message_headers_get_list (msg->response_headers, "WWW-Authenticate"); if (header) { if (strstr (header, "Basic ")) test_data.server_requested_basic = TRUE; if (strstr (header, "Digest ")) test_data.server_requested_digest = TRUE; } }
static void prompt_check (SoupMessage *msg, gpointer user_data) { NTLMState *state = user_data; const char *header; header = soup_message_headers_get_list (msg->response_headers, "WWW-Authenticate"); if (header && strstr (header, "Basic ")) state->got_basic_prompt = TRUE; if (header && strstr (header, "NTLM") && !strstr (header, NTLM_CHALLENGE)) state->got_ntlm_prompt = TRUE; }
static EContact * download_contact (EBookBackendWebdav *webdav, const gchar *uri, GCancellable *cancellable) { SoupMessage *message; const gchar *etag; EContact *contact; guint status; message = soup_message_new (SOUP_METHOD_GET, uri); soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT); soup_message_headers_append (message->request_headers, "Connection", "close"); status = send_and_handle_ssl (webdav, message, cancellable); if (status != 200) { g_warning ("Couldn't load '%s' (http status %d)", uri, status); g_object_unref (message); return NULL; } if (message->response_body == NULL) { g_message ("no response body after requesting '%s'", uri); g_object_unref (message); return NULL; } if (message->response_body->length <= 11 || 0 != g_ascii_strncasecmp ((const gchar *) message->response_body->data, "BEGIN:VCARD", 11)) { g_object_unref (message); return NULL; } etag = soup_message_headers_get_list (message->response_headers, "ETag"); /* we use our URI as UID */ contact = e_contact_new_from_vcard_with_uid (message->response_body->data, uri); if (contact == NULL) { g_warning ("Invalid vcard at '%s'", uri); g_object_unref (message); return NULL; } /* the etag is remembered in the revision field */ if (etag != NULL) { e_contact_set (contact, E_CONTACT_REV, (gconstpointer) etag); } g_object_unref (message); return contact; }
/** * soup_message_headers_clean_connection_headers: * @hdrs: a #SoupMessageHeaders * * Removes all the headers listed in the Connection header. * * Since: 2.36 */ void soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) { /* RFC 2616 14.10 */ const char *connection; GSList *tokens, *t; connection = soup_message_headers_get_list (hdrs, "Connection"); if (!connection) return; tokens = soup_header_parse_list (connection); for (t = tokens; t; t = t->next) soup_message_headers_remove (hdrs, t->data); soup_header_free_list (tokens); }
static guint parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, SoupEncoding *encoding, gpointer sock) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); char *req_method, *req_path, *url; SoupHTTPVersion version; const char *req_host; guint status; SoupURI *uri; status = soup_headers_parse_request (headers, headers_len, msg->request_headers, &req_method, &req_path, &version); if (!SOUP_STATUS_IS_SUCCESSFUL (status)) return status; g_object_set (G_OBJECT (msg), SOUP_MESSAGE_METHOD, req_method, SOUP_MESSAGE_HTTP_VERSION, version, NULL); g_free (req_method); /* Handle request body encoding */ *encoding = soup_message_headers_get_encoding (msg->request_headers); if (*encoding == SOUP_ENCODING_UNRECOGNIZED) { if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding")) return SOUP_STATUS_NOT_IMPLEMENTED; else return SOUP_STATUS_BAD_REQUEST; } /* Generate correct context for request */ req_host = soup_message_headers_get_one (msg->request_headers, "Host"); if (req_host && strchr (req_host, '/')) { g_free (req_path); return SOUP_STATUS_BAD_REQUEST; } if (!strcmp (req_path, "*") && req_host) { /* Eg, "OPTIONS * HTTP/1.1" */ url = g_strdup_printf ("%s://%s", soup_socket_is_ssl (sock) ? "https" : "http", req_host); uri = soup_uri_new (url); if (uri) soup_uri_set_path (uri, "*"); g_free (url); } else if (*req_path != '/') { /* Must be an absolute URI */ uri = soup_uri_new (req_path); } else if (req_host) { url = g_strdup_printf ("%s://%s%s", soup_socket_is_ssl (sock) ? "https" : "http", req_host, req_path); uri = soup_uri_new (url); g_free (url); } else if (priv->http_version == SOUP_HTTP_1_0) { /* No Host header, no AbsoluteUri */ SoupAddress *addr = soup_socket_get_local_address (sock); uri = soup_uri_new (NULL); soup_uri_set_scheme (uri, soup_socket_is_ssl (sock) ? SOUP_URI_SCHEME_HTTPS : SOUP_URI_SCHEME_HTTP); soup_uri_set_host (uri, soup_address_get_physical (addr)); soup_uri_set_port (uri, soup_address_get_port (addr)); soup_uri_set_path (uri, req_path); } else uri = NULL; g_free (req_path); if (!SOUP_URI_VALID_FOR_HTTP (uri)) { /* certainly not "a valid host on the server" (RFC2616 5.2.3) * SOUP_URI_VALID_FOR_HTTP also guards against uri == NULL */ if (uri) soup_uri_free (uri); return SOUP_STATUS_BAD_REQUEST; } soup_message_set_uri (msg, uri); soup_uri_free (uri); return SOUP_STATUS_OK; }
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 gboolean cal_backend_http_load (ECalBackendHttp *backend, const gchar *uri, gchar **out_certificate_pem, GTlsCertificateFlags *out_certificate_errors, GCancellable *cancellable, GError **error) { ECalBackendHttpPrivate *priv = backend->priv; ETimezoneCache *timezone_cache; SoupMessage *soup_message; SoupSession *soup_session; icalcomponent *icalcomp, *subcomp; icalcomponent_kind kind; const gchar *newuri; SoupURI *uri_parsed; GHashTable *old_cache; GSList *comps_in_cache; ESource *source; guint status_code; gulong cancel_id = 0; struct { SoupSession *soup_session; SoupMessage *soup_message; } cancel_data; timezone_cache = E_TIMEZONE_CACHE (backend); soup_session = backend->priv->soup_session; soup_message = cal_backend_http_new_message (backend, uri); if (soup_message == NULL) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: %s"), uri); return FALSE; } if (G_IS_CANCELLABLE (cancellable)) { cancel_data.soup_session = soup_session; cancel_data.soup_message = soup_message; cancel_id = g_cancellable_connect ( cancellable, G_CALLBACK (cal_backend_http_cancelled), &cancel_data, (GDestroyNotify) NULL); } source = e_backend_get_source (E_BACKEND (backend)); e_soup_ssl_trust_connect (soup_message, source); e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING); status_code = soup_session_send_message (soup_session, soup_message); if (G_IS_CANCELLABLE (cancellable)) g_cancellable_disconnect (cancellable, cancel_id); if (status_code == SOUP_STATUS_NOT_MODIFIED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); /* attempts with ETag can result in 304 status code */ g_object_unref (soup_message); priv->opened = TRUE; return TRUE; } /* Handle redirection ourselves */ if (SOUP_STATUS_IS_REDIRECTION (status_code)) { gboolean success; newuri = soup_message_headers_get_list ( soup_message->response_headers, "Location"); d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri)); if (newuri != NULL) { gchar *redirected_uri; if (newuri[0]=='/') { g_warning ("Hey! Relative URI returned! Working around...\n"); uri_parsed = soup_uri_new (uri); soup_uri_set_path (uri_parsed, newuri); soup_uri_set_query (uri_parsed, NULL); /* g_free (newuri); */ newuri = soup_uri_to_string (uri_parsed, FALSE); g_message ("Translated URI: %s\n", newuri); soup_uri_free (uri_parsed); } redirected_uri = webcal_to_http_method (newuri, FALSE); success = cal_backend_http_load ( backend, redirected_uri, out_certificate_pem, out_certificate_errors, cancellable, error); g_free (redirected_uri); } else { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST, _("Redirected to Invalid URI")); success = FALSE; } if (success) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); return success; } /* check status code */ if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) { /* because evolution knows only G_IO_ERROR_CANCELLED */ if (status_code == SOUP_STATUS_CANCELLED) g_set_error ( error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "%s", soup_message->reason_phrase); else g_set_error ( error, SOUP_HTTP_ERROR, status_code, "%s", soup_message->reason_phrase); if (status_code == SOUP_STATUS_SSL_FAILED) { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED); cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, out_certificate_errors); } else { e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED); } g_object_unref (soup_message); empty_cache (backend); return FALSE; } e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED); if (priv->store) { const gchar *etag; etag = soup_message_headers_get_one ( soup_message->response_headers, "ETag"); if (etag != NULL && *etag == '\0') etag = NULL; e_cal_backend_store_put_key_value (priv->store, "ETag", etag); } /* get the calendar from the response */ icalcomp = icalparser_parse_string (soup_message->response_body->data); if (!icalcomp) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Bad file format.")); g_object_unref (soup_message); empty_cache (backend); return FALSE; } if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) { g_set_error ( error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Not a calendar.")); icalcomponent_free (icalcomp); g_object_unref (soup_message); empty_cache (backend); return FALSE; } g_object_unref (soup_message); soup_message = NULL; /* Update cache */ old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); comps_in_cache = e_cal_backend_store_get_components (priv->store); while (comps_in_cache != NULL) { const gchar *uid; ECalComponent *comp = comps_in_cache->data; e_cal_component_get_uid (comp, &uid); g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp)); comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data); g_object_unref (comp); } kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend)); subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT); e_cal_backend_store_freeze_changes (priv->store); while (subcomp) { ECalComponent *comp; icalcomponent_kind subcomp_kind; icalproperty *prop = NULL; subcomp_kind = icalcomponent_isa (subcomp); prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY); if (!prop && subcomp_kind == kind) { gchar *new_uid = e_cal_component_gen_uid (); icalcomponent_set_uid (subcomp, new_uid); g_free (new_uid); } if (subcomp_kind == kind) { comp = e_cal_component_new (); if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) { const gchar *uid; gpointer orig_key, orig_value; e_cal_component_get_uid (comp, &uid); if (!put_component_to_store (backend, comp)) { g_hash_table_remove (old_cache, uid); } else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, &orig_value)) { ECalComponent *orig_comp = e_cal_component_new_from_string (orig_value); e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp); g_hash_table_remove (old_cache, uid); if (orig_comp) g_object_unref (orig_comp); } else { e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp); } } g_object_unref (comp); } else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) { icaltimezone *zone; zone = icaltimezone_new (); icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp)); e_timezone_cache_add_timezone (timezone_cache, zone); icaltimezone_free (zone, 1); } subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT); } e_cal_backend_store_thaw_changes (priv->store); /* notify the removals */ g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend); g_hash_table_destroy (old_cache); /* free memory */ icalcomponent_free (icalcomp); priv->opened = TRUE; return TRUE; }
/** * soup_message_headers_get: * @hdrs: a #SoupMessageHeaders * @name: header name * * Gets the value of header @name in @hdrs. * * This method was supposed to work correctly for both single-valued * and list-valued headers, but because some HTTP clients/servers * mistakenly send multiple copies of headers that are supposed to be * single-valued, it sometimes returns incorrect results. To fix this, * the methods soup_message_headers_get_one() and * soup_message_headers_get_list() were introduced, so callers can * explicitly state which behavior they are expecting. * * Return value: as with soup_message_headers_get_list(). * * Deprecated: Use soup_message_headers_get_one() or * soup_message_headers_get_list() instead. **/ const char * soup_message_headers_get (SoupMessageHeaders *hdrs, const char *name) { return soup_message_headers_get_list (hdrs, name); }
static guint upload_contact (EBookBackendWebdav *webdav, EContact *contact, gchar **reason, GCancellable *cancellable) { ESource *source; ESourceWebdav *webdav_extension; SoupMessage *message; gchar *uri; gchar *etag; const gchar *new_etag, *redir_uri; gchar *request; guint status; gboolean avoid_ifmatch; const gchar *extension_name; source = e_backend_get_source (E_BACKEND (webdav)); extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; webdav_extension = e_source_get_extension (source, extension_name); source = e_backend_get_source (E_BACKEND (webdav)); uri = e_contact_get (contact, E_CONTACT_UID); if (uri == NULL) { g_warning ("can't upload contact without UID"); return 400; } message = soup_message_new (SOUP_METHOD_PUT, uri); soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT); soup_message_headers_append (message->request_headers, "Connection", "close"); avoid_ifmatch = e_source_webdav_get_avoid_ifmatch (webdav_extension); /* some servers (like apache < 2.2.8) don't handle If-Match, correctly so * we can leave it out */ if (!avoid_ifmatch) { /* only override if etag is still the same on the server */ etag = e_contact_get (contact, E_CONTACT_REV); if (etag == NULL) { soup_message_headers_append ( message->request_headers, "If-None-Match", "*"); } else if (etag[0] == 'W' && etag[1] == '/') { g_warning ("we only have a weak ETag, don't use If-Match synchronisation"); } else { soup_message_headers_append ( message->request_headers, "If-Match", etag); g_free (etag); } } request = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30); soup_message_set_request ( message, "text/vcard", SOUP_MEMORY_TEMPORARY, request, strlen (request)); status = send_and_handle_ssl (webdav, message, cancellable); new_etag = soup_message_headers_get_list (message->response_headers, "ETag"); redir_uri = soup_message_headers_get_list (message->response_headers, "Location"); /* set UID and REV fields */ e_contact_set (contact, E_CONTACT_REV, (gconstpointer) new_etag); if (redir_uri && *redir_uri) { if (!strstr (redir_uri, "://")) { /* it's a relative URI */ SoupURI *suri = soup_uri_new (uri); gchar *full_uri; soup_uri_set_path (suri, redir_uri); full_uri = soup_uri_to_string (suri, TRUE); e_contact_set (contact, E_CONTACT_UID, full_uri); g_free (full_uri); soup_uri_free (suri); } else { e_contact_set (contact, E_CONTACT_UID, redir_uri); } } else { e_contact_set (contact, E_CONTACT_UID, uri); } if (reason) { *reason = g_strdup (message->reason_phrase && *message->reason_phrase ? message->reason_phrase : (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error"))); } g_object_unref (message); g_free (request); g_free (uri); return status; }
/** * soup_websocket_client_verify_handshake: * @msg: #SoupMessage containing both client and server sides of a * WebSocket handshake * @error: return location for a #GError * * Looks at the response status code and headers in @msg and * determines if they contain a valid WebSocket handshake response * (given the handshake request in @msg's request headers). * * 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. * * Returns: %TRUE if @msg contains a completed valid WebSocket * handshake, %FALSE and an error if not. * * Since: 2.50 */ gboolean soup_websocket_client_verify_handshake (SoupMessage *msg, GError **error) { const char *protocol, *request_protocols, *extensions, *accept_key; char *expected_accept_key; gboolean key_ok; if (msg->status_code == SOUP_STATUS_BAD_REQUEST) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE, _("Server rejected WebSocket handshake")); return FALSE; } if (msg->status_code != SOUP_STATUS_SWITCHING_PROTOCOLS) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET, _("Server ignored WebSocket handshake")); return FALSE; } if (!soup_message_headers_header_equals (msg->response_headers, "Upgrade", "websocket") || !soup_message_headers_header_contains (msg->response_headers, "Connection", "upgrade")) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_NOT_WEBSOCKET, _("Server ignored WebSocket handshake")); return FALSE; } protocol = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"); if (protocol) { request_protocols = soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Protocol"); if (!request_protocols || !soup_header_contains (request_protocols, protocol)) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE, _("Server requested unsupported protocol")); return FALSE; } } extensions = soup_message_headers_get_list (msg->response_headers, "Sec-WebSocket-Extensions"); if (extensions && *extensions) { g_set_error_literal (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE, _("Server requested unsupported extension")); return FALSE; } accept_key = soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Accept"); expected_accept_key = compute_accept_key (soup_message_headers_get_one (msg->request_headers, "Sec-WebSocket-Key")); key_ok = (accept_key && expected_accept_key && !g_ascii_strcasecmp (accept_key, expected_accept_key)); g_free (expected_accept_key); if (!key_ok) { g_set_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_ERROR_BAD_HANDSHAKE, _("Server returned incorrect \"%s\" key"), "Sec-WebSocket-Accept"); return FALSE; } return TRUE; }