summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcorvid <corvid@lavabit.com>2009-06-01 01:29:42 +0000
committercorvid <corvid@lavabit.com>2009-06-01 01:29:42 +0000
commit16e260e5621cde71a2a7baef681e5b658c2cc2b3 (patch)
tree4daf1644375c7ee5e98deaaec86b769ce2e1e784
parentfe833a994380f5e200904ecb367ae5d2b79701fd (diff)
proxy support for HTTPS
-rw-r--r--ChangeLog1
-rw-r--r--dillorc5
-rw-r--r--dpi/https.c66
-rw-r--r--src/IO/Url.h2
-rw-r--r--src/IO/http.c51
-rw-r--r--src/capi.c15
6 files changed, 132 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 8fbdf1e5..2dd4a19b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -37,6 +37,7 @@ dillo-2.1
- Added "View Stylesheets" to the page menu.
- Remove standard_widget_colors dillorc option.
- Added dillo(1) man page.
+ - Proxy support for HTTPS.
Patches: place (AKA corvid)
+- Switched SSL-enabled to configure.in (./configure --enable-ssl).
- Standardised the installation of dpid/dpidrc with auto* tools.
diff --git a/dillorc b/dillorc
index ab45bc10..b97e6045 100644
--- a/dillorc
+++ b/dillorc
@@ -115,9 +115,8 @@
# Set the proxy information for http.
# Note that the http_proxy environment variable overrides this setting.
-# WARNING: - HTTPS does not currently use the proxy settings.
-# - FTP and downloads plugins use wget. To use a proxy with them,
-# you will need to configure wget accordingly.
+# WARNING: FTP and downloads plugins use wget. To use a proxy with them,
+# you will need to configure wget accordingly.
# http_proxy="http://localhost:8080/"
#(by default, no proxy is used)
diff --git a/dpi/https.c b/dpi/https.c
index ba6c73a9..34d2b5f3 100644
--- a/dpi/https.c
+++ b/dpi/https.c
@@ -129,7 +129,8 @@ static void yes_ssl_support(void)
SSL_CTX * ssl_context = NULL;
SSL * ssl_connection = NULL;
- char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *http_query = NULL;
+ char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *http_query = NULL,
+ *proxy_url = NULL, *proxy_connect = NULL;
char buf[4096];
int retval = 0;
int network_socket = -1;
@@ -194,6 +195,9 @@ static void yes_ssl_support(void)
/*Get the network address and command to be used*/
dpip_tag = sock_handler_read(sh);
cmd = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "cmd");
+ proxy_url = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "proxy_url");
+ proxy_connect =
+ a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "proxy_connect");
url = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "url");
http_query = a_Dpip_get_attr(dpip_tag, strlen(dpip_tag), "query");
@@ -205,13 +209,66 @@ static void yes_ssl_support(void)
}
if (exit_error == 0){
- network_socket = get_network_connection(url);
+ char *connect_url = proxy_url ? proxy_url : url;
+
+ network_socket = get_network_connection(connect_url);
if (network_socket<0){
MSG("Network socket create error\n");
exit_error = 1;
}
}
+ if (exit_error == 0 && proxy_connect != NULL) {
+ ssize_t St;
+ const char *p = proxy_connect;
+ int writelen = strlen(proxy_connect);
+
+ while (writelen > 0) {
+ St = write(network_socket, p, writelen);
+ if (St < 0) {
+ /* Error */
+ if (errno != EINTR) {
+ MSG("Error writing to proxy.\n");
+ exit_error = 1;
+ break;
+ }
+ } else {
+ p += St;
+ writelen -= St;
+ }
+ }
+ if (exit_error == 0) {
+ const size_t buflen = 200;
+ char buf[buflen];
+ Dstr *reply = dStr_new("");
+
+ while (1) {
+ St = read(network_socket, buf, buflen);
+ if (St > 0) {
+ dStr_append_l(reply, buf, St);
+ if (strstr(reply->str, "\r\n\r\n")) {
+ /* have whole reply header */
+ if (reply->len >= 12 && reply->str[9] == '2') {
+ /* e.g. "HTTP/1.1 200 Connection established[...]" */
+ MSG("CONNECT through proxy succeeded.\n");
+ } else {
+ /* TODO: send reply body to dillo */
+ exit_error = 1;
+ MSG("CONNECT through proxy failed.\n");
+ }
+ break;
+ }
+ } else if (St < 0) {
+ if (errno != EINTR) {
+ exit_error = 1;
+ MSG("Error reading from proxy.\n");
+ break;
+ }
+ }
+ }
+ dStr_free(reply, 1);
+ }
+ }
if (exit_error == 0){
/* Configure SSL to use network file descriptor */
@@ -263,6 +320,8 @@ static void yes_ssl_support(void)
dFree(cmd);
dFree(url);
dFree(http_query);
+ dFree(proxy_url);
+ dFree(proxy_connect);
if (network_socket != -1){
close(network_socket);
@@ -297,6 +356,9 @@ static int get_network_connection(char * url)
/*Determine how much of url we chop off as unneeded*/
if (dStrncasecmp(url, "https://", 8) == 0){
url_offset = 8;
+ } else if (dStrncasecmp(url, "http://", 7) == 0) {
+ url_offset = 7;
+ portnum = 80;
}
/*Find end of URL*/
diff --git a/src/IO/Url.h b/src/IO/Url.h
index d57e9251..f144bfad 100644
--- a/src/IO/Url.h
+++ b/src/IO/Url.h
@@ -16,6 +16,8 @@ extern void a_Http_freeall(void);
int a_Http_init(void);
int a_Http_proxy_auth(void);
void a_Http_set_proxy_passwd(const char *str);
+char *a_Http_make_connect_str(const DilloUrl *url);
+const char *a_Http_get_proxy_urlstr();
Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy);
void a_Http_ccc (int Op, int Branch, int Dir, ChainLink *Info,
diff --git a/src/IO/http.c b/src/IO/http.c
index 55ba3502..ae87c8d0 100644
--- a/src/IO/http.c
+++ b/src/IO/http.c
@@ -16,6 +16,7 @@
#include <config.h>
+#include <ctype.h> /* isdigit */
#include <unistd.h>
#include <errno.h> /* for errno */
#include <stdlib.h>
@@ -415,6 +416,56 @@ static int Http_must_use_proxy(const DilloUrl *url)
}
/*
+ * Return a new string for the request used to tunnel HTTPS through a proxy.
+ * As of 2009, the best reference appears to be section 5 of RFC 2817.
+ */
+char *a_Http_make_connect_str(const DilloUrl *url)
+{
+ Dstr *dstr;
+ const char *auth1;
+ int auth_len;
+ char *auth2, *proxy_auth, *retstr;
+
+ dReturn_val_if_fail(Http_must_use_proxy(url), NULL);
+
+ dstr = dStr_new("");
+ auth1 = URL_AUTHORITY(url);
+ auth_len = strlen(auth1);
+ if (auth_len > 0 && !isdigit(auth1[auth_len - 1]))
+ /* if no port number, add HTTPS port */
+ auth2 = dStrconcat(auth1, ":443", NULL);
+ else
+ auth2 = dStrdup(auth1);
+ proxy_auth = HTTP_Proxy_Auth_base64 ?
+ dStrconcat ("Proxy-Authorization: Basic ",
+ HTTP_Proxy_Auth_base64, "\r\n", NULL) :
+ dStrdup("");
+ dStr_sprintfa(
+ dstr,
+ "CONNECT %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "%s"
+ "\r\n",
+ auth2,
+ auth2,
+ proxy_auth);
+
+ dFree(auth2);
+ dFree(proxy_auth);
+ retstr = dstr->str;
+ dStr_free(dstr, 0);
+ return retstr;
+}
+
+/*
+ * Return URL string of HTTP proxy, if any
+ */
+const char *a_Http_get_proxy_urlstr()
+{
+ return HTTP_Proxy ? URL_STR(HTTP_Proxy) : NULL;
+}
+
+/*
* Callback function for the DNS resolver.
* Continue connecting the socket, or abort upon error condition.
* S->web is checked to assert the operation wasn't aborted while waiting.
diff --git a/src/capi.c b/src/capi.c
index faa3035e..57cb4184 100644
--- a/src/capi.c
+++ b/src/capi.c
@@ -265,7 +265,6 @@ static int Capi_url_uses_dpi(DilloUrl *url, char **server_ptr)
/*
* Build the dpip command tag, according to URL and server.
- * TODO: make it PROXY-aware (AFAIS, it should be easy)
*/
static char *Capi_dpi_build_cmd(DilloWeb *web, char *server)
{
@@ -273,10 +272,20 @@ static char *Capi_dpi_build_cmd(DilloWeb *web, char *server)
if (strcmp(server, "proto.https") == 0) {
/* Let's be kind and make the HTTP query string for the dpi */
+ char *proxy_connect = a_Http_make_connect_str(web->url);
Dstr *http_query = a_Http_make_query_str(web->url, FALSE);
/* BUG: embedded NULLs in query data will truncate message */
- cmd = a_Dpip_build_cmd("cmd=%s url=%s query=%s",
- "open_url", URL_STR(web->url), http_query->str);
+ if (proxy_connect) {
+ const char *proxy_urlstr = a_Http_get_proxy_urlstr();
+ cmd = a_Dpip_build_cmd("cmd=%s proxy_url=%s proxy_connect=%s "
+ "url=%s query=%s", "open_url", proxy_urlstr,
+ proxy_connect, URL_STR(web->url),
+ http_query->str);
+ } else {
+ cmd = a_Dpip_build_cmd("cmd=%s url=%s query=%s",
+ "open_url", URL_STR(web->url),http_query->str);
+ }
+ dFree(proxy_connect);
dStr_free(http_query, 1);
} else if (strcmp(server, "downloads") == 0) {