From e0a455b457935e044adeff453e4c923fe79a6b09 Mon Sep 17 00:00:00 2001 From: Johan Sternerup Date: Fri, 25 Sep 2020 17:14:52 +0200 Subject: agent: Support adding optional headers to HTTP proxy client One use case for this is adding an ALPN header which is a MUST requirement when a HTTP proxy is used in WebRTC (see RFC8835, section 3.4). --- agent/agent-priv.h | 1 + agent/agent.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- socket/http.c | 42 ++++++++++++++++++++++++++++-------------- socket/http.h | 3 ++- 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/agent/agent-priv.h b/agent/agent-priv.h index 1d8b683..35ae5ab 100644 --- a/agent/agent-priv.h +++ b/agent/agent-priv.h @@ -140,6 +140,7 @@ struct _NiceAgent NiceProxyType proxy_type; /* property: Proxy type */ gchar *proxy_username; /* property: Proxy username */ gchar *proxy_password; /* property: Proxy password */ + GHashTable *proxy_extra_headers;/* property: Proxy extra headers */ gboolean saved_controlling_mode;/* property: controlling-mode */ guint timer_ta; /* property: timer Ta */ guint max_conn_checks; /* property: max connectivity checks */ diff --git a/agent/agent.c b/agent/agent.c index a2e150f..6278fa7 100644 --- a/agent/agent.c +++ b/agent/agent.c @@ -112,6 +112,7 @@ enum PROP_PROXY_PORT, PROP_PROXY_USERNAME, PROP_PROXY_PASSWORD, + PROP_PROXY_EXTRA_HEADERS, PROP_UPNP, PROP_UPNP_TIMEOUT, PROP_RELIABLE, @@ -614,6 +615,23 @@ nice_agent_class_init (NiceAgentClass *klass) NULL, G_PARAM_READWRITE)); + /** + * NiceAgent:proxy-extra-headers: (type GLib.HashTable(utf8,utf8)) + * + * Optional extra headers to append to the HTTP proxy CONNECT request. + * Provided as key/value-pairs in hash table corresponding to + * header-name/header-value. + * + * Since: 0.1.20 + */ + g_object_class_install_property (gobject_class, PROP_PROXY_EXTRA_HEADERS, + g_param_spec_boxed ( + "proxy-extra-headers", + "Extra headers for HTTP proxy connect", + "Extra headers to append to the HTTP proxy CONNECT request", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE)); + /** * NiceAgent:upnp: * @@ -1427,6 +1445,10 @@ nice_agent_get_property ( g_value_set_string (value, agent->proxy_password); break; + case PROP_PROXY_EXTRA_HEADERS: + g_value_set_boxed (value, agent->proxy_extra_headers); + break; + case PROP_UPNP: #ifdef HAVE_GUPNP g_value_set_boolean (value, agent->upnp_enabled); @@ -1563,6 +1585,12 @@ nice_agent_reset_all_stun_agents (NiceAgent *agent, gboolean only_software) } } +static void +copy_hash_entry (const gchar *key, const gchar *value, GHashTable *hdest) +{ + g_hash_table_insert (hdest, g_strdup (key), g_strdup (value)); +} + static void nice_agent_set_property ( GObject *object, @@ -1652,6 +1680,17 @@ nice_agent_set_property ( agent->proxy_password = g_value_dup_string (value); break; + case PROP_PROXY_EXTRA_HEADERS:{ + GHashTable *h = g_value_get_boxed (value); + if (agent->proxy_extra_headers) { + g_hash_table_unref (agent->proxy_extra_headers); + } + agent->proxy_extra_headers = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, g_free); + g_hash_table_foreach (h, (GHFunc)copy_hash_entry, + agent->proxy_extra_headers); + break; + } case PROP_UPNP_TIMEOUT: #ifdef HAVE_GUPNP agent->upnp_timeout = g_value_get_uint (value); @@ -2673,7 +2712,8 @@ agent_create_tcp_turn_socket (NiceAgent *agent, NiceStream *stream, agent->proxy_username, agent->proxy_password); } else if (agent->proxy_type == NICE_PROXY_TYPE_HTTP){ nicesock = nice_http_socket_new (nicesock, server, - agent->proxy_username, agent->proxy_password); + agent->proxy_username, agent->proxy_password, + agent->proxy_extra_headers); } else { nice_socket_free (nicesock); nicesock = NULL; @@ -5761,7 +5801,10 @@ nice_agent_dispose (GObject *object) agent->proxy_username = NULL; g_free (agent->proxy_password); agent->proxy_password = NULL; - + if (agent->proxy_extra_headers != NULL) { + g_hash_table_unref (agent->proxy_extra_headers); + agent->proxy_extra_headers = NULL; + } nice_rng_free (agent->rng); agent->rng = NULL; diff --git a/socket/http.c b/socket/http.c index 96ddfd8..d16b317 100644 --- a/socket/http.c +++ b/socket/http.c @@ -97,9 +97,17 @@ static void socket_set_writable_callback (NiceSocket *sock, NiceSocketWritableCb callback, gpointer user_data); static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other); +static void +_append_extra_header (gpointer key, gpointer value, gpointer user_data) +{ + GString *str = user_data; + g_string_append_printf (str, "%s: %s\r\n", (gchar *)key, (gchar *)value); +} + NiceSocket * nice_http_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password) + NiceAddress *addr, gchar *username, gchar *password, + GHashTable *extra_headers) { HttpPriv *priv; NiceSocket *sock = NULL; @@ -133,7 +141,7 @@ nice_http_socket_new (NiceSocket *base_socket, /* Send HTTP CONNECT */ { gchar *msg = NULL; - gchar *credential = NULL; + GString *str = NULL; gchar host[INET6_ADDRSTRLEN]; gint port = nice_address_get_port (&priv->addr); GOutputVector local_bufs; @@ -141,25 +149,31 @@ nice_http_socket_new (NiceSocket *base_socket, nice_address_to_string (&priv->addr, host); + str = g_string_new (NULL); + g_string_printf (str, "CONNECT %s:%d HTTP/1.0\r\n" + "Host: %s\r\n" + "User-Agent: %s\r\n" + "Content-Length: 0\r\n" + "Proxy-Connection: Keep-Alive\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n" + "Pragma: no-cache\r\n", + host, port, host, HTTP_USER_AGENT); + + if (extra_headers) { + g_hash_table_foreach (extra_headers, _append_extra_header, str); + } + if (username) { gchar * userpass = g_strdup_printf ("%s:%s", username, password ? password : ""); gchar * auth = g_base64_encode ((guchar *)userpass, strlen (userpass)); - credential = g_strdup_printf ("Proxy-Authorization: Basic %s\r\n", auth); + g_string_append_printf (str, "Proxy-Authorization: Basic %s\r\n", auth); g_free (auth); g_free (userpass); } - msg = g_strdup_printf ("CONNECT %s:%d HTTP/1.0\r\n" - "Host: %s\r\n" - "User-Agent: %s\r\n" - "Content-Length: 0\r\n" - "Proxy-Connection: Keep-Alive\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n" - "Pragma: no-cache\r\n" - "%s\r\n", host, port, host, HTTP_USER_AGENT, - credential? credential : "" ); - g_free (credential); + g_string_append_printf (str, "\r\n"); + msg = g_string_free (str, FALSE); local_bufs.buffer = msg; local_bufs.size = strlen (msg); diff --git a/socket/http.h b/socket/http.h index 7f095a0..b2df362 100644 --- a/socket/http.h +++ b/socket/http.h @@ -45,7 +45,8 @@ G_BEGIN_DECLS NiceSocket * nice_http_socket_new (NiceSocket *base_socket, - NiceAddress *addr, gchar *username, gchar *password); + NiceAddress *addr, gchar *username, gchar *password, + GHashTable *extra_headers); G_END_DECLS -- cgit v1.2.3