summaryrefslogtreecommitdiffstats
path: root/lib/http_proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/http_proxy.c')
-rw-r--r--lib/http_proxy.c110
1 files changed, 85 insertions, 25 deletions
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 58489ab..e13f485 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -158,6 +158,10 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
{
struct http_connect_state *s;
struct connectdata *conn = data->conn;
+ if(conn->handler->flags & PROTOPT_NOTCPPROXY) {
+ failf(data, "%s cannot be done over CONNECT", conn->handler->scheme);
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
if(!reinit) {
CURLcode result;
DEBUGASSERT(!conn->connect_state);
@@ -198,18 +202,25 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
return CURLE_OK;
}
-static void connect_done(struct Curl_easy *data)
+void Curl_connect_done(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct http_connect_state *s = conn->connect_state;
- if(s->tunnel_state != TUNNEL_EXIT) {
+ if(s && (s->tunnel_state != TUNNEL_EXIT)) {
s->tunnel_state = TUNNEL_EXIT;
Curl_dyn_free(&s->rcvbuf);
Curl_dyn_free(&s->req);
- /* retore the protocol pointer */
- data->req.p.http = s->prot_save;
+ /* restore the protocol pointer, if not already done */
+ if(s->prot_save)
+ data->req.p.http = s->prot_save;
s->prot_save = NULL;
+ data->info.httpcode = 0; /* clear it as it might've been used for the
+ proxy */
+ data->req.ignorebody = FALSE;
+#ifdef USE_HYPER
+ data->state.hconnect = FALSE;
+#endif
infof(data, "CONNECT phase completed!");
}
}
@@ -284,8 +295,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
/* This only happens if we've looped here due to authentication
reasons, and we don't really use the newly cloned URL here
then. Just free() it. */
- free(data->req.newurl);
- data->req.newurl = NULL;
+ Curl_safefree(data->req.newurl);
/* initialize send-buffer */
Curl_dyn_init(req, DYN_HTTP_REQUEST);
@@ -657,15 +667,13 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(s->close_connection && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please");
- connect_done(data);
+ Curl_connect_done(data);
}
else {
free(data->req.newurl);
data->req.newurl = NULL;
/* failure, close this connection to avoid re-use */
streamclose(conn, "proxy CONNECT failure");
- Curl_closesocket(data, conn, conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
}
/* to back to init state */
@@ -735,6 +743,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* tell Hyper how to read/write network data */
@@ -750,6 +759,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->exec = hyper_executor_new();
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
@@ -757,6 +767,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
options = hyper_clientconn_options_new();
if(!options) {
failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -767,6 +778,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
handshake = hyper_clientconn_handshake(io, options);
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
io = NULL;
@@ -774,6 +786,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
handshake = NULL; /* ownership passed on */
@@ -781,6 +794,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
task = hyper_executor_poll(h->exec);
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -789,14 +803,24 @@ static CURLcode CONNECT(struct Curl_easy *data,
req = hyper_request_new();
if(!req) {
failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
strlen("CONNECT"))) {
failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
+ hostname, remote_port);
+
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ Curl_safefree(data->req.newurl);
+
result = CONNECT_host(data, conn, hostname, remote_port,
&hostheader, &host);
if(result)
@@ -806,6 +830,16 @@ static CURLcode CONNECT(struct Curl_easy *data,
strlen(hostheader))) {
failf(data, "error setting path");
result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(data->set.verbose) {
+ char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader);
+ if(!se) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
+ free(se);
}
/* Setup the proxy-authorization header, if any */
result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
@@ -819,21 +853,29 @@ static CURLcode CONNECT(struct Curl_easy *data,
(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0))) {
failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
- if(host && Curl_hyper_header(data, headers, host))
- goto error;
- Curl_safefree(host);
+ if(host) {
+ result = Curl_hyper_header(data, headers, host);
+ if(result)
+ goto error;
+ Curl_safefree(host);
+ }
- if(data->state.aptr.proxyuserpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
- goto error;
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
data->set.str[STRING_USERAGENT]) {
@@ -843,26 +885,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
data->set.str[STRING_USERAGENT]);
if(result)
goto error;
- if(Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)))
+ result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
+ if(result)
goto error;
Curl_dyn_free(&ua);
}
- if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
- Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
- goto error;
+ if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+ result = Curl_hyper_header(data, headers,
+ "Proxy-Connection: Keep-Alive");
+ if(result)
+ goto error;
+ }
- if(Curl_add_custom_headers(data, TRUE, headers))
+ result = Curl_add_custom_headers(data, TRUE, headers);
+ if(result)
goto error;
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -875,8 +924,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(error)
hypererr = hyper_task_value(task);
hyper_task_free(task);
- if(error)
+ if(error) {
+ /* this could probably use a better error code? */
+ result = CURLE_OUT_OF_MEMORY;
goto error;
+ }
}
} while(task);
s->tunnel_state = TUNNEL_CONNECT;
@@ -904,20 +956,28 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->write_waker = NULL;
}
}
- /* FALLTHROUGH */
+ break;
+
default:
break;
}
+
+ /* If we are supposed to continue and request a new URL, which basically
+ * means the HTTP authentication is still going on so if the tunnel
+ * is complete we start over in INIT state */
+ if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
+ infof(data, "CONNECT request done, loop to make another");
+ connect_init(data, TRUE); /* reinit */
+ }
} while(data->req.newurl);
result = CURLE_OK;
if(s->tunnel_state == TUNNEL_COMPLETE) {
- data->info.httpproxycode = data->req.httpcode;
if(data->info.httpproxycode/100 != 2) {
if(conn->bits.close && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please");
- connect_done(data);
+ Curl_connect_done(data);
}
else {
free(data->req.newurl);
@@ -991,7 +1051,7 @@ CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
result = CONNECT(data, sockindex, hostname, remote_port);
if(result || Curl_connect_complete(conn))
- connect_done(data);
+ Curl_connect_done(data);
return result;
}