Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/http_proxy.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. | |
| 9 * | |
| 10 * This software is licensed as described in the file COPYING, which | |
| 11 * you should have received as part of this distribution. The terms | |
| 12 * are also available at https://curl.haxx.se/docs/copyright.html. | |
| 13 * | |
| 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell | |
| 15 * copies of the Software, and permit persons to whom the Software is | |
| 16 * furnished to do so, under the terms of the COPYING file. | |
| 17 * | |
| 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | |
| 19 * KIND, either express or implied. | |
| 20 * | |
| 21 ***************************************************************************/ | |
| 22 | |
| 23 #include "curl_setup.h" | |
| 24 | |
| 25 #include "http_proxy.h" | |
| 26 | |
| 27 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) | |
| 28 | |
| 29 #include <curl/curl.h> | |
| 30 #include "sendf.h" | |
| 31 #include "http.h" | |
| 32 #include "url.h" | |
| 33 #include "select.h" | |
| 34 #include "progress.h" | |
| 35 #include "non-ascii.h" | |
| 36 #include "connect.h" | |
| 37 #include "curlx.h" | |
| 38 #include "vtls/vtls.h" | |
| 39 | |
| 40 /* The last 3 #include files should be in this order */ | |
| 41 #include "curl_printf.h" | |
| 42 #include "curl_memory.h" | |
| 43 #include "memdebug.h" | |
| 44 | |
| 45 /* | |
| 46 * Perform SSL initialization for HTTPS proxy. Sets | |
| 47 * proxy_ssl_connected connection bit when complete. Can be | |
| 48 * called multiple times. | |
| 49 */ | |
| 50 static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) | |
| 51 { | |
| 52 #ifdef USE_SSL | |
| 53 CURLcode result = CURLE_OK; | |
| 54 DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS); | |
| 55 if(!conn->bits.proxy_ssl_connected[sockindex]) { | |
| 56 /* perform SSL initialization for this socket */ | |
| 57 result = | |
| 58 Curl_ssl_connect_nonblocking(conn, sockindex, | |
| 59 &conn->bits.proxy_ssl_connected[sockindex]); | |
| 60 if(result) | |
| 61 conn->bits.close = TRUE; /* a failed connection is marked for closure to | |
| 62 prevent (bad) re-use or similar */ | |
| 63 } | |
| 64 return result; | |
| 65 #else | |
| 66 (void) conn; | |
| 67 (void) sockindex; | |
| 68 return CURLE_NOT_BUILT_IN; | |
| 69 #endif | |
| 70 } | |
| 71 | |
| 72 CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) | |
| 73 { | |
| 74 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { | |
| 75 const CURLcode result = https_proxy_connect(conn, sockindex); | |
| 76 if(result) | |
| 77 return result; | |
| 78 if(!conn->bits.proxy_ssl_connected[sockindex]) | |
| 79 return result; /* wait for HTTPS proxy SSL initialization to complete */ | |
| 80 } | |
| 81 | |
| 82 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { | |
| 83 #ifndef CURL_DISABLE_PROXY | |
| 84 /* for [protocol] tunneled through HTTP proxy */ | |
| 85 struct HTTP http_proxy; | |
| 86 void *prot_save; | |
| 87 const char *hostname; | |
| 88 int remote_port; | |
| 89 CURLcode result; | |
| 90 | |
| 91 /* BLOCKING */ | |
| 92 /* We want "seamless" operations through HTTP proxy tunnel */ | |
| 93 | |
| 94 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the | |
| 95 * member conn->proto.http; we want [protocol] through HTTP and we have | |
| 96 * to change the member temporarily for connecting to the HTTP | |
| 97 * proxy. After Curl_proxyCONNECT we have to set back the member to the | |
| 98 * original pointer | |
| 99 * | |
| 100 * This function might be called several times in the multi interface case | |
| 101 * if the proxy's CONNECT response is not instant. | |
| 102 */ | |
| 103 prot_save = conn->data->req.protop; | |
| 104 memset(&http_proxy, 0, sizeof(http_proxy)); | |
| 105 conn->data->req.protop = &http_proxy; | |
| 106 connkeep(conn, "HTTP proxy CONNECT"); | |
| 107 | |
| 108 /* for the secondary socket (FTP), use the "connect to host" | |
| 109 * but ignore the "connect to port" (use the secondary port) | |
| 110 */ | |
| 111 | |
| 112 if(conn->bits.conn_to_host) | |
| 113 hostname = conn->conn_to_host.name; | |
| 114 else if(sockindex == SECONDARYSOCKET) | |
| 115 hostname = conn->secondaryhostname; | |
| 116 else | |
| 117 hostname = conn->host.name; | |
| 118 | |
| 119 if(sockindex == SECONDARYSOCKET) | |
| 120 remote_port = conn->secondary_port; | |
| 121 else if(conn->bits.conn_to_port) | |
| 122 remote_port = conn->conn_to_port; | |
| 123 else | |
| 124 remote_port = conn->remote_port; | |
| 125 result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port); | |
| 126 conn->data->req.protop = prot_save; | |
| 127 if(CURLE_OK != result) | |
| 128 return result; | |
| 129 Curl_safefree(conn->allocptr.proxyuserpwd); | |
| 130 #else | |
| 131 return CURLE_NOT_BUILT_IN; | |
| 132 #endif | |
| 133 } | |
| 134 /* no HTTP tunnel proxy, just return */ | |
| 135 return CURLE_OK; | |
| 136 } | |
| 137 | |
| 138 bool Curl_connect_complete(struct connectdata *conn) | |
| 139 { | |
| 140 return !conn->connect_state || | |
| 141 (conn->connect_state->tunnel_state == TUNNEL_COMPLETE); | |
| 142 } | |
| 143 | |
| 144 bool Curl_connect_ongoing(struct connectdata *conn) | |
| 145 { | |
| 146 return conn->connect_state && | |
| 147 (conn->connect_state->tunnel_state != TUNNEL_COMPLETE); | |
| 148 } | |
| 149 | |
| 150 static CURLcode connect_init(struct connectdata *conn, bool reinit) | |
| 151 { | |
| 152 struct http_connect_state *s; | |
| 153 if(!reinit) { | |
| 154 DEBUGASSERT(!conn->connect_state); | |
| 155 s = calloc(1, sizeof(struct http_connect_state)); | |
| 156 if(!s) | |
| 157 return CURLE_OUT_OF_MEMORY; | |
| 158 infof(conn->data, "allocate connect buffer!\n"); | |
| 159 conn->connect_state = s; | |
| 160 } | |
| 161 else { | |
| 162 DEBUGASSERT(conn->connect_state); | |
| 163 s = conn->connect_state; | |
| 164 } | |
| 165 s->tunnel_state = TUNNEL_INIT; | |
| 166 s->keepon = TRUE; | |
| 167 s->line_start = s->connect_buffer; | |
| 168 s->ptr = s->line_start; | |
| 169 s->cl = 0; | |
| 170 s->close_connection = FALSE; | |
| 171 return CURLE_OK; | |
| 172 } | |
| 173 | |
| 174 static void connect_done(struct connectdata *conn) | |
| 175 { | |
| 176 struct http_connect_state *s = conn->connect_state; | |
| 177 s->tunnel_state = TUNNEL_COMPLETE; | |
| 178 infof(conn->data, "CONNECT phase completed!\n"); | |
| 179 } | |
| 180 | |
| 181 static CURLcode CONNECT(struct connectdata *conn, | |
| 182 int sockindex, | |
| 183 const char *hostname, | |
| 184 int remote_port) | |
| 185 { | |
| 186 int subversion = 0; | |
| 187 struct Curl_easy *data = conn->data; | |
| 188 struct SingleRequest *k = &data->req; | |
| 189 CURLcode result; | |
| 190 curl_socket_t tunnelsocket = conn->sock[sockindex]; | |
| 191 struct http_connect_state *s = conn->connect_state; | |
| 192 | |
| 193 #define SELECT_OK 0 | |
| 194 #define SELECT_ERROR 1 | |
| 195 | |
| 196 if(Curl_connect_complete(conn)) | |
| 197 return CURLE_OK; /* CONNECT is already completed */ | |
| 198 | |
| 199 conn->bits.proxy_connect_closed = FALSE; | |
| 200 | |
| 201 do { | |
| 202 timediff_t check; | |
| 203 if(TUNNEL_INIT == s->tunnel_state) { | |
| 204 /* BEGIN CONNECT PHASE */ | |
| 205 char *host_port; | |
| 206 Curl_send_buffer *req_buffer; | |
| 207 | |
| 208 infof(data, "Establish HTTP proxy tunnel to %s:%d\n", | |
| 209 hostname, remote_port); | |
| 210 | |
| 211 /* This only happens if we've looped here due to authentication | |
| 212 reasons, and we don't really use the newly cloned URL here | |
| 213 then. Just free() it. */ | |
| 214 free(data->req.newurl); | |
| 215 data->req.newurl = NULL; | |
| 216 | |
| 217 /* initialize a dynamic send-buffer */ | |
| 218 req_buffer = Curl_add_buffer_init(); | |
| 219 | |
| 220 if(!req_buffer) | |
| 221 return CURLE_OUT_OF_MEMORY; | |
| 222 | |
| 223 host_port = aprintf("%s:%d", hostname, remote_port); | |
| 224 if(!host_port) { | |
| 225 Curl_add_buffer_free(&req_buffer); | |
| 226 return CURLE_OUT_OF_MEMORY; | |
| 227 } | |
| 228 | |
| 229 /* Setup the proxy-authorization header, if any */ | |
| 230 result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); | |
| 231 | |
| 232 free(host_port); | |
| 233 | |
| 234 if(!result) { | |
| 235 char *host = NULL; | |
| 236 const char *proxyconn = ""; | |
| 237 const char *useragent = ""; | |
| 238 const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? | |
| 239 "1.0" : "1.1"; | |
| 240 bool ipv6_ip = conn->bits.ipv6_ip; | |
| 241 char *hostheader; | |
| 242 | |
| 243 /* the hostname may be different */ | |
| 244 if(hostname != conn->host.name) | |
| 245 ipv6_ip = (strchr(hostname, ':') != NULL); | |
| 246 hostheader = /* host:port with IPv6 support */ | |
| 247 aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", | |
| 248 remote_port); | |
| 249 if(!hostheader) { | |
| 250 Curl_add_buffer_free(&req_buffer); | |
| 251 return CURLE_OUT_OF_MEMORY; | |
| 252 } | |
| 253 | |
| 254 if(!Curl_checkProxyheaders(conn, "Host")) { | |
| 255 host = aprintf("Host: %s\r\n", hostheader); | |
| 256 if(!host) { | |
| 257 free(hostheader); | |
| 258 Curl_add_buffer_free(&req_buffer); | |
| 259 return CURLE_OUT_OF_MEMORY; | |
| 260 } | |
| 261 } | |
| 262 if(!Curl_checkProxyheaders(conn, "Proxy-Connection")) | |
| 263 proxyconn = "Proxy-Connection: Keep-Alive\r\n"; | |
| 264 | |
| 265 if(!Curl_checkProxyheaders(conn, "User-Agent") && | |
| 266 data->set.str[STRING_USERAGENT]) | |
| 267 useragent = conn->allocptr.uagent; | |
| 268 | |
| 269 result = | |
| 270 Curl_add_bufferf(&req_buffer, | |
| 271 "CONNECT %s HTTP/%s\r\n" | |
| 272 "%s" /* Host: */ | |
| 273 "%s" /* Proxy-Authorization */ | |
| 274 "%s" /* User-Agent */ | |
| 275 "%s", /* Proxy-Connection */ | |
| 276 hostheader, | |
| 277 http, | |
| 278 host?host:"", | |
| 279 conn->allocptr.proxyuserpwd? | |
| 280 conn->allocptr.proxyuserpwd:"", | |
| 281 useragent, | |
| 282 proxyconn); | |
| 283 | |
| 284 if(host) | |
| 285 free(host); | |
| 286 free(hostheader); | |
| 287 | |
| 288 if(!result) | |
| 289 result = Curl_add_custom_headers(conn, TRUE, req_buffer); | |
| 290 | |
| 291 if(!result) | |
| 292 /* CRLF terminate the request */ | |
| 293 result = Curl_add_bufferf(&req_buffer, "\r\n"); | |
| 294 | |
| 295 if(!result) { | |
| 296 /* Send the connect request to the proxy */ | |
| 297 /* BLOCKING */ | |
| 298 result = | |
| 299 Curl_add_buffer_send(&req_buffer, conn, | |
| 300 &data->info.request_size, 0, sockindex); | |
| 301 } | |
| 302 req_buffer = NULL; | |
| 303 if(result) | |
| 304 failf(data, "Failed sending CONNECT to proxy"); | |
| 305 } | |
| 306 | |
| 307 Curl_add_buffer_free(&req_buffer); | |
| 308 if(result) | |
| 309 return result; | |
| 310 | |
| 311 s->tunnel_state = TUNNEL_CONNECT; | |
| 312 s->perline = 0; | |
| 313 } /* END CONNECT PHASE */ | |
| 314 | |
| 315 check = Curl_timeleft(data, NULL, TRUE); | |
| 316 if(check <= 0) { | |
| 317 failf(data, "Proxy CONNECT aborted due to timeout"); | |
| 318 return CURLE_OPERATION_TIMEDOUT; | |
| 319 } | |
| 320 | |
| 321 if(!Curl_conn_data_pending(conn, sockindex)) | |
| 322 /* return so we'll be called again polling-style */ | |
| 323 return CURLE_OK; | |
| 324 | |
| 325 /* at this point, the tunnel_connecting phase is over. */ | |
| 326 | |
| 327 { /* READING RESPONSE PHASE */ | |
| 328 int error = SELECT_OK; | |
| 329 | |
| 330 while(s->keepon && !error) { | |
| 331 ssize_t gotbytes; | |
| 332 | |
| 333 /* make sure we have space to read more data */ | |
| 334 if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) { | |
| 335 failf(data, "CONNECT response too large!"); | |
| 336 return CURLE_RECV_ERROR; | |
| 337 } | |
| 338 | |
| 339 /* Read one byte at a time to avoid a race condition. Wait at most one | |
| 340 second before looping to ensure continuous pgrsUpdates. */ | |
| 341 result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes); | |
| 342 if(result == CURLE_AGAIN) | |
| 343 /* socket buffer drained, return */ | |
| 344 return CURLE_OK; | |
| 345 | |
| 346 if(Curl_pgrsUpdate(conn)) | |
| 347 return CURLE_ABORTED_BY_CALLBACK; | |
| 348 | |
| 349 if(result) { | |
| 350 s->keepon = FALSE; | |
| 351 break; | |
| 352 } | |
| 353 else if(gotbytes <= 0) { | |
| 354 if(data->set.proxyauth && data->state.authproxy.avail) { | |
| 355 /* proxy auth was requested and there was proxy auth available, | |
| 356 then deem this as "mere" proxy disconnect */ | |
| 357 conn->bits.proxy_connect_closed = TRUE; | |
| 358 infof(data, "Proxy CONNECT connection closed\n"); | |
| 359 } | |
| 360 else { | |
| 361 error = SELECT_ERROR; | |
| 362 failf(data, "Proxy CONNECT aborted"); | |
| 363 } | |
| 364 s->keepon = FALSE; | |
| 365 break; | |
| 366 } | |
| 367 | |
| 368 | |
| 369 if(s->keepon > TRUE) { | |
| 370 /* This means we are currently ignoring a response-body */ | |
| 371 | |
| 372 s->ptr = s->connect_buffer; | |
| 373 if(s->cl) { | |
| 374 /* A Content-Length based body: simply count down the counter | |
| 375 and make sure to break out of the loop when we're done! */ | |
| 376 s->cl--; | |
| 377 if(s->cl <= 0) { | |
| 378 s->keepon = FALSE; | |
| 379 s->tunnel_state = TUNNEL_COMPLETE; | |
| 380 break; | |
| 381 } | |
| 382 } | |
| 383 else { | |
| 384 /* chunked-encoded body, so we need to do the chunked dance | |
| 385 properly to know when the end of the body is reached */ | |
| 386 CHUNKcode r; | |
| 387 ssize_t tookcareof = 0; | |
| 388 | |
| 389 /* now parse the chunked piece of data so that we can | |
| 390 properly tell when the stream ends */ | |
| 391 r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof); | |
| 392 if(r == CHUNKE_STOP) { | |
| 393 /* we're done reading chunks! */ | |
| 394 infof(data, "chunk reading DONE\n"); | |
| 395 s->keepon = FALSE; | |
| 396 /* we did the full CONNECT treatment, go COMPLETE */ | |
| 397 s->tunnel_state = TUNNEL_COMPLETE; | |
| 398 } | |
| 399 } | |
| 400 continue; | |
| 401 } | |
| 402 | |
| 403 s->perline++; /* amount of bytes in this line so far */ | |
| 404 | |
| 405 /* if this is not the end of a header line then continue */ | |
| 406 if(*s->ptr != 0x0a) { | |
| 407 s->ptr++; | |
| 408 continue; | |
| 409 } | |
| 410 | |
| 411 /* convert from the network encoding */ | |
| 412 result = Curl_convert_from_network(data, s->line_start, | |
| 413 (size_t)s->perline); | |
| 414 /* Curl_convert_from_network calls failf if unsuccessful */ | |
| 415 if(result) | |
| 416 return result; | |
| 417 | |
| 418 /* output debug if that is requested */ | |
| 419 if(data->set.verbose) | |
| 420 Curl_debug(data, CURLINFO_HEADER_IN, | |
| 421 s->line_start, (size_t)s->perline); | |
| 422 | |
| 423 if(!data->set.suppress_connect_headers) { | |
| 424 /* send the header to the callback */ | |
| 425 int writetype = CLIENTWRITE_HEADER; | |
| 426 if(data->set.include_header) | |
| 427 writetype |= CLIENTWRITE_BODY; | |
| 428 | |
| 429 result = Curl_client_write(conn, writetype, | |
| 430 s->line_start, s->perline); | |
| 431 if(result) | |
| 432 return result; | |
| 433 } | |
| 434 | |
| 435 data->info.header_size += (long)s->perline; | |
| 436 data->req.headerbytecount += (long)s->perline; | |
| 437 | |
| 438 /* Newlines are CRLF, so the CR is ignored as the line isn't | |
| 439 really terminated until the LF comes. Treat a following CR | |
| 440 as end-of-headers as well.*/ | |
| 441 | |
| 442 if(('\r' == s->line_start[0]) || | |
| 443 ('\n' == s->line_start[0])) { | |
| 444 /* end of response-headers from the proxy */ | |
| 445 s->ptr = s->connect_buffer; | |
| 446 if((407 == k->httpcode) && !data->state.authproblem) { | |
| 447 /* If we get a 407 response code with content length | |
| 448 when we have no auth problem, we must ignore the | |
| 449 whole response-body */ | |
| 450 s->keepon = 2; | |
| 451 | |
| 452 if(s->cl) { | |
| 453 infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T | |
| 454 " bytes of response-body\n", s->cl); | |
| 455 } | |
| 456 else if(s->chunked_encoding) { | |
| 457 CHUNKcode r; | |
| 458 | |
| 459 infof(data, "Ignore chunked response-body\n"); | |
| 460 | |
| 461 /* We set ignorebody true here since the chunked | |
| 462 decoder function will acknowledge that. Pay | |
| 463 attention so that this is cleared again when this | |
| 464 function returns! */ | |
| 465 k->ignorebody = TRUE; | |
| 466 | |
| 467 if(s->line_start[1] == '\n') { | |
| 468 /* this can only be a LF if the letter at index 0 | |
| 469 was a CR */ | |
| 470 s->line_start++; | |
| 471 } | |
| 472 | |
| 473 /* now parse the chunked piece of data so that we can | |
| 474 properly tell when the stream ends */ | |
| 475 r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes); | |
| 476 if(r == CHUNKE_STOP) { | |
| 477 /* we're done reading chunks! */ | |
| 478 infof(data, "chunk reading DONE\n"); | |
| 479 s->keepon = FALSE; | |
| 480 /* we did the full CONNECT treatment, go to COMPLETE */ | |
| 481 s->tunnel_state = TUNNEL_COMPLETE; | |
| 482 } | |
| 483 } | |
| 484 else { | |
| 485 /* without content-length or chunked encoding, we | |
| 486 can't keep the connection alive since the close is | |
| 487 the end signal so we bail out at once instead */ | |
| 488 s->keepon = FALSE; | |
| 489 } | |
| 490 } | |
| 491 else | |
| 492 s->keepon = FALSE; | |
| 493 if(!s->cl) | |
| 494 /* we did the full CONNECT treatment, go to COMPLETE */ | |
| 495 s->tunnel_state = TUNNEL_COMPLETE; | |
| 496 continue; | |
| 497 } | |
| 498 | |
| 499 s->line_start[s->perline] = 0; /* zero terminate the buffer */ | |
| 500 if((checkprefix("WWW-Authenticate:", s->line_start) && | |
| 501 (401 == k->httpcode)) || | |
| 502 (checkprefix("Proxy-authenticate:", s->line_start) && | |
| 503 (407 == k->httpcode))) { | |
| 504 | |
| 505 bool proxy = (k->httpcode == 407) ? TRUE : FALSE; | |
| 506 char *auth = Curl_copy_header_value(s->line_start); | |
| 507 if(!auth) | |
| 508 return CURLE_OUT_OF_MEMORY; | |
| 509 | |
| 510 result = Curl_http_input_auth(conn, proxy, auth); | |
| 511 | |
| 512 free(auth); | |
| 513 | |
| 514 if(result) | |
| 515 return result; | |
| 516 } | |
| 517 else if(checkprefix("Content-Length:", s->line_start)) { | |
| 518 if(k->httpcode/100 == 2) { | |
| 519 /* A client MUST ignore any Content-Length or Transfer-Encoding | |
| 520 header fields received in a successful response to CONNECT. | |
| 521 "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ | |
| 522 infof(data, "Ignoring Content-Length in CONNECT %03d response\n", | |
| 523 k->httpcode); | |
| 524 } | |
| 525 else { | |
| 526 (void)curlx_strtoofft(s->line_start + | |
| 527 strlen("Content-Length:"), NULL, 10, &s->cl); | |
| 528 } | |
| 529 } | |
| 530 else if(Curl_compareheader(s->line_start, "Connection:", "close")) | |
| 531 s->close_connection = TRUE; | |
| 532 else if(checkprefix("Transfer-Encoding:", s->line_start)) { | |
| 533 if(k->httpcode/100 == 2) { | |
| 534 /* A client MUST ignore any Content-Length or Transfer-Encoding | |
| 535 header fields received in a successful response to CONNECT. | |
| 536 "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ | |
| 537 infof(data, "Ignoring Transfer-Encoding in " | |
| 538 "CONNECT %03d response\n", k->httpcode); | |
| 539 } | |
| 540 else if(Curl_compareheader(s->line_start, | |
| 541 "Transfer-Encoding:", "chunked")) { | |
| 542 infof(data, "CONNECT responded chunked\n"); | |
| 543 s->chunked_encoding = TRUE; | |
| 544 /* init our chunky engine */ | |
| 545 Curl_httpchunk_init(conn); | |
| 546 } | |
| 547 } | |
| 548 else if(Curl_compareheader(s->line_start, | |
| 549 "Proxy-Connection:", "close")) | |
| 550 s->close_connection = TRUE; | |
| 551 else if(2 == sscanf(s->line_start, "HTTP/1.%d %d", | |
| 552 &subversion, | |
| 553 &k->httpcode)) { | |
| 554 /* store the HTTP code from the proxy */ | |
| 555 data->info.httpproxycode = k->httpcode; | |
| 556 } | |
| 557 | |
| 558 s->perline = 0; /* line starts over here */ | |
| 559 s->ptr = s->connect_buffer; | |
| 560 s->line_start = s->ptr; | |
| 561 } /* while there's buffer left and loop is requested */ | |
| 562 | |
| 563 if(Curl_pgrsUpdate(conn)) | |
| 564 return CURLE_ABORTED_BY_CALLBACK; | |
| 565 | |
| 566 if(error) | |
| 567 return CURLE_RECV_ERROR; | |
| 568 | |
| 569 if(data->info.httpproxycode/100 != 2) { | |
| 570 /* Deal with the possibly already received authenticate | |
| 571 headers. 'newurl' is set to a new URL if we must loop. */ | |
| 572 result = Curl_http_auth_act(conn); | |
| 573 if(result) | |
| 574 return result; | |
| 575 | |
| 576 if(conn->bits.close) | |
| 577 /* the connection has been marked for closure, most likely in the | |
| 578 Curl_http_auth_act() function and thus we can kill it at once | |
| 579 below */ | |
| 580 s->close_connection = TRUE; | |
| 581 } | |
| 582 | |
| 583 if(s->close_connection && data->req.newurl) { | |
| 584 /* Connection closed by server. Don't use it anymore */ | |
| 585 Curl_closesocket(conn, conn->sock[sockindex]); | |
| 586 conn->sock[sockindex] = CURL_SOCKET_BAD; | |
| 587 break; | |
| 588 } | |
| 589 } /* END READING RESPONSE PHASE */ | |
| 590 | |
| 591 /* If we are supposed to continue and request a new URL, which basically | |
| 592 * means the HTTP authentication is still going on so if the tunnel | |
| 593 * is complete we start over in INIT state */ | |
| 594 if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) { | |
| 595 connect_init(conn, TRUE); /* reinit */ | |
| 596 } | |
| 597 | |
| 598 } while(data->req.newurl); | |
| 599 | |
| 600 if(data->info.httpproxycode/100 != 2) { | |
| 601 if(s->close_connection && data->req.newurl) { | |
| 602 conn->bits.proxy_connect_closed = TRUE; | |
| 603 infof(data, "Connect me again please\n"); | |
| 604 connect_done(conn); | |
| 605 } | |
| 606 else { | |
| 607 free(data->req.newurl); | |
| 608 data->req.newurl = NULL; | |
| 609 /* failure, close this connection to avoid re-use */ | |
| 610 streamclose(conn, "proxy CONNECT failure"); | |
| 611 Curl_closesocket(conn, conn->sock[sockindex]); | |
| 612 conn->sock[sockindex] = CURL_SOCKET_BAD; | |
| 613 } | |
| 614 | |
| 615 /* to back to init state */ | |
| 616 s->tunnel_state = TUNNEL_INIT; | |
| 617 | |
| 618 if(conn->bits.proxy_connect_closed) | |
| 619 /* this is not an error, just part of the connection negotiation */ | |
| 620 return CURLE_OK; | |
| 621 failf(data, "Received HTTP code %d from proxy after CONNECT", | |
| 622 data->req.httpcode); | |
| 623 return CURLE_RECV_ERROR; | |
| 624 } | |
| 625 | |
| 626 s->tunnel_state = TUNNEL_COMPLETE; | |
| 627 | |
| 628 /* If a proxy-authorization header was used for the proxy, then we should | |
| 629 make sure that it isn't accidentally used for the document request | |
| 630 after we've connected. So let's free and clear it here. */ | |
| 631 Curl_safefree(conn->allocptr.proxyuserpwd); | |
| 632 conn->allocptr.proxyuserpwd = NULL; | |
| 633 | |
| 634 data->state.authproxy.done = TRUE; | |
| 635 data->state.authproxy.multipass = FALSE; | |
| 636 | |
| 637 infof(data, "Proxy replied %d to CONNECT request\n", | |
| 638 data->info.httpproxycode); | |
| 639 data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ | |
| 640 conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the | |
| 641 document request */ | |
| 642 return CURLE_OK; | |
| 643 } | |
| 644 | |
| 645 void Curl_connect_free(struct Curl_easy *data) | |
| 646 { | |
| 647 struct connectdata *conn = data->conn; | |
| 648 struct http_connect_state *s = conn->connect_state; | |
| 649 if(s) { | |
| 650 free(s); | |
| 651 conn->connect_state = NULL; | |
| 652 } | |
| 653 } | |
| 654 | |
| 655 /* | |
| 656 * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This | |
| 657 * function will issue the necessary commands to get a seamless tunnel through | |
| 658 * this proxy. After that, the socket can be used just as a normal socket. | |
| 659 */ | |
| 660 | |
| 661 CURLcode Curl_proxyCONNECT(struct connectdata *conn, | |
| 662 int sockindex, | |
| 663 const char *hostname, | |
| 664 int remote_port) | |
| 665 { | |
| 666 CURLcode result; | |
| 667 if(!conn->connect_state) { | |
| 668 result = connect_init(conn, FALSE); | |
| 669 if(result) | |
| 670 return result; | |
| 671 } | |
| 672 result = CONNECT(conn, sockindex, hostname, remote_port); | |
| 673 | |
| 674 if(result || Curl_connect_complete(conn)) | |
| 675 connect_done(conn); | |
| 676 | |
| 677 return result; | |
| 678 } | |
| 679 | |
| 680 #else | |
| 681 void Curl_connect_free(struct Curl_easy *data) | |
| 682 { | |
| 683 (void)data; | |
| 684 } | |
| 685 | |
| 686 #endif /* CURL_DISABLE_PROXY */ |
