00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
00026
00027 #include "urldata.h"
00028 #include <curl/curl.h>
00029 #include "http_proxy.h"
00030 #include "sendf.h"
00031 #include "http.h"
00032 #include "url.h"
00033 #include "select.h"
00034 #include "progress.h"
00035 #include "non-ascii.h"
00036 #include "connect.h"
00037 #include "curlx.h"
00038 #include "vtls/vtls.h"
00039
00040
00041 #include "curl_printf.h"
00042 #include "curl_memory.h"
00043 #include "memdebug.h"
00044
00045
00046
00047
00048
00049
00050 static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
00051 {
00052 #ifdef USE_SSL
00053 CURLcode result = CURLE_OK;
00054 DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS);
00055 if(!conn->bits.proxy_ssl_connected[sockindex]) {
00056
00057 result =
00058 Curl_ssl_connect_nonblocking(conn, sockindex,
00059 &conn->bits.proxy_ssl_connected[sockindex]);
00060 if(result)
00061 conn->bits.close = TRUE;
00062
00063 }
00064 return result;
00065 #else
00066 (void) conn;
00067 (void) sockindex;
00068 return CURLE_NOT_BUILT_IN;
00069 #endif
00070 }
00071
00072 CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
00073 {
00074 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
00075 const CURLcode result = https_proxy_connect(conn, sockindex);
00076 if(result)
00077 return result;
00078 if(!conn->bits.proxy_ssl_connected[sockindex])
00079 return result;
00080 }
00081
00082 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
00083 #ifndef CURL_DISABLE_PROXY
00084
00085 struct HTTP http_proxy;
00086 void *prot_save;
00087 const char *hostname;
00088 int remote_port;
00089 CURLcode result;
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 prot_save = conn->data->req.protop;
00104 memset(&http_proxy, 0, sizeof(http_proxy));
00105 conn->data->req.protop = &http_proxy;
00106 connkeep(conn, "HTTP proxy CONNECT");
00107 if(sockindex == SECONDARYSOCKET)
00108 hostname = conn->secondaryhostname;
00109 else if(conn->bits.conn_to_host)
00110 hostname = conn->conn_to_host.name;
00111 else
00112 hostname = conn->host.name;
00113
00114 if(sockindex == SECONDARYSOCKET)
00115 remote_port = conn->secondary_port;
00116 else if(conn->bits.conn_to_port)
00117 remote_port = conn->conn_to_port;
00118 else
00119 remote_port = conn->remote_port;
00120 result = Curl_proxyCONNECT(conn, sockindex, hostname,
00121 remote_port, FALSE);
00122 conn->data->req.protop = prot_save;
00123 if(CURLE_OK != result)
00124 return result;
00125 Curl_safefree(conn->allocptr.proxyuserpwd);
00126 #else
00127 return CURLE_NOT_BUILT_IN;
00128 #endif
00129 }
00130
00131 return CURLE_OK;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
00144 int sockindex,
00145 const char *hostname,
00146 int remote_port,
00147 bool blocking)
00148 {
00149 int subversion=0;
00150 struct Curl_easy *data=conn->data;
00151 struct SingleRequest *k = &data->req;
00152 CURLcode result;
00153 curl_socket_t tunnelsocket = conn->sock[sockindex];
00154 curl_off_t cl=0;
00155 bool closeConnection = FALSE;
00156 bool chunked_encoding = FALSE;
00157 time_t check;
00158
00159 #define SELECT_OK 0
00160 #define SELECT_ERROR 1
00161 #define SELECT_TIMEOUT 2
00162 int error = SELECT_OK;
00163
00164 if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
00165 return CURLE_OK;
00166
00167 conn->bits.proxy_connect_closed = FALSE;
00168
00169 do {
00170 if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
00171
00172 char *host_port;
00173 Curl_send_buffer *req_buffer;
00174
00175 infof(data, "Establish HTTP proxy tunnel to %s:%hu\n",
00176 hostname, remote_port);
00177
00178
00179
00180
00181 free(data->req.newurl);
00182 data->req.newurl = NULL;
00183
00184
00185 req_buffer = Curl_add_buffer_init();
00186
00187 if(!req_buffer)
00188 return CURLE_OUT_OF_MEMORY;
00189
00190 host_port = aprintf("%s:%hu", hostname, remote_port);
00191 if(!host_port) {
00192 Curl_add_buffer_free(req_buffer);
00193 return CURLE_OUT_OF_MEMORY;
00194 }
00195
00196
00197 result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
00198
00199 free(host_port);
00200
00201 if(!result) {
00202 char *host=(char *)"";
00203 const char *proxyconn="";
00204 const char *useragent="";
00205 const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
00206 "1.0" : "1.1";
00207 bool ipv6_ip = conn->bits.ipv6_ip;
00208 char *hostheader;
00209
00210
00211 if(hostname != conn->host.name)
00212 ipv6_ip = (strchr(hostname, ':') != NULL);
00213 hostheader=
00214 aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
00215 remote_port);
00216 if(!hostheader) {
00217 Curl_add_buffer_free(req_buffer);
00218 return CURLE_OUT_OF_MEMORY;
00219 }
00220
00221 if(!Curl_checkProxyheaders(conn, "Host:")) {
00222 host = aprintf("Host: %s\r\n", hostheader);
00223 if(!host) {
00224 free(hostheader);
00225 Curl_add_buffer_free(req_buffer);
00226 return CURLE_OUT_OF_MEMORY;
00227 }
00228 }
00229 if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
00230 proxyconn = "Proxy-Connection: Keep-Alive\r\n";
00231
00232 if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
00233 data->set.str[STRING_USERAGENT])
00234 useragent = conn->allocptr.uagent;
00235
00236 result =
00237 Curl_add_bufferf(req_buffer,
00238 "CONNECT %s HTTP/%s\r\n"
00239 "%s"
00240 "%s"
00241 "%s"
00242 "%s",
00243 hostheader,
00244 http,
00245 host,
00246 conn->allocptr.proxyuserpwd?
00247 conn->allocptr.proxyuserpwd:"",
00248 useragent,
00249 proxyconn);
00250
00251 if(host && *host)
00252 free(host);
00253 free(hostheader);
00254
00255 if(!result)
00256 result = Curl_add_custom_headers(conn, TRUE, req_buffer);
00257
00258 if(!result)
00259
00260 result = Curl_add_bufferf(req_buffer, "\r\n");
00261
00262 if(!result) {
00263
00264
00265 result =
00266 Curl_add_buffer_send(req_buffer, conn,
00267 &data->info.request_size, 0, sockindex);
00268 }
00269 req_buffer = NULL;
00270 if(result)
00271 failf(data, "Failed sending CONNECT to proxy");
00272 }
00273
00274 Curl_add_buffer_free(req_buffer);
00275 if(result)
00276 return result;
00277
00278 conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
00279 }
00280
00281 check = Curl_timeleft(data, NULL, TRUE);
00282 if(check <= 0) {
00283 failf(data, "Proxy CONNECT aborted due to timeout");
00284 return CURLE_RECV_ERROR;
00285 }
00286
00287 if(!blocking) {
00288 if(!Curl_conn_data_pending(conn, sockindex))
00289
00290 return CURLE_OK;
00291 else {
00292 DEBUGF(infof(data,
00293 "Read response immediately from proxy CONNECT\n"));
00294 }
00295 }
00296
00297
00298
00299 {
00300 size_t nread;
00301 int perline;
00302 int keepon=TRUE;
00303 ssize_t gotbytes;
00304 char *ptr;
00305 char *line_start;
00306
00307 ptr = data->state.buffer;
00308 line_start = ptr;
00309
00310 nread = 0;
00311 perline = 0;
00312
00313 while(nread < BUFSIZE && keepon && !error) {
00314 int writetype;
00315
00316 if(Curl_pgrsUpdate(conn))
00317 return CURLE_ABORTED_BY_CALLBACK;
00318
00319 if(ptr >= &data->state.buffer[BUFSIZE]) {
00320 failf(data, "CONNECT response too large!");
00321 return CURLE_RECV_ERROR;
00322 }
00323
00324 check = Curl_timeleft(data, NULL, TRUE);
00325 if(check <= 0) {
00326 failf(data, "Proxy CONNECT aborted due to timeout");
00327 error = SELECT_TIMEOUT;
00328 break;
00329 }
00330
00331
00332
00333 result = Curl_read(conn, tunnelsocket, ptr, 1, &gotbytes);
00334 if(result == CURLE_AGAIN) {
00335 if(SOCKET_READABLE(tunnelsocket, check<1000L?check:1000) == -1) {
00336 error = SELECT_ERROR;
00337 failf(data, "Proxy CONNECT aborted due to select/poll error");
00338 break;
00339 }
00340 continue;
00341 }
00342 else if(result) {
00343 keepon = FALSE;
00344 break;
00345 }
00346 else if(gotbytes <= 0) {
00347 if(data->set.proxyauth && data->state.authproxy.avail) {
00348
00349
00350 conn->bits.proxy_connect_closed = TRUE;
00351 infof(data, "Proxy CONNECT connection closed\n");
00352 }
00353 else {
00354 error = SELECT_ERROR;
00355 failf(data, "Proxy CONNECT aborted");
00356 }
00357 keepon = FALSE;
00358 break;
00359 }
00360
00361
00362 nread++;
00363
00364 if(keepon > TRUE) {
00365
00366
00367 nread = 0;
00368 ptr = data->state.buffer;
00369 if(cl) {
00370
00371
00372 cl--;
00373 if(cl <= 0) {
00374 keepon = FALSE;
00375 break;
00376 }
00377 }
00378 else {
00379
00380
00381 CHUNKcode r;
00382 ssize_t tookcareof = 0;
00383
00384
00385
00386 r = Curl_httpchunk_read(conn, ptr, 1, &tookcareof);
00387 if(r == CHUNKE_STOP) {
00388
00389 infof(data, "chunk reading DONE\n");
00390 keepon = FALSE;
00391
00392 conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
00393 }
00394 }
00395 continue;
00396 }
00397
00398 perline++;
00399
00400
00401 if(*ptr != 0x0a) {
00402 ptr++;
00403 continue;
00404 }
00405
00406
00407 result = Curl_convert_from_network(data, line_start, perline);
00408
00409 if(result)
00410 return result;
00411
00412
00413 if(data->set.verbose)
00414 Curl_debug(data, CURLINFO_HEADER_IN,
00415 line_start, (size_t)perline, conn);
00416
00417
00418 writetype = CLIENTWRITE_HEADER;
00419 if(data->set.include_header)
00420 writetype |= CLIENTWRITE_BODY;
00421
00422 result = Curl_client_write(conn, writetype, line_start, perline);
00423
00424 data->info.header_size += (long)perline;
00425 data->req.headerbytecount += (long)perline;
00426
00427 if(result)
00428 return result;
00429
00430
00431
00432
00433
00434 if(('\r' == line_start[0]) ||
00435 ('\n' == line_start[0])) {
00436
00437 nread = 0;
00438
00439 ptr = data->state.buffer;
00440 if((407 == k->httpcode) && !data->state.authproblem) {
00441
00442
00443
00444 keepon = 2;
00445
00446 if(cl) {
00447 infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
00448 " bytes of response-body\n", cl);
00449 }
00450 else if(chunked_encoding) {
00451 CHUNKcode r;
00452
00453 infof(data, "Ignore chunked response-body\n");
00454
00455
00456
00457
00458
00459 k->ignorebody = TRUE;
00460
00461 if(line_start[1] == '\n') {
00462
00463
00464 line_start++;
00465 }
00466
00467
00468
00469 r = Curl_httpchunk_read(conn, line_start + 1, 1, &gotbytes);
00470 if(r == CHUNKE_STOP) {
00471
00472 infof(data, "chunk reading DONE\n");
00473 keepon = FALSE;
00474
00475
00476 conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
00477 }
00478 }
00479 else {
00480
00481
00482
00483 keepon = FALSE;
00484 }
00485 }
00486 else
00487 keepon = FALSE;
00488
00489 conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
00490 continue;
00491 }
00492
00493 line_start[perline] = 0;
00494 if((checkprefix("WWW-Authenticate:", line_start) &&
00495 (401 == k->httpcode)) ||
00496 (checkprefix("Proxy-authenticate:", line_start) &&
00497 (407 == k->httpcode))) {
00498
00499 bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
00500 char *auth = Curl_copy_header_value(line_start);
00501 if(!auth)
00502 return CURLE_OUT_OF_MEMORY;
00503
00504 result = Curl_http_input_auth(conn, proxy, auth);
00505
00506 free(auth);
00507
00508 if(result)
00509 return result;
00510 }
00511 else if(checkprefix("Content-Length:", line_start)) {
00512 if(k->httpcode/100 == 2) {
00513
00514
00515
00516 failf(data, "Content-Length: in %03d response",
00517 k->httpcode);
00518 return CURLE_RECV_ERROR;
00519 }
00520
00521 cl = curlx_strtoofft(line_start +
00522 strlen("Content-Length:"), NULL, 10);
00523 }
00524 else if(Curl_compareheader(line_start, "Connection:", "close"))
00525 closeConnection = TRUE;
00526 else if(Curl_compareheader(line_start,
00527 "Transfer-Encoding:",
00528 "chunked")) {
00529 if(k->httpcode/100 == 2) {
00530
00531
00532
00533 failf(data, "Transfer-Encoding: in %03d response", k->httpcode);
00534 return CURLE_RECV_ERROR;
00535 }
00536 infof(data, "CONNECT responded chunked\n");
00537 chunked_encoding = TRUE;
00538
00539 Curl_httpchunk_init(conn);
00540 }
00541 else if(Curl_compareheader(line_start, "Proxy-Connection:", "close"))
00542 closeConnection = TRUE;
00543 else if(2 == sscanf(line_start, "HTTP/1.%d %d",
00544 &subversion,
00545 &k->httpcode)) {
00546
00547 data->info.httpproxycode = k->httpcode;
00548 }
00549
00550 perline = 0;
00551 ptr = data->state.buffer;
00552 line_start = ptr;
00553 }
00554
00555 if(Curl_pgrsUpdate(conn))
00556 return CURLE_ABORTED_BY_CALLBACK;
00557
00558 if(error)
00559 return CURLE_RECV_ERROR;
00560
00561 if(data->info.httpproxycode != 200) {
00562
00563
00564 result = Curl_http_auth_act(conn);
00565 if(result)
00566 return result;
00567
00568 if(conn->bits.close)
00569
00570
00571
00572 closeConnection = TRUE;
00573 }
00574
00575 if(closeConnection && data->req.newurl) {
00576
00577 Curl_closesocket(conn, conn->sock[sockindex]);
00578 conn->sock[sockindex] = CURL_SOCKET_BAD;
00579 break;
00580 }
00581 }
00582
00583
00584
00585
00586 if(data->req.newurl &&
00587 (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) {
00588 conn->tunnel_state[sockindex] = TUNNEL_INIT;
00589 infof(data, "TUNNEL_STATE switched to: %d\n",
00590 conn->tunnel_state[sockindex]);
00591 }
00592
00593 } while(data->req.newurl);
00594
00595 if(200 != data->req.httpcode) {
00596 if(closeConnection && data->req.newurl) {
00597 conn->bits.proxy_connect_closed = TRUE;
00598 infof(data, "Connect me again please\n");
00599 }
00600 else {
00601 free(data->req.newurl);
00602 data->req.newurl = NULL;
00603
00604 streamclose(conn, "proxy CONNECT failure");
00605 Curl_closesocket(conn, conn->sock[sockindex]);
00606 conn->sock[sockindex] = CURL_SOCKET_BAD;
00607 }
00608
00609
00610 conn->tunnel_state[sockindex] = TUNNEL_INIT;
00611
00612 if(conn->bits.proxy_connect_closed)
00613
00614 return CURLE_OK;
00615 else {
00616 failf(data, "Received HTTP code %d from proxy after CONNECT",
00617 data->req.httpcode);
00618 return CURLE_RECV_ERROR;
00619 }
00620 }
00621
00622 conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
00623
00624
00625
00626
00627 Curl_safefree(conn->allocptr.proxyuserpwd);
00628 conn->allocptr.proxyuserpwd = NULL;
00629
00630 data->state.authproxy.done = TRUE;
00631
00632 infof(data, "Proxy replied OK to CONNECT request\n");
00633 data->req.ignorebody = FALSE;
00634 conn->bits.rewindaftersend = FALSE;
00635
00636 return CURLE_OK;
00637 }
00638 #endif