Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/http.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 #ifndef CURL_DISABLE_HTTP | |
| 26 | |
| 27 #ifdef HAVE_NETINET_IN_H | |
| 28 #include <netinet/in.h> | |
| 29 #endif | |
| 30 | |
| 31 #ifdef HAVE_NETDB_H | |
| 32 #include <netdb.h> | |
| 33 #endif | |
| 34 #ifdef HAVE_ARPA_INET_H | |
| 35 #include <arpa/inet.h> | |
| 36 #endif | |
| 37 #ifdef HAVE_NET_IF_H | |
| 38 #include <net/if.h> | |
| 39 #endif | |
| 40 #ifdef HAVE_SYS_IOCTL_H | |
| 41 #include <sys/ioctl.h> | |
| 42 #endif | |
| 43 | |
| 44 #ifdef HAVE_SYS_PARAM_H | |
| 45 #include <sys/param.h> | |
| 46 #endif | |
| 47 | |
| 48 #include "urldata.h" | |
| 49 #include <curl/curl.h> | |
| 50 #include "transfer.h" | |
| 51 #include "sendf.h" | |
| 52 #include "formdata.h" | |
| 53 #include "mime.h" | |
| 54 #include "progress.h" | |
| 55 #include "curl_base64.h" | |
| 56 #include "cookie.h" | |
| 57 #include "vauth/vauth.h" | |
| 58 #include "vtls/vtls.h" | |
| 59 #include "http_digest.h" | |
| 60 #include "http_ntlm.h" | |
| 61 #include "curl_ntlm_wb.h" | |
| 62 #include "http_negotiate.h" | |
| 63 #include "url.h" | |
| 64 #include "share.h" | |
| 65 #include "hostip.h" | |
| 66 #include "http.h" | |
| 67 #include "select.h" | |
| 68 #include "parsedate.h" /* for the week day and month names */ | |
| 69 #include "strtoofft.h" | |
| 70 #include "multiif.h" | |
| 71 #include "strcase.h" | |
| 72 #include "content_encoding.h" | |
| 73 #include "http_proxy.h" | |
| 74 #include "warnless.h" | |
| 75 #include "non-ascii.h" | |
| 76 #include "http2.h" | |
| 77 #include "connect.h" | |
| 78 #include "strdup.h" | |
| 79 #include "altsvc.h" | |
| 80 | |
| 81 /* The last 3 #include files should be in this order */ | |
| 82 #include "curl_printf.h" | |
| 83 #include "curl_memory.h" | |
| 84 #include "memdebug.h" | |
| 85 | |
| 86 /* | |
| 87 * Forward declarations. | |
| 88 */ | |
| 89 | |
| 90 static int http_getsock_do(struct connectdata *conn, | |
| 91 curl_socket_t *socks); | |
| 92 static int http_should_fail(struct connectdata *conn); | |
| 93 | |
| 94 #ifndef CURL_DISABLE_PROXY | |
| 95 static CURLcode add_haproxy_protocol_header(struct connectdata *conn); | |
| 96 #endif | |
| 97 | |
| 98 #ifdef USE_SSL | |
| 99 static CURLcode https_connecting(struct connectdata *conn, bool *done); | |
| 100 static int https_getsock(struct connectdata *conn, | |
| 101 curl_socket_t *socks); | |
| 102 #else | |
| 103 #define https_connecting(x,y) CURLE_COULDNT_CONNECT | |
| 104 #endif | |
| 105 static CURLcode http_setup_conn(struct connectdata *conn); | |
| 106 | |
| 107 /* | |
| 108 * HTTP handler interface. | |
| 109 */ | |
| 110 const struct Curl_handler Curl_handler_http = { | |
| 111 "HTTP", /* scheme */ | |
| 112 http_setup_conn, /* setup_connection */ | |
| 113 Curl_http, /* do_it */ | |
| 114 Curl_http_done, /* done */ | |
| 115 ZERO_NULL, /* do_more */ | |
| 116 Curl_http_connect, /* connect_it */ | |
| 117 ZERO_NULL, /* connecting */ | |
| 118 ZERO_NULL, /* doing */ | |
| 119 ZERO_NULL, /* proto_getsock */ | |
| 120 http_getsock_do, /* doing_getsock */ | |
| 121 ZERO_NULL, /* domore_getsock */ | |
| 122 ZERO_NULL, /* perform_getsock */ | |
| 123 ZERO_NULL, /* disconnect */ | |
| 124 ZERO_NULL, /* readwrite */ | |
| 125 ZERO_NULL, /* connection_check */ | |
| 126 PORT_HTTP, /* defport */ | |
| 127 CURLPROTO_HTTP, /* protocol */ | |
| 128 PROTOPT_CREDSPERREQUEST /* flags */ | |
| 129 }; | |
| 130 | |
| 131 #ifdef USE_SSL | |
| 132 /* | |
| 133 * HTTPS handler interface. | |
| 134 */ | |
| 135 const struct Curl_handler Curl_handler_https = { | |
| 136 "HTTPS", /* scheme */ | |
| 137 http_setup_conn, /* setup_connection */ | |
| 138 Curl_http, /* do_it */ | |
| 139 Curl_http_done, /* done */ | |
| 140 ZERO_NULL, /* do_more */ | |
| 141 Curl_http_connect, /* connect_it */ | |
| 142 https_connecting, /* connecting */ | |
| 143 ZERO_NULL, /* doing */ | |
| 144 https_getsock, /* proto_getsock */ | |
| 145 http_getsock_do, /* doing_getsock */ | |
| 146 ZERO_NULL, /* domore_getsock */ | |
| 147 ZERO_NULL, /* perform_getsock */ | |
| 148 ZERO_NULL, /* disconnect */ | |
| 149 ZERO_NULL, /* readwrite */ | |
| 150 ZERO_NULL, /* connection_check */ | |
| 151 PORT_HTTPS, /* defport */ | |
| 152 CURLPROTO_HTTPS, /* protocol */ | |
| 153 PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ | |
| 154 }; | |
| 155 #endif | |
| 156 | |
| 157 static CURLcode http_setup_conn(struct connectdata *conn) | |
| 158 { | |
| 159 /* allocate the HTTP-specific struct for the Curl_easy, only to survive | |
| 160 during this request */ | |
| 161 struct HTTP *http; | |
| 162 struct Curl_easy *data = conn->data; | |
| 163 DEBUGASSERT(data->req.protop == NULL); | |
| 164 | |
| 165 http = calloc(1, sizeof(struct HTTP)); | |
| 166 if(!http) | |
| 167 return CURLE_OUT_OF_MEMORY; | |
| 168 | |
| 169 Curl_mime_initpart(&http->form, conn->data); | |
| 170 data->req.protop = http; | |
| 171 | |
| 172 if(data->set.httpversion == CURL_HTTP_VERSION_3) { | |
| 173 if(conn->handler->flags & PROTOPT_SSL) | |
| 174 /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does | |
| 175 the QUIC dance. */ | |
| 176 conn->transport = TRNSPRT_QUIC; | |
| 177 else { | |
| 178 failf(data, "HTTP/3 requested for non-HTTPS URL"); | |
| 179 return CURLE_URL_MALFORMAT; | |
| 180 } | |
| 181 } | |
| 182 else { | |
| 183 if(!CONN_INUSE(conn)) | |
| 184 /* if not already multi-using, setup connection details */ | |
| 185 Curl_http2_setup_conn(conn); | |
| 186 Curl_http2_setup_req(data); | |
| 187 } | |
| 188 return CURLE_OK; | |
| 189 } | |
| 190 | |
| 191 #ifndef CURL_DISABLE_PROXY | |
| 192 /* | |
| 193 * checkProxyHeaders() checks the linked list of custom proxy headers | |
| 194 * if proxy headers are not available, then it will lookup into http header | |
| 195 * link list | |
| 196 * | |
| 197 * It takes a connectdata struct as input instead of the Curl_easy simply to | |
| 198 * know if this is a proxy request or not, as it then might check a different | |
| 199 * header list. Provide the header prefix without colon!. | |
| 200 */ | |
| 201 char *Curl_checkProxyheaders(const struct connectdata *conn, | |
| 202 const char *thisheader) | |
| 203 { | |
| 204 struct curl_slist *head; | |
| 205 size_t thislen = strlen(thisheader); | |
| 206 struct Curl_easy *data = conn->data; | |
| 207 | |
| 208 for(head = (conn->bits.proxy && data->set.sep_headers) ? | |
| 209 data->set.proxyheaders : data->set.headers; | |
| 210 head; head = head->next) { | |
| 211 if(strncasecompare(head->data, thisheader, thislen) && | |
| 212 Curl_headersep(head->data[thislen])) | |
| 213 return head->data; | |
| 214 } | |
| 215 | |
| 216 return NULL; | |
| 217 } | |
| 218 #else | |
| 219 /* disabled */ | |
| 220 #define Curl_checkProxyheaders(x,y) NULL | |
| 221 #endif | |
| 222 | |
| 223 /* | |
| 224 * Strip off leading and trailing whitespace from the value in the | |
| 225 * given HTTP header line and return a strdupped copy. Returns NULL in | |
| 226 * case of allocation failure. Returns an empty string if the header value | |
| 227 * consists entirely of whitespace. | |
| 228 */ | |
| 229 char *Curl_copy_header_value(const char *header) | |
| 230 { | |
| 231 const char *start; | |
| 232 const char *end; | |
| 233 char *value; | |
| 234 size_t len; | |
| 235 | |
| 236 /* Find the end of the header name */ | |
| 237 while(*header && (*header != ':')) | |
| 238 ++header; | |
| 239 | |
| 240 if(*header) | |
| 241 /* Skip over colon */ | |
| 242 ++header; | |
| 243 | |
| 244 /* Find the first non-space letter */ | |
| 245 start = header; | |
| 246 while(*start && ISSPACE(*start)) | |
| 247 start++; | |
| 248 | |
| 249 /* data is in the host encoding so | |
| 250 use '\r' and '\n' instead of 0x0d and 0x0a */ | |
| 251 end = strchr(start, '\r'); | |
| 252 if(!end) | |
| 253 end = strchr(start, '\n'); | |
| 254 if(!end) | |
| 255 end = strchr(start, '\0'); | |
| 256 if(!end) | |
| 257 return NULL; | |
| 258 | |
| 259 /* skip all trailing space letters */ | |
| 260 while((end > start) && ISSPACE(*end)) | |
| 261 end--; | |
| 262 | |
| 263 /* get length of the type */ | |
| 264 len = end - start + 1; | |
| 265 | |
| 266 value = malloc(len + 1); | |
| 267 if(!value) | |
| 268 return NULL; | |
| 269 | |
| 270 memcpy(value, start, len); | |
| 271 value[len] = 0; /* zero terminate */ | |
| 272 | |
| 273 return value; | |
| 274 } | |
| 275 | |
| 276 #ifndef CURL_DISABLE_HTTP_AUTH | |
| 277 /* | |
| 278 * http_output_basic() sets up an Authorization: header (or the proxy version) | |
| 279 * for HTTP Basic authentication. | |
| 280 * | |
| 281 * Returns CURLcode. | |
| 282 */ | |
| 283 static CURLcode http_output_basic(struct connectdata *conn, bool proxy) | |
| 284 { | |
| 285 size_t size = 0; | |
| 286 char *authorization = NULL; | |
| 287 struct Curl_easy *data = conn->data; | |
| 288 char **userp; | |
| 289 const char *user; | |
| 290 const char *pwd; | |
| 291 CURLcode result; | |
| 292 char *out; | |
| 293 | |
| 294 if(proxy) { | |
| 295 userp = &conn->allocptr.proxyuserpwd; | |
| 296 user = conn->http_proxy.user; | |
| 297 pwd = conn->http_proxy.passwd; | |
| 298 } | |
| 299 else { | |
| 300 userp = &conn->allocptr.userpwd; | |
| 301 user = conn->user; | |
| 302 pwd = conn->passwd; | |
| 303 } | |
| 304 | |
| 305 out = aprintf("%s:%s", user, pwd); | |
| 306 if(!out) | |
| 307 return CURLE_OUT_OF_MEMORY; | |
| 308 | |
| 309 result = Curl_base64_encode(data, out, strlen(out), &authorization, &size); | |
| 310 if(result) | |
| 311 goto fail; | |
| 312 | |
| 313 if(!authorization) { | |
| 314 result = CURLE_REMOTE_ACCESS_DENIED; | |
| 315 goto fail; | |
| 316 } | |
| 317 | |
| 318 free(*userp); | |
| 319 *userp = aprintf("%sAuthorization: Basic %s\r\n", | |
| 320 proxy ? "Proxy-" : "", | |
| 321 authorization); | |
| 322 free(authorization); | |
| 323 if(!*userp) { | |
| 324 result = CURLE_OUT_OF_MEMORY; | |
| 325 goto fail; | |
| 326 } | |
| 327 | |
| 328 fail: | |
| 329 free(out); | |
| 330 return result; | |
| 331 } | |
| 332 | |
| 333 /* | |
| 334 * http_output_bearer() sets up an Authorization: header | |
| 335 * for HTTP Bearer authentication. | |
| 336 * | |
| 337 * Returns CURLcode. | |
| 338 */ | |
| 339 static CURLcode http_output_bearer(struct connectdata *conn) | |
| 340 { | |
| 341 char **userp; | |
| 342 CURLcode result = CURLE_OK; | |
| 343 | |
| 344 userp = &conn->allocptr.userpwd; | |
| 345 free(*userp); | |
| 346 *userp = aprintf("Authorization: Bearer %s\r\n", | |
| 347 conn->oauth_bearer); | |
| 348 | |
| 349 if(!*userp) { | |
| 350 result = CURLE_OUT_OF_MEMORY; | |
| 351 goto fail; | |
| 352 } | |
| 353 | |
| 354 fail: | |
| 355 return result; | |
| 356 } | |
| 357 | |
| 358 #endif | |
| 359 | |
| 360 /* pickoneauth() selects the most favourable authentication method from the | |
| 361 * ones available and the ones we want. | |
| 362 * | |
| 363 * return TRUE if one was picked | |
| 364 */ | |
| 365 static bool pickoneauth(struct auth *pick, unsigned long mask) | |
| 366 { | |
| 367 bool picked; | |
| 368 /* only deal with authentication we want */ | |
| 369 unsigned long avail = pick->avail & pick->want & mask; | |
| 370 picked = TRUE; | |
| 371 | |
| 372 /* The order of these checks is highly relevant, as this will be the order | |
| 373 of preference in case of the existence of multiple accepted types. */ | |
| 374 if(avail & CURLAUTH_NEGOTIATE) | |
| 375 pick->picked = CURLAUTH_NEGOTIATE; | |
| 376 else if(avail & CURLAUTH_BEARER) | |
| 377 pick->picked = CURLAUTH_BEARER; | |
| 378 else if(avail & CURLAUTH_DIGEST) | |
| 379 pick->picked = CURLAUTH_DIGEST; | |
| 380 else if(avail & CURLAUTH_NTLM) | |
| 381 pick->picked = CURLAUTH_NTLM; | |
| 382 else if(avail & CURLAUTH_NTLM_WB) | |
| 383 pick->picked = CURLAUTH_NTLM_WB; | |
| 384 else if(avail & CURLAUTH_BASIC) | |
| 385 pick->picked = CURLAUTH_BASIC; | |
| 386 else { | |
| 387 pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ | |
| 388 picked = FALSE; | |
| 389 } | |
| 390 pick->avail = CURLAUTH_NONE; /* clear it here */ | |
| 391 | |
| 392 return picked; | |
| 393 } | |
| 394 | |
| 395 /* | |
| 396 * http_perhapsrewind() | |
| 397 * | |
| 398 * If we are doing POST or PUT { | |
| 399 * If we have more data to send { | |
| 400 * If we are doing NTLM { | |
| 401 * Keep sending since we must not disconnect | |
| 402 * } | |
| 403 * else { | |
| 404 * If there is more than just a little data left to send, close | |
| 405 * the current connection by force. | |
| 406 * } | |
| 407 * } | |
| 408 * If we have sent any data { | |
| 409 * If we don't have track of all the data { | |
| 410 * call app to tell it to rewind | |
| 411 * } | |
| 412 * else { | |
| 413 * rewind internally so that the operation can restart fine | |
| 414 * } | |
| 415 * } | |
| 416 * } | |
| 417 */ | |
| 418 static CURLcode http_perhapsrewind(struct connectdata *conn) | |
| 419 { | |
| 420 struct Curl_easy *data = conn->data; | |
| 421 struct HTTP *http = data->req.protop; | |
| 422 curl_off_t bytessent; | |
| 423 curl_off_t expectsend = -1; /* default is unknown */ | |
| 424 | |
| 425 if(!http) | |
| 426 /* If this is still NULL, we have not reach very far and we can safely | |
| 427 skip this rewinding stuff */ | |
| 428 return CURLE_OK; | |
| 429 | |
| 430 switch(data->set.httpreq) { | |
| 431 case HTTPREQ_GET: | |
| 432 case HTTPREQ_HEAD: | |
| 433 return CURLE_OK; | |
| 434 default: | |
| 435 break; | |
| 436 } | |
| 437 | |
| 438 bytessent = data->req.writebytecount; | |
| 439 | |
| 440 if(conn->bits.authneg) { | |
| 441 /* This is a state where we are known to be negotiating and we don't send | |
| 442 any data then. */ | |
| 443 expectsend = 0; | |
| 444 } | |
| 445 else if(!conn->bits.protoconnstart) { | |
| 446 /* HTTP CONNECT in progress: there is no body */ | |
| 447 expectsend = 0; | |
| 448 } | |
| 449 else { | |
| 450 /* figure out how much data we are expected to send */ | |
| 451 switch(data->set.httpreq) { | |
| 452 case HTTPREQ_POST: | |
| 453 if(data->state.infilesize != -1) | |
| 454 expectsend = data->state.infilesize; | |
| 455 break; | |
| 456 case HTTPREQ_PUT: | |
| 457 if(data->state.infilesize != -1) | |
| 458 expectsend = data->state.infilesize; | |
| 459 break; | |
| 460 case HTTPREQ_POST_FORM: | |
| 461 case HTTPREQ_POST_MIME: | |
| 462 expectsend = http->postsize; | |
| 463 break; | |
| 464 default: | |
| 465 break; | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 conn->bits.rewindaftersend = FALSE; /* default */ | |
| 470 | |
| 471 if((expectsend == -1) || (expectsend > bytessent)) { | |
| 472 #if defined(USE_NTLM) | |
| 473 /* There is still data left to send */ | |
| 474 if((data->state.authproxy.picked == CURLAUTH_NTLM) || | |
| 475 (data->state.authhost.picked == CURLAUTH_NTLM) || | |
| 476 (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || | |
| 477 (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { | |
| 478 if(((expectsend - bytessent) < 2000) || | |
| 479 (conn->http_ntlm_state != NTLMSTATE_NONE) || | |
| 480 (conn->proxy_ntlm_state != NTLMSTATE_NONE)) { | |
| 481 /* The NTLM-negotiation has started *OR* there is just a little (<2K) | |
| 482 data left to send, keep on sending. */ | |
| 483 | |
| 484 /* rewind data when completely done sending! */ | |
| 485 if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { | |
| 486 conn->bits.rewindaftersend = TRUE; | |
| 487 infof(data, "Rewind stream after send\n"); | |
| 488 } | |
| 489 | |
| 490 return CURLE_OK; | |
| 491 } | |
| 492 | |
| 493 if(conn->bits.close) | |
| 494 /* this is already marked to get closed */ | |
| 495 return CURLE_OK; | |
| 496 | |
| 497 infof(data, "NTLM send, close instead of sending %" | |
| 498 CURL_FORMAT_CURL_OFF_T " bytes\n", | |
| 499 (curl_off_t)(expectsend - bytessent)); | |
| 500 } | |
| 501 #endif | |
| 502 #if defined(USE_SPNEGO) | |
| 503 /* There is still data left to send */ | |
| 504 if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) || | |
| 505 (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) { | |
| 506 if(((expectsend - bytessent) < 2000) || | |
| 507 (conn->http_negotiate_state != GSS_AUTHNONE) || | |
| 508 (conn->proxy_negotiate_state != GSS_AUTHNONE)) { | |
| 509 /* The NEGOTIATE-negotiation has started *OR* | |
| 510 there is just a little (<2K) data left to send, keep on sending. */ | |
| 511 | |
| 512 /* rewind data when completely done sending! */ | |
| 513 if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { | |
| 514 conn->bits.rewindaftersend = TRUE; | |
| 515 infof(data, "Rewind stream after send\n"); | |
| 516 } | |
| 517 | |
| 518 return CURLE_OK; | |
| 519 } | |
| 520 | |
| 521 if(conn->bits.close) | |
| 522 /* this is already marked to get closed */ | |
| 523 return CURLE_OK; | |
| 524 | |
| 525 infof(data, "NEGOTIATE send, close instead of sending %" | |
| 526 CURL_FORMAT_CURL_OFF_T " bytes\n", | |
| 527 (curl_off_t)(expectsend - bytessent)); | |
| 528 } | |
| 529 #endif | |
| 530 | |
| 531 /* This is not NEGOTIATE/NTLM or many bytes left to send: close */ | |
| 532 streamclose(conn, "Mid-auth HTTP and much data left to send"); | |
| 533 data->req.size = 0; /* don't download any more than 0 bytes */ | |
| 534 | |
| 535 /* There still is data left to send, but this connection is marked for | |
| 536 closure so we can safely do the rewind right now */ | |
| 537 } | |
| 538 | |
| 539 if(bytessent) | |
| 540 /* we rewind now at once since if we already sent something */ | |
| 541 return Curl_readrewind(conn); | |
| 542 | |
| 543 return CURLE_OK; | |
| 544 } | |
| 545 | |
| 546 /* | |
| 547 * Curl_http_auth_act() gets called when all HTTP headers have been received | |
| 548 * and it checks what authentication methods that are available and decides | |
| 549 * which one (if any) to use. It will set 'newurl' if an auth method was | |
| 550 * picked. | |
| 551 */ | |
| 552 | |
| 553 CURLcode Curl_http_auth_act(struct connectdata *conn) | |
| 554 { | |
| 555 struct Curl_easy *data = conn->data; | |
| 556 bool pickhost = FALSE; | |
| 557 bool pickproxy = FALSE; | |
| 558 CURLcode result = CURLE_OK; | |
| 559 unsigned long authmask = ~0ul; | |
| 560 | |
| 561 if(!conn->oauth_bearer) | |
| 562 authmask &= (unsigned long)~CURLAUTH_BEARER; | |
| 563 | |
| 564 if(100 <= data->req.httpcode && 199 >= data->req.httpcode) | |
| 565 /* this is a transient response code, ignore */ | |
| 566 return CURLE_OK; | |
| 567 | |
| 568 if(data->state.authproblem) | |
| 569 return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; | |
| 570 | |
| 571 if((conn->bits.user_passwd || conn->oauth_bearer) && | |
| 572 ((data->req.httpcode == 401) || | |
| 573 (conn->bits.authneg && data->req.httpcode < 300))) { | |
| 574 pickhost = pickoneauth(&data->state.authhost, authmask); | |
| 575 if(!pickhost) | |
| 576 data->state.authproblem = TRUE; | |
| 577 if(data->state.authhost.picked == CURLAUTH_NTLM && | |
| 578 conn->httpversion > 11) { | |
| 579 infof(data, "Forcing HTTP/1.1 for NTLM"); | |
| 580 connclose(conn, "Force HTTP/1.1 connection"); | |
| 581 conn->data->set.httpversion = CURL_HTTP_VERSION_1_1; | |
| 582 } | |
| 583 } | |
| 584 if(conn->bits.proxy_user_passwd && | |
| 585 ((data->req.httpcode == 407) || | |
| 586 (conn->bits.authneg && data->req.httpcode < 300))) { | |
| 587 pickproxy = pickoneauth(&data->state.authproxy, | |
| 588 authmask & ~CURLAUTH_BEARER); | |
| 589 if(!pickproxy) | |
| 590 data->state.authproblem = TRUE; | |
| 591 } | |
| 592 | |
| 593 if(pickhost || pickproxy) { | |
| 594 if((data->set.httpreq != HTTPREQ_GET) && | |
| 595 (data->set.httpreq != HTTPREQ_HEAD) && | |
| 596 !conn->bits.rewindaftersend) { | |
| 597 result = http_perhapsrewind(conn); | |
| 598 if(result) | |
| 599 return result; | |
| 600 } | |
| 601 /* In case this is GSS auth, the newurl field is already allocated so | |
| 602 we must make sure to free it before allocating a new one. As figured | |
| 603 out in bug #2284386 */ | |
| 604 Curl_safefree(data->req.newurl); | |
| 605 data->req.newurl = strdup(data->change.url); /* clone URL */ | |
| 606 if(!data->req.newurl) | |
| 607 return CURLE_OUT_OF_MEMORY; | |
| 608 } | |
| 609 else if((data->req.httpcode < 300) && | |
| 610 (!data->state.authhost.done) && | |
| 611 conn->bits.authneg) { | |
| 612 /* no (known) authentication available, | |
| 613 authentication is not "done" yet and | |
| 614 no authentication seems to be required and | |
| 615 we didn't try HEAD or GET */ | |
| 616 if((data->set.httpreq != HTTPREQ_GET) && | |
| 617 (data->set.httpreq != HTTPREQ_HEAD)) { | |
| 618 data->req.newurl = strdup(data->change.url); /* clone URL */ | |
| 619 if(!data->req.newurl) | |
| 620 return CURLE_OUT_OF_MEMORY; | |
| 621 data->state.authhost.done = TRUE; | |
| 622 } | |
| 623 } | |
| 624 if(http_should_fail(conn)) { | |
| 625 failf(data, "The requested URL returned error: %d", | |
| 626 data->req.httpcode); | |
| 627 result = CURLE_HTTP_RETURNED_ERROR; | |
| 628 } | |
| 629 | |
| 630 return result; | |
| 631 } | |
| 632 | |
| 633 #ifndef CURL_DISABLE_HTTP_AUTH | |
| 634 /* | |
| 635 * Output the correct authentication header depending on the auth type | |
| 636 * and whether or not it is to a proxy. | |
| 637 */ | |
| 638 static CURLcode | |
| 639 output_auth_headers(struct connectdata *conn, | |
| 640 struct auth *authstatus, | |
| 641 const char *request, | |
| 642 const char *path, | |
| 643 bool proxy) | |
| 644 { | |
| 645 const char *auth = NULL; | |
| 646 CURLcode result = CURLE_OK; | |
| 647 #if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) | |
| 648 struct Curl_easy *data = conn->data; | |
| 649 #endif | |
| 650 | |
| 651 #ifdef CURL_DISABLE_CRYPTO_AUTH | |
| 652 (void)request; | |
| 653 (void)path; | |
| 654 #endif | |
| 655 | |
| 656 #ifdef USE_SPNEGO | |
| 657 if(authstatus->picked == CURLAUTH_NEGOTIATE) { | |
| 658 auth = "Negotiate"; | |
| 659 result = Curl_output_negotiate(conn, proxy); | |
| 660 if(result) | |
| 661 return result; | |
| 662 } | |
| 663 else | |
| 664 #endif | |
| 665 #ifdef USE_NTLM | |
| 666 if(authstatus->picked == CURLAUTH_NTLM) { | |
| 667 auth = "NTLM"; | |
| 668 result = Curl_output_ntlm(conn, proxy); | |
| 669 if(result) | |
| 670 return result; | |
| 671 } | |
| 672 else | |
| 673 #endif | |
| 674 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) | |
| 675 if(authstatus->picked == CURLAUTH_NTLM_WB) { | |
| 676 auth = "NTLM_WB"; | |
| 677 result = Curl_output_ntlm_wb(conn, proxy); | |
| 678 if(result) | |
| 679 return result; | |
| 680 } | |
| 681 else | |
| 682 #endif | |
| 683 #ifndef CURL_DISABLE_CRYPTO_AUTH | |
| 684 if(authstatus->picked == CURLAUTH_DIGEST) { | |
| 685 auth = "Digest"; | |
| 686 result = Curl_output_digest(conn, | |
| 687 proxy, | |
| 688 (const unsigned char *)request, | |
| 689 (const unsigned char *)path); | |
| 690 if(result) | |
| 691 return result; | |
| 692 } | |
| 693 else | |
| 694 #endif | |
| 695 if(authstatus->picked == CURLAUTH_BASIC) { | |
| 696 /* Basic */ | |
| 697 if((proxy && conn->bits.proxy_user_passwd && | |
| 698 !Curl_checkProxyheaders(conn, "Proxy-authorization")) || | |
| 699 (!proxy && conn->bits.user_passwd && | |
| 700 !Curl_checkheaders(conn, "Authorization"))) { | |
| 701 auth = "Basic"; | |
| 702 result = http_output_basic(conn, proxy); | |
| 703 if(result) | |
| 704 return result; | |
| 705 } | |
| 706 | |
| 707 /* NOTE: this function should set 'done' TRUE, as the other auth | |
| 708 functions work that way */ | |
| 709 authstatus->done = TRUE; | |
| 710 } | |
| 711 if(authstatus->picked == CURLAUTH_BEARER) { | |
| 712 /* Bearer */ | |
| 713 if((!proxy && conn->oauth_bearer && | |
| 714 !Curl_checkheaders(conn, "Authorization:"))) { | |
| 715 auth = "Bearer"; | |
| 716 result = http_output_bearer(conn); | |
| 717 if(result) | |
| 718 return result; | |
| 719 } | |
| 720 | |
| 721 /* NOTE: this function should set 'done' TRUE, as the other auth | |
| 722 functions work that way */ | |
| 723 authstatus->done = TRUE; | |
| 724 } | |
| 725 | |
| 726 if(auth) { | |
| 727 infof(data, "%s auth using %s with user '%s'\n", | |
| 728 proxy ? "Proxy" : "Server", auth, | |
| 729 proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : | |
| 730 (conn->user ? conn->user : "")); | |
| 731 authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; | |
| 732 } | |
| 733 else | |
| 734 authstatus->multipass = FALSE; | |
| 735 | |
| 736 return CURLE_OK; | |
| 737 } | |
| 738 | |
| 739 /** | |
| 740 * Curl_http_output_auth() setups the authentication headers for the | |
| 741 * host/proxy and the correct authentication | |
| 742 * method. conn->data->state.authdone is set to TRUE when authentication is | |
| 743 * done. | |
| 744 * | |
| 745 * @param conn all information about the current connection | |
| 746 * @param request pointer to the request keyword | |
| 747 * @param path pointer to the requested path; should include query part | |
| 748 * @param proxytunnel boolean if this is the request setting up a "proxy | |
| 749 * tunnel" | |
| 750 * | |
| 751 * @returns CURLcode | |
| 752 */ | |
| 753 CURLcode | |
| 754 Curl_http_output_auth(struct connectdata *conn, | |
| 755 const char *request, | |
| 756 const char *path, | |
| 757 bool proxytunnel) /* TRUE if this is the request setting | |
| 758 up the proxy tunnel */ | |
| 759 { | |
| 760 CURLcode result = CURLE_OK; | |
| 761 struct Curl_easy *data = conn->data; | |
| 762 struct auth *authhost; | |
| 763 struct auth *authproxy; | |
| 764 | |
| 765 DEBUGASSERT(data); | |
| 766 | |
| 767 authhost = &data->state.authhost; | |
| 768 authproxy = &data->state.authproxy; | |
| 769 | |
| 770 if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || | |
| 771 conn->bits.user_passwd || conn->oauth_bearer) | |
| 772 /* continue please */; | |
| 773 else { | |
| 774 authhost->done = TRUE; | |
| 775 authproxy->done = TRUE; | |
| 776 return CURLE_OK; /* no authentication with no user or password */ | |
| 777 } | |
| 778 | |
| 779 if(authhost->want && !authhost->picked) | |
| 780 /* The app has selected one or more methods, but none has been picked | |
| 781 so far by a server round-trip. Then we set the picked one to the | |
| 782 want one, and if this is one single bit it'll be used instantly. */ | |
| 783 authhost->picked = authhost->want; | |
| 784 | |
| 785 if(authproxy->want && !authproxy->picked) | |
| 786 /* The app has selected one or more methods, but none has been picked so | |
| 787 far by a proxy round-trip. Then we set the picked one to the want one, | |
| 788 and if this is one single bit it'll be used instantly. */ | |
| 789 authproxy->picked = authproxy->want; | |
| 790 | |
| 791 #ifndef CURL_DISABLE_PROXY | |
| 792 /* Send proxy authentication header if needed */ | |
| 793 if(conn->bits.httpproxy && | |
| 794 (conn->bits.tunnel_proxy == (bit)proxytunnel)) { | |
| 795 result = output_auth_headers(conn, authproxy, request, path, TRUE); | |
| 796 if(result) | |
| 797 return result; | |
| 798 } | |
| 799 else | |
| 800 #else | |
| 801 (void)proxytunnel; | |
| 802 #endif /* CURL_DISABLE_PROXY */ | |
| 803 /* we have no proxy so let's pretend we're done authenticating | |
| 804 with it */ | |
| 805 authproxy->done = TRUE; | |
| 806 | |
| 807 /* To prevent the user+password to get sent to other than the original | |
| 808 host due to a location-follow, we do some weirdo checks here */ | |
| 809 if(!data->state.this_is_a_follow || | |
| 810 conn->bits.netrc || | |
| 811 !data->state.first_host || | |
| 812 data->set.allow_auth_to_other_hosts || | |
| 813 strcasecompare(data->state.first_host, conn->host.name)) { | |
| 814 result = output_auth_headers(conn, authhost, request, path, FALSE); | |
| 815 } | |
| 816 else | |
| 817 authhost->done = TRUE; | |
| 818 | |
| 819 return result; | |
| 820 } | |
| 821 | |
| 822 #else | |
| 823 /* when disabled */ | |
| 824 CURLcode | |
| 825 Curl_http_output_auth(struct connectdata *conn, | |
| 826 const char *request, | |
| 827 const char *path, | |
| 828 bool proxytunnel) | |
| 829 { | |
| 830 (void)conn; | |
| 831 (void)request; | |
| 832 (void)path; | |
| 833 (void)proxytunnel; | |
| 834 return CURLE_OK; | |
| 835 } | |
| 836 #endif | |
| 837 | |
| 838 /* | |
| 839 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: | |
| 840 * headers. They are dealt with both in the transfer.c main loop and in the | |
| 841 * proxy CONNECT loop. | |
| 842 */ | |
| 843 | |
| 844 CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, | |
| 845 const char *auth) /* the first non-space */ | |
| 846 { | |
| 847 /* | |
| 848 * This resource requires authentication | |
| 849 */ | |
| 850 struct Curl_easy *data = conn->data; | |
| 851 | |
| 852 #ifdef USE_SPNEGO | |
| 853 curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state : | |
| 854 &conn->http_negotiate_state; | |
| 855 #endif | |
| 856 unsigned long *availp; | |
| 857 struct auth *authp; | |
| 858 | |
| 859 if(proxy) { | |
| 860 availp = &data->info.proxyauthavail; | |
| 861 authp = &data->state.authproxy; | |
| 862 } | |
| 863 else { | |
| 864 availp = &data->info.httpauthavail; | |
| 865 authp = &data->state.authhost; | |
| 866 } | |
| 867 | |
| 868 /* | |
| 869 * Here we check if we want the specific single authentication (using ==) and | |
| 870 * if we do, we initiate usage of it. | |
| 871 * | |
| 872 * If the provided authentication is wanted as one out of several accepted | |
| 873 * types (using &), we OR this authentication type to the authavail | |
| 874 * variable. | |
| 875 * | |
| 876 * Note: | |
| 877 * | |
| 878 * ->picked is first set to the 'want' value (one or more bits) before the | |
| 879 * request is sent, and then it is again set _after_ all response 401/407 | |
| 880 * headers have been received but then only to a single preferred method | |
| 881 * (bit). | |
| 882 */ | |
| 883 | |
| 884 while(*auth) { | |
| 885 #ifdef USE_SPNEGO | |
| 886 if(checkprefix("Negotiate", auth)) { | |
| 887 if((authp->avail & CURLAUTH_NEGOTIATE) || | |
| 888 Curl_auth_is_spnego_supported()) { | |
| 889 *availp |= CURLAUTH_NEGOTIATE; | |
| 890 authp->avail |= CURLAUTH_NEGOTIATE; | |
| 891 | |
| 892 if(authp->picked == CURLAUTH_NEGOTIATE) { | |
| 893 CURLcode result = Curl_input_negotiate(conn, proxy, auth); | |
| 894 if(!result) { | |
| 895 DEBUGASSERT(!data->req.newurl); | |
| 896 data->req.newurl = strdup(data->change.url); | |
| 897 if(!data->req.newurl) | |
| 898 return CURLE_OUT_OF_MEMORY; | |
| 899 data->state.authproblem = FALSE; | |
| 900 /* we received a GSS auth token and we dealt with it fine */ | |
| 901 *negstate = GSS_AUTHRECV; | |
| 902 } | |
| 903 else | |
| 904 data->state.authproblem = TRUE; | |
| 905 } | |
| 906 } | |
| 907 } | |
| 908 else | |
| 909 #endif | |
| 910 #ifdef USE_NTLM | |
| 911 /* NTLM support requires the SSL crypto libs */ | |
| 912 if(checkprefix("NTLM", auth)) { | |
| 913 if((authp->avail & CURLAUTH_NTLM) || | |
| 914 (authp->avail & CURLAUTH_NTLM_WB) || | |
| 915 Curl_auth_is_ntlm_supported()) { | |
| 916 *availp |= CURLAUTH_NTLM; | |
| 917 authp->avail |= CURLAUTH_NTLM; | |
| 918 | |
| 919 if(authp->picked == CURLAUTH_NTLM || | |
| 920 authp->picked == CURLAUTH_NTLM_WB) { | |
| 921 /* NTLM authentication is picked and activated */ | |
| 922 CURLcode result = Curl_input_ntlm(conn, proxy, auth); | |
| 923 if(!result) { | |
| 924 data->state.authproblem = FALSE; | |
| 925 #ifdef NTLM_WB_ENABLED | |
| 926 if(authp->picked == CURLAUTH_NTLM_WB) { | |
| 927 *availp &= ~CURLAUTH_NTLM; | |
| 928 authp->avail &= ~CURLAUTH_NTLM; | |
| 929 *availp |= CURLAUTH_NTLM_WB; | |
| 930 authp->avail |= CURLAUTH_NTLM_WB; | |
| 931 | |
| 932 result = Curl_input_ntlm_wb(conn, proxy, auth); | |
| 933 if(result) { | |
| 934 infof(data, "Authentication problem. Ignoring this.\n"); | |
| 935 data->state.authproblem = TRUE; | |
| 936 } | |
| 937 } | |
| 938 #endif | |
| 939 } | |
| 940 else { | |
| 941 infof(data, "Authentication problem. Ignoring this.\n"); | |
| 942 data->state.authproblem = TRUE; | |
| 943 } | |
| 944 } | |
| 945 } | |
| 946 } | |
| 947 else | |
| 948 #endif | |
| 949 #ifndef CURL_DISABLE_CRYPTO_AUTH | |
| 950 if(checkprefix("Digest", auth)) { | |
| 951 if((authp->avail & CURLAUTH_DIGEST) != 0) | |
| 952 infof(data, "Ignoring duplicate digest auth header.\n"); | |
| 953 else if(Curl_auth_is_digest_supported()) { | |
| 954 CURLcode result; | |
| 955 | |
| 956 *availp |= CURLAUTH_DIGEST; | |
| 957 authp->avail |= CURLAUTH_DIGEST; | |
| 958 | |
| 959 /* We call this function on input Digest headers even if Digest | |
| 960 * authentication isn't activated yet, as we need to store the | |
| 961 * incoming data from this header in case we are going to use | |
| 962 * Digest */ | |
| 963 result = Curl_input_digest(conn, proxy, auth); | |
| 964 if(result) { | |
| 965 infof(data, "Authentication problem. Ignoring this.\n"); | |
| 966 data->state.authproblem = TRUE; | |
| 967 } | |
| 968 } | |
| 969 } | |
| 970 else | |
| 971 #endif | |
| 972 if(checkprefix("Basic", auth)) { | |
| 973 *availp |= CURLAUTH_BASIC; | |
| 974 authp->avail |= CURLAUTH_BASIC; | |
| 975 if(authp->picked == CURLAUTH_BASIC) { | |
| 976 /* We asked for Basic authentication but got a 40X back | |
| 977 anyway, which basically means our name+password isn't | |
| 978 valid. */ | |
| 979 authp->avail = CURLAUTH_NONE; | |
| 980 infof(data, "Authentication problem. Ignoring this.\n"); | |
| 981 data->state.authproblem = TRUE; | |
| 982 } | |
| 983 } | |
| 984 else | |
| 985 if(checkprefix("Bearer", auth)) { | |
| 986 *availp |= CURLAUTH_BEARER; | |
| 987 authp->avail |= CURLAUTH_BEARER; | |
| 988 if(authp->picked == CURLAUTH_BEARER) { | |
| 989 /* We asked for Bearer authentication but got a 40X back | |
| 990 anyway, which basically means our token isn't valid. */ | |
| 991 authp->avail = CURLAUTH_NONE; | |
| 992 infof(data, "Authentication problem. Ignoring this.\n"); | |
| 993 data->state.authproblem = TRUE; | |
| 994 } | |
| 995 } | |
| 996 | |
| 997 /* there may be multiple methods on one line, so keep reading */ | |
| 998 while(*auth && *auth != ',') /* read up to the next comma */ | |
| 999 auth++; | |
| 1000 if(*auth == ',') /* if we're on a comma, skip it */ | |
| 1001 auth++; | |
| 1002 while(*auth && ISSPACE(*auth)) | |
| 1003 auth++; | |
| 1004 } | |
| 1005 | |
| 1006 return CURLE_OK; | |
| 1007 } | |
| 1008 | |
| 1009 /** | |
| 1010 * http_should_fail() determines whether an HTTP response has gotten us | |
| 1011 * into an error state or not. | |
| 1012 * | |
| 1013 * @param conn all information about the current connection | |
| 1014 * | |
| 1015 * @retval 0 communications should continue | |
| 1016 * | |
| 1017 * @retval 1 communications should not continue | |
| 1018 */ | |
| 1019 static int http_should_fail(struct connectdata *conn) | |
| 1020 { | |
| 1021 struct Curl_easy *data; | |
| 1022 int httpcode; | |
| 1023 | |
| 1024 DEBUGASSERT(conn); | |
| 1025 data = conn->data; | |
| 1026 DEBUGASSERT(data); | |
| 1027 | |
| 1028 httpcode = data->req.httpcode; | |
| 1029 | |
| 1030 /* | |
| 1031 ** If we haven't been asked to fail on error, | |
| 1032 ** don't fail. | |
| 1033 */ | |
| 1034 if(!data->set.http_fail_on_error) | |
| 1035 return 0; | |
| 1036 | |
| 1037 /* | |
| 1038 ** Any code < 400 is never terminal. | |
| 1039 */ | |
| 1040 if(httpcode < 400) | |
| 1041 return 0; | |
| 1042 | |
| 1043 /* | |
| 1044 ** Any code >= 400 that's not 401 or 407 is always | |
| 1045 ** a terminal error | |
| 1046 */ | |
| 1047 if((httpcode != 401) && (httpcode != 407)) | |
| 1048 return 1; | |
| 1049 | |
| 1050 /* | |
| 1051 ** All we have left to deal with is 401 and 407 | |
| 1052 */ | |
| 1053 DEBUGASSERT((httpcode == 401) || (httpcode == 407)); | |
| 1054 | |
| 1055 /* | |
| 1056 ** Examine the current authentication state to see if this | |
| 1057 ** is an error. The idea is for this function to get | |
| 1058 ** called after processing all the headers in a response | |
| 1059 ** message. So, if we've been to asked to authenticate a | |
| 1060 ** particular stage, and we've done it, we're OK. But, if | |
| 1061 ** we're already completely authenticated, it's not OK to | |
| 1062 ** get another 401 or 407. | |
| 1063 ** | |
| 1064 ** It is possible for authentication to go stale such that | |
| 1065 ** the client needs to reauthenticate. Once that info is | |
| 1066 ** available, use it here. | |
| 1067 */ | |
| 1068 | |
| 1069 /* | |
| 1070 ** Either we're not authenticating, or we're supposed to | |
| 1071 ** be authenticating something else. This is an error. | |
| 1072 */ | |
| 1073 if((httpcode == 401) && !conn->bits.user_passwd) | |
| 1074 return TRUE; | |
| 1075 if((httpcode == 407) && !conn->bits.proxy_user_passwd) | |
| 1076 return TRUE; | |
| 1077 | |
| 1078 return data->state.authproblem; | |
| 1079 } | |
| 1080 | |
| 1081 /* | |
| 1082 * readmoredata() is a "fread() emulation" to provide POST and/or request | |
| 1083 * data. It is used when a huge POST is to be made and the entire chunk wasn't | |
| 1084 * sent in the first send(). This function will then be called from the | |
| 1085 * transfer.c loop when more data is to be sent to the peer. | |
| 1086 * | |
| 1087 * Returns the amount of bytes it filled the buffer with. | |
| 1088 */ | |
| 1089 static size_t readmoredata(char *buffer, | |
| 1090 size_t size, | |
| 1091 size_t nitems, | |
| 1092 void *userp) | |
| 1093 { | |
| 1094 struct connectdata *conn = (struct connectdata *)userp; | |
| 1095 struct HTTP *http = conn->data->req.protop; | |
| 1096 size_t fullsize = size * nitems; | |
| 1097 | |
| 1098 if(!http->postsize) | |
| 1099 /* nothing to return */ | |
| 1100 return 0; | |
| 1101 | |
| 1102 /* make sure that a HTTP request is never sent away chunked! */ | |
| 1103 conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; | |
| 1104 | |
| 1105 if(http->postsize <= (curl_off_t)fullsize) { | |
| 1106 memcpy(buffer, http->postdata, (size_t)http->postsize); | |
| 1107 fullsize = (size_t)http->postsize; | |
| 1108 | |
| 1109 if(http->backup.postsize) { | |
| 1110 /* move backup data into focus and continue on that */ | |
| 1111 http->postdata = http->backup.postdata; | |
| 1112 http->postsize = http->backup.postsize; | |
| 1113 conn->data->state.fread_func = http->backup.fread_func; | |
| 1114 conn->data->state.in = http->backup.fread_in; | |
| 1115 | |
| 1116 http->sending++; /* move one step up */ | |
| 1117 | |
| 1118 http->backup.postsize = 0; | |
| 1119 } | |
| 1120 else | |
| 1121 http->postsize = 0; | |
| 1122 | |
| 1123 return fullsize; | |
| 1124 } | |
| 1125 | |
| 1126 memcpy(buffer, http->postdata, fullsize); | |
| 1127 http->postdata += fullsize; | |
| 1128 http->postsize -= fullsize; | |
| 1129 | |
| 1130 return fullsize; | |
| 1131 } | |
| 1132 | |
| 1133 /* ------------------------------------------------------------------------- */ | |
| 1134 /* add_buffer functions */ | |
| 1135 | |
| 1136 /* | |
| 1137 * Curl_add_buffer_init() sets up and returns a fine buffer struct | |
| 1138 */ | |
| 1139 Curl_send_buffer *Curl_add_buffer_init(void) | |
| 1140 { | |
| 1141 return calloc(1, sizeof(Curl_send_buffer)); | |
| 1142 } | |
| 1143 | |
| 1144 /* | |
| 1145 * Curl_add_buffer_free() frees all associated resources. | |
| 1146 */ | |
| 1147 void Curl_add_buffer_free(Curl_send_buffer **inp) | |
| 1148 { | |
| 1149 Curl_send_buffer *in; | |
| 1150 if(!inp) | |
| 1151 return; | |
| 1152 in = *inp; | |
| 1153 if(in) { /* deal with NULL input */ | |
| 1154 free(in->buffer); | |
| 1155 free(in); | |
| 1156 } | |
| 1157 *inp = NULL; | |
| 1158 } | |
| 1159 | |
| 1160 /* | |
| 1161 * Curl_add_buffer_send() sends a header buffer and frees all associated | |
| 1162 * memory. Body data may be appended to the header data if desired. | |
| 1163 * | |
| 1164 * Returns CURLcode | |
| 1165 */ | |
| 1166 CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, | |
| 1167 struct connectdata *conn, | |
| 1168 | |
| 1169 /* add the number of sent bytes to this | |
| 1170 counter */ | |
| 1171 curl_off_t *bytes_written, | |
| 1172 | |
| 1173 /* how much of the buffer contains body data */ | |
| 1174 size_t included_body_bytes, | |
| 1175 int socketindex) | |
| 1176 { | |
| 1177 ssize_t amount; | |
| 1178 CURLcode result; | |
| 1179 char *ptr; | |
| 1180 size_t size; | |
| 1181 struct Curl_easy *data = conn->data; | |
| 1182 struct HTTP *http = data->req.protop; | |
| 1183 size_t sendsize; | |
| 1184 curl_socket_t sockfd; | |
| 1185 size_t headersize; | |
| 1186 Curl_send_buffer *in = *inp; | |
| 1187 | |
| 1188 DEBUGASSERT(socketindex <= SECONDARYSOCKET); | |
| 1189 | |
| 1190 sockfd = conn->sock[socketindex]; | |
| 1191 | |
| 1192 /* The looping below is required since we use non-blocking sockets, but due | |
| 1193 to the circumstances we will just loop and try again and again etc */ | |
| 1194 | |
| 1195 ptr = in->buffer; | |
| 1196 size = in->size_used; | |
| 1197 | |
| 1198 headersize = size - included_body_bytes; /* the initial part that isn't body | |
| 1199 is header */ | |
| 1200 | |
| 1201 DEBUGASSERT(size > included_body_bytes); | |
| 1202 | |
| 1203 result = Curl_convert_to_network(data, ptr, headersize); | |
| 1204 /* Curl_convert_to_network calls failf if unsuccessful */ | |
| 1205 if(result) { | |
| 1206 /* conversion failed, free memory and return to the caller */ | |
| 1207 Curl_add_buffer_free(inp); | |
| 1208 return result; | |
| 1209 } | |
| 1210 | |
| 1211 if((conn->handler->flags & PROTOPT_SSL || | |
| 1212 conn->http_proxy.proxytype == CURLPROXY_HTTPS) | |
| 1213 && conn->httpversion != 20) { | |
| 1214 /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk | |
| 1215 when we speak HTTPS, as if only a fraction of it is sent now, this data | |
| 1216 needs to fit into the normal read-callback buffer later on and that | |
| 1217 buffer is using this size. | |
| 1218 */ | |
| 1219 | |
| 1220 sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE); | |
| 1221 | |
| 1222 /* OpenSSL is very picky and we must send the SAME buffer pointer to the | |
| 1223 library when we attempt to re-send this buffer. Sending the same data | |
| 1224 is not enough, we must use the exact same address. For this reason, we | |
| 1225 must copy the data to the uploadbuffer first, since that is the buffer | |
| 1226 we will be using if this send is retried later. | |
| 1227 */ | |
| 1228 result = Curl_get_upload_buffer(data); | |
| 1229 if(result) { | |
| 1230 /* malloc failed, free memory and return to the caller */ | |
| 1231 Curl_add_buffer_free(&in); | |
| 1232 return result; | |
| 1233 } | |
| 1234 memcpy(data->state.ulbuf, ptr, sendsize); | |
| 1235 ptr = data->state.ulbuf; | |
| 1236 } | |
| 1237 else | |
| 1238 sendsize = size; | |
| 1239 | |
| 1240 result = Curl_write(conn, sockfd, ptr, sendsize, &amount); | |
| 1241 | |
| 1242 if(!result) { | |
| 1243 /* | |
| 1244 * Note that we may not send the entire chunk at once, and we have a set | |
| 1245 * number of data bytes at the end of the big buffer (out of which we may | |
| 1246 * only send away a part). | |
| 1247 */ | |
| 1248 /* how much of the header that was sent */ | |
| 1249 size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; | |
| 1250 size_t bodylen = amount - headlen; | |
| 1251 | |
| 1252 if(data->set.verbose) { | |
| 1253 /* this data _may_ contain binary stuff */ | |
| 1254 Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen); | |
| 1255 if(bodylen) { | |
| 1256 /* there was body data sent beyond the initial header part, pass that | |
| 1257 on to the debug callback too */ | |
| 1258 Curl_debug(data, CURLINFO_DATA_OUT, | |
| 1259 ptr + headlen, bodylen); | |
| 1260 } | |
| 1261 } | |
| 1262 | |
| 1263 /* 'amount' can never be a very large value here so typecasting it so a | |
| 1264 signed 31 bit value should not cause problems even if ssize_t is | |
| 1265 64bit */ | |
| 1266 *bytes_written += (long)amount; | |
| 1267 | |
| 1268 if(http) { | |
| 1269 /* if we sent a piece of the body here, up the byte counter for it | |
| 1270 accordingly */ | |
| 1271 data->req.writebytecount += bodylen; | |
| 1272 Curl_pgrsSetUploadCounter(data, data->req.writebytecount); | |
| 1273 | |
| 1274 if((size_t)amount != size) { | |
| 1275 /* The whole request could not be sent in one system call. We must | |
| 1276 queue it up and send it later when we get the chance. We must not | |
| 1277 loop here and wait until it might work again. */ | |
| 1278 | |
| 1279 size -= amount; | |
| 1280 | |
| 1281 ptr = in->buffer + amount; | |
| 1282 | |
| 1283 /* backup the currently set pointers */ | |
| 1284 http->backup.fread_func = data->state.fread_func; | |
| 1285 http->backup.fread_in = data->state.in; | |
| 1286 http->backup.postdata = http->postdata; | |
| 1287 http->backup.postsize = http->postsize; | |
| 1288 | |
| 1289 /* set the new pointers for the request-sending */ | |
| 1290 data->state.fread_func = (curl_read_callback)readmoredata; | |
| 1291 data->state.in = (void *)conn; | |
| 1292 http->postdata = ptr; | |
| 1293 http->postsize = (curl_off_t)size; | |
| 1294 | |
| 1295 http->send_buffer = in; | |
| 1296 http->sending = HTTPSEND_REQUEST; | |
| 1297 | |
| 1298 return CURLE_OK; | |
| 1299 } | |
| 1300 http->sending = HTTPSEND_BODY; | |
| 1301 /* the full buffer was sent, clean up and return */ | |
| 1302 } | |
| 1303 else { | |
| 1304 if((size_t)amount != size) | |
| 1305 /* We have no continue-send mechanism now, fail. This can only happen | |
| 1306 when this function is used from the CONNECT sending function. We | |
| 1307 currently (stupidly) assume that the whole request is always sent | |
| 1308 away in the first single chunk. | |
| 1309 | |
| 1310 This needs FIXing. | |
| 1311 */ | |
| 1312 return CURLE_SEND_ERROR; | |
| 1313 } | |
| 1314 } | |
| 1315 Curl_add_buffer_free(&in); | |
| 1316 | |
| 1317 return result; | |
| 1318 } | |
| 1319 | |
| 1320 | |
| 1321 /* | |
| 1322 * add_bufferf() add the formatted input to the buffer. | |
| 1323 */ | |
| 1324 CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) | |
| 1325 { | |
| 1326 char *s; | |
| 1327 va_list ap; | |
| 1328 Curl_send_buffer *in = *inp; | |
| 1329 va_start(ap, fmt); | |
| 1330 s = vaprintf(fmt, ap); /* this allocs a new string to append */ | |
| 1331 va_end(ap); | |
| 1332 | |
| 1333 if(s) { | |
| 1334 CURLcode result = Curl_add_buffer(inp, s, strlen(s)); | |
| 1335 free(s); | |
| 1336 return result; | |
| 1337 } | |
| 1338 /* If we failed, we cleanup the whole buffer and return error */ | |
| 1339 free(in->buffer); | |
| 1340 free(in); | |
| 1341 *inp = NULL; | |
| 1342 return CURLE_OUT_OF_MEMORY; | |
| 1343 } | |
| 1344 | |
| 1345 /* | |
| 1346 * Curl_add_buffer() appends a memory chunk to the existing buffer | |
| 1347 */ | |
| 1348 CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, | |
| 1349 size_t size) | |
| 1350 { | |
| 1351 char *new_rb; | |
| 1352 Curl_send_buffer *in = *inp; | |
| 1353 | |
| 1354 if(~size < in->size_used) { | |
| 1355 /* If resulting used size of send buffer would wrap size_t, cleanup | |
| 1356 the whole buffer and return error. Otherwise the required buffer | |
| 1357 size will fit into a single allocatable memory chunk */ | |
| 1358 Curl_safefree(in->buffer); | |
| 1359 free(in); | |
| 1360 *inp = NULL; | |
| 1361 return CURLE_OUT_OF_MEMORY; | |
| 1362 } | |
| 1363 | |
| 1364 if(!in->buffer || | |
| 1365 ((in->size_used + size) > (in->size_max - 1))) { | |
| 1366 /* If current buffer size isn't enough to hold the result, use a | |
| 1367 buffer size that doubles the required size. If this new size | |
| 1368 would wrap size_t, then just use the largest possible one */ | |
| 1369 size_t new_size; | |
| 1370 | |
| 1371 if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || | |
| 1372 (~(size * 2) < (in->size_used * 2))) | |
| 1373 new_size = (size_t)-1; | |
| 1374 else | |
| 1375 new_size = (in->size_used + size) * 2; | |
| 1376 | |
| 1377 if(in->buffer) | |
| 1378 /* we have a buffer, enlarge the existing one */ | |
| 1379 new_rb = Curl_saferealloc(in->buffer, new_size); | |
| 1380 else | |
| 1381 /* create a new buffer */ | |
| 1382 new_rb = malloc(new_size); | |
| 1383 | |
| 1384 if(!new_rb) { | |
| 1385 /* If we failed, we cleanup the whole buffer and return error */ | |
| 1386 free(in); | |
| 1387 *inp = NULL; | |
| 1388 return CURLE_OUT_OF_MEMORY; | |
| 1389 } | |
| 1390 | |
| 1391 in->buffer = new_rb; | |
| 1392 in->size_max = new_size; | |
| 1393 } | |
| 1394 memcpy(&in->buffer[in->size_used], inptr, size); | |
| 1395 | |
| 1396 in->size_used += size; | |
| 1397 | |
| 1398 return CURLE_OK; | |
| 1399 } | |
| 1400 | |
| 1401 /* end of the add_buffer functions */ | |
| 1402 /* ------------------------------------------------------------------------- */ | |
| 1403 | |
| 1404 | |
| 1405 | |
| 1406 /* | |
| 1407 * Curl_compareheader() | |
| 1408 * | |
| 1409 * Returns TRUE if 'headerline' contains the 'header' with given 'content'. | |
| 1410 * Pass headers WITH the colon. | |
| 1411 */ | |
| 1412 bool | |
| 1413 Curl_compareheader(const char *headerline, /* line to check */ | |
| 1414 const char *header, /* header keyword _with_ colon */ | |
| 1415 const char *content) /* content string to find */ | |
| 1416 { | |
| 1417 /* RFC2616, section 4.2 says: "Each header field consists of a name followed | |
| 1418 * by a colon (":") and the field value. Field names are case-insensitive. | |
| 1419 * The field value MAY be preceded by any amount of LWS, though a single SP | |
| 1420 * is preferred." */ | |
| 1421 | |
| 1422 size_t hlen = strlen(header); | |
| 1423 size_t clen; | |
| 1424 size_t len; | |
| 1425 const char *start; | |
| 1426 const char *end; | |
| 1427 | |
| 1428 if(!strncasecompare(headerline, header, hlen)) | |
| 1429 return FALSE; /* doesn't start with header */ | |
| 1430 | |
| 1431 /* pass the header */ | |
| 1432 start = &headerline[hlen]; | |
| 1433 | |
| 1434 /* pass all white spaces */ | |
| 1435 while(*start && ISSPACE(*start)) | |
| 1436 start++; | |
| 1437 | |
| 1438 /* find the end of the header line */ | |
| 1439 end = strchr(start, '\r'); /* lines end with CRLF */ | |
| 1440 if(!end) { | |
| 1441 /* in case there's a non-standard compliant line here */ | |
| 1442 end = strchr(start, '\n'); | |
| 1443 | |
| 1444 if(!end) | |
| 1445 /* hm, there's no line ending here, use the zero byte! */ | |
| 1446 end = strchr(start, '\0'); | |
| 1447 } | |
| 1448 | |
| 1449 len = end-start; /* length of the content part of the input line */ | |
| 1450 clen = strlen(content); /* length of the word to find */ | |
| 1451 | |
| 1452 /* find the content string in the rest of the line */ | |
| 1453 for(; len >= clen; len--, start++) { | |
| 1454 if(strncasecompare(start, content, clen)) | |
| 1455 return TRUE; /* match! */ | |
| 1456 } | |
| 1457 | |
| 1458 return FALSE; /* no match */ | |
| 1459 } | |
| 1460 | |
| 1461 /* | |
| 1462 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from | |
| 1463 * the generic Curl_connect(). | |
| 1464 */ | |
| 1465 CURLcode Curl_http_connect(struct connectdata *conn, bool *done) | |
| 1466 { | |
| 1467 CURLcode result; | |
| 1468 | |
| 1469 /* We default to persistent connections. We set this already in this connect | |
| 1470 function to make the re-use checks properly be able to check this bit. */ | |
| 1471 connkeep(conn, "HTTP default"); | |
| 1472 | |
| 1473 /* the CONNECT procedure might not have been completed */ | |
| 1474 result = Curl_proxy_connect(conn, FIRSTSOCKET); | |
| 1475 if(result) | |
| 1476 return result; | |
| 1477 | |
| 1478 if(conn->bits.proxy_connect_closed) | |
| 1479 /* this is not an error, just part of the connection negotiation */ | |
| 1480 return CURLE_OK; | |
| 1481 | |
| 1482 if(CONNECT_FIRSTSOCKET_PROXY_SSL()) | |
| 1483 return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ | |
| 1484 | |
| 1485 if(Curl_connect_ongoing(conn)) | |
| 1486 /* nothing else to do except wait right now - we're not done here. */ | |
| 1487 return CURLE_OK; | |
| 1488 | |
| 1489 #ifndef CURL_DISABLE_PROXY | |
| 1490 if(conn->data->set.haproxyprotocol) { | |
| 1491 /* add HAProxy PROXY protocol header */ | |
| 1492 result = add_haproxy_protocol_header(conn); | |
| 1493 if(result) | |
| 1494 return result; | |
| 1495 } | |
| 1496 #endif | |
| 1497 | |
| 1498 if(conn->given->protocol & CURLPROTO_HTTPS) { | |
| 1499 /* perform SSL initialization */ | |
| 1500 result = https_connecting(conn, done); | |
| 1501 if(result) | |
| 1502 return result; | |
| 1503 } | |
| 1504 else | |
| 1505 *done = TRUE; | |
| 1506 | |
| 1507 return CURLE_OK; | |
| 1508 } | |
| 1509 | |
| 1510 /* this returns the socket to wait for in the DO and DOING state for the multi | |
| 1511 interface and then we're always _sending_ a request and thus we wait for | |
| 1512 the single socket to become writable only */ | |
| 1513 static int http_getsock_do(struct connectdata *conn, | |
| 1514 curl_socket_t *socks) | |
| 1515 { | |
| 1516 /* write mode */ | |
| 1517 socks[0] = conn->sock[FIRSTSOCKET]; | |
| 1518 return GETSOCK_WRITESOCK(0); | |
| 1519 } | |
| 1520 | |
| 1521 #ifndef CURL_DISABLE_PROXY | |
| 1522 static CURLcode add_haproxy_protocol_header(struct connectdata *conn) | |
| 1523 { | |
| 1524 char proxy_header[128]; | |
| 1525 Curl_send_buffer *req_buffer; | |
| 1526 CURLcode result; | |
| 1527 char tcp_version[5]; | |
| 1528 | |
| 1529 /* Emit the correct prefix for IPv6 */ | |
| 1530 if(conn->bits.ipv6) { | |
| 1531 strcpy(tcp_version, "TCP6"); | |
| 1532 } | |
| 1533 else { | |
| 1534 strcpy(tcp_version, "TCP4"); | |
| 1535 } | |
| 1536 | |
| 1537 msnprintf(proxy_header, | |
| 1538 sizeof(proxy_header), | |
| 1539 "PROXY %s %s %s %li %li\r\n", | |
| 1540 tcp_version, | |
| 1541 conn->data->info.conn_local_ip, | |
| 1542 conn->data->info.conn_primary_ip, | |
| 1543 conn->data->info.conn_local_port, | |
| 1544 conn->data->info.conn_primary_port); | |
| 1545 | |
| 1546 req_buffer = Curl_add_buffer_init(); | |
| 1547 if(!req_buffer) | |
| 1548 return CURLE_OUT_OF_MEMORY; | |
| 1549 | |
| 1550 result = Curl_add_bufferf(&req_buffer, proxy_header); | |
| 1551 if(result) | |
| 1552 return result; | |
| 1553 | |
| 1554 result = Curl_add_buffer_send(&req_buffer, | |
| 1555 conn, | |
| 1556 &conn->data->info.request_size, | |
| 1557 0, | |
| 1558 FIRSTSOCKET); | |
| 1559 | |
| 1560 return result; | |
| 1561 } | |
| 1562 #endif | |
| 1563 | |
| 1564 #ifdef USE_SSL | |
| 1565 static CURLcode https_connecting(struct connectdata *conn, bool *done) | |
| 1566 { | |
| 1567 CURLcode result; | |
| 1568 DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL)); | |
| 1569 | |
| 1570 #ifdef ENABLE_QUIC | |
| 1571 if(conn->transport == TRNSPRT_QUIC) { | |
| 1572 *done = TRUE; | |
| 1573 return CURLE_OK; | |
| 1574 } | |
| 1575 #endif | |
| 1576 | |
| 1577 /* perform SSL initialization for this socket */ | |
| 1578 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); | |
| 1579 if(result) | |
| 1580 connclose(conn, "Failed HTTPS connection"); | |
| 1581 | |
| 1582 return result; | |
| 1583 } | |
| 1584 | |
| 1585 static int https_getsock(struct connectdata *conn, | |
| 1586 curl_socket_t *socks) | |
| 1587 { | |
| 1588 if(conn->handler->flags & PROTOPT_SSL) | |
| 1589 return Curl_ssl_getsock(conn, socks); | |
| 1590 return GETSOCK_BLANK; | |
| 1591 } | |
| 1592 #endif /* USE_SSL */ | |
| 1593 | |
| 1594 /* | |
| 1595 * Curl_http_done() gets called after a single HTTP request has been | |
| 1596 * performed. | |
| 1597 */ | |
| 1598 | |
| 1599 CURLcode Curl_http_done(struct connectdata *conn, | |
| 1600 CURLcode status, bool premature) | |
| 1601 { | |
| 1602 struct Curl_easy *data = conn->data; | |
| 1603 struct HTTP *http = data->req.protop; | |
| 1604 | |
| 1605 /* Clear multipass flag. If authentication isn't done yet, then it will get | |
| 1606 * a chance to be set back to true when we output the next auth header */ | |
| 1607 data->state.authhost.multipass = FALSE; | |
| 1608 data->state.authproxy.multipass = FALSE; | |
| 1609 | |
| 1610 Curl_unencode_cleanup(conn); | |
| 1611 | |
| 1612 /* set the proper values (possibly modified on POST) */ | |
| 1613 conn->seek_func = data->set.seek_func; /* restore */ | |
| 1614 conn->seek_client = data->set.seek_client; /* restore */ | |
| 1615 | |
| 1616 if(!http) | |
| 1617 return CURLE_OK; | |
| 1618 | |
| 1619 if(http->send_buffer) { | |
| 1620 Curl_add_buffer_free(&http->send_buffer); | |
| 1621 } | |
| 1622 | |
| 1623 Curl_http2_done(conn, premature); | |
| 1624 | |
| 1625 Curl_mime_cleanpart(&http->form); | |
| 1626 | |
| 1627 if(status) | |
| 1628 return status; | |
| 1629 | |
| 1630 if(!premature && /* this check is pointless when DONE is called before the | |
| 1631 entire operation is complete */ | |
| 1632 !conn->bits.retry && | |
| 1633 !data->set.connect_only && | |
| 1634 (data->req.bytecount + | |
| 1635 data->req.headerbytecount - | |
| 1636 data->req.deductheadercount) <= 0) { | |
| 1637 /* If this connection isn't simply closed to be retried, AND nothing was | |
| 1638 read from the HTTP server (that counts), this can't be right so we | |
| 1639 return an error here */ | |
| 1640 failf(data, "Empty reply from server"); | |
| 1641 return CURLE_GOT_NOTHING; | |
| 1642 } | |
| 1643 | |
| 1644 return CURLE_OK; | |
| 1645 } | |
| 1646 | |
| 1647 /* | |
| 1648 * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons | |
| 1649 * to avoid it include: | |
| 1650 * | |
| 1651 * - if the user specifically requested HTTP 1.0 | |
| 1652 * - if the server we are connected to only supports 1.0 | |
| 1653 * - if any server previously contacted to handle this request only supports | |
| 1654 * 1.0. | |
| 1655 */ | |
| 1656 static bool use_http_1_1plus(const struct Curl_easy *data, | |
| 1657 const struct connectdata *conn) | |
| 1658 { | |
| 1659 if((data->state.httpversion == 10) || (conn->httpversion == 10)) | |
| 1660 return FALSE; | |
| 1661 if((data->set.httpversion == CURL_HTTP_VERSION_1_0) && | |
| 1662 (conn->httpversion <= 10)) | |
| 1663 return FALSE; | |
| 1664 return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) || | |
| 1665 (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); | |
| 1666 } | |
| 1667 | |
| 1668 static const char *get_http_string(const struct Curl_easy *data, | |
| 1669 const struct connectdata *conn) | |
| 1670 { | |
| 1671 #ifdef ENABLE_QUIC | |
| 1672 if((data->set.httpversion == CURL_HTTP_VERSION_3) || | |
| 1673 (conn->httpversion == 30)) | |
| 1674 return "3"; | |
| 1675 #endif | |
| 1676 | |
| 1677 #ifdef USE_NGHTTP2 | |
| 1678 if(conn->proto.httpc.h2) | |
| 1679 return "2"; | |
| 1680 #endif | |
| 1681 | |
| 1682 if(use_http_1_1plus(data, conn)) | |
| 1683 return "1.1"; | |
| 1684 | |
| 1685 return "1.0"; | |
| 1686 } | |
| 1687 | |
| 1688 /* check and possibly add an Expect: header */ | |
| 1689 static CURLcode expect100(struct Curl_easy *data, | |
| 1690 struct connectdata *conn, | |
| 1691 Curl_send_buffer *req_buffer) | |
| 1692 { | |
| 1693 CURLcode result = CURLE_OK; | |
| 1694 data->state.expect100header = FALSE; /* default to false unless it is set | |
| 1695 to TRUE below */ | |
| 1696 if(use_http_1_1plus(data, conn) && | |
| 1697 (conn->httpversion < 20)) { | |
| 1698 /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an | |
| 1699 Expect: 100-continue to the headers which actually speeds up post | |
| 1700 operations (as there is one packet coming back from the web server) */ | |
| 1701 const char *ptr = Curl_checkheaders(conn, "Expect"); | |
| 1702 if(ptr) { | |
| 1703 data->state.expect100header = | |
| 1704 Curl_compareheader(ptr, "Expect:", "100-continue"); | |
| 1705 } | |
| 1706 else { | |
| 1707 result = Curl_add_bufferf(&req_buffer, | |
| 1708 "Expect: 100-continue\r\n"); | |
| 1709 if(!result) | |
| 1710 data->state.expect100header = TRUE; | |
| 1711 } | |
| 1712 } | |
| 1713 | |
| 1714 return result; | |
| 1715 } | |
| 1716 | |
| 1717 enum proxy_use { | |
| 1718 HEADER_SERVER, /* direct to server */ | |
| 1719 HEADER_PROXY, /* regular request to proxy */ | |
| 1720 HEADER_CONNECT /* sending CONNECT to a proxy */ | |
| 1721 }; | |
| 1722 | |
| 1723 /* used to compile the provided trailers into one buffer | |
| 1724 will return an error code if one of the headers is | |
| 1725 not formatted correctly */ | |
| 1726 CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, | |
| 1727 Curl_send_buffer **buffer, | |
| 1728 struct Curl_easy *handle) | |
| 1729 { | |
| 1730 char *ptr = NULL; | |
| 1731 CURLcode result = CURLE_OK; | |
| 1732 const char *endofline_native = NULL; | |
| 1733 const char *endofline_network = NULL; | |
| 1734 | |
| 1735 if( | |
| 1736 #ifdef CURL_DO_LINEEND_CONV | |
| 1737 (handle->set.prefer_ascii) || | |
| 1738 #endif | |
| 1739 (handle->set.crlf)) { | |
| 1740 /* \n will become \r\n later on */ | |
| 1741 endofline_native = "\n"; | |
| 1742 endofline_network = "\x0a"; | |
| 1743 } | |
| 1744 else { | |
| 1745 endofline_native = "\r\n"; | |
| 1746 endofline_network = "\x0d\x0a"; | |
| 1747 } | |
| 1748 | |
| 1749 while(trailers) { | |
| 1750 /* only add correctly formatted trailers */ | |
| 1751 ptr = strchr(trailers->data, ':'); | |
| 1752 if(ptr && *(ptr + 1) == ' ') { | |
| 1753 result = Curl_add_bufferf(buffer, "%s%s", trailers->data, | |
| 1754 endofline_native); | |
| 1755 if(result) | |
| 1756 return result; | |
| 1757 } | |
| 1758 else | |
| 1759 infof(handle, "Malformatted trailing header ! Skipping trailer."); | |
| 1760 trailers = trailers->next; | |
| 1761 } | |
| 1762 result = Curl_add_buffer(buffer, endofline_network, | |
| 1763 strlen(endofline_network)); | |
| 1764 return result; | |
| 1765 } | |
| 1766 | |
| 1767 CURLcode Curl_add_custom_headers(struct connectdata *conn, | |
| 1768 bool is_connect, | |
| 1769 Curl_send_buffer *req_buffer) | |
| 1770 { | |
| 1771 char *ptr; | |
| 1772 struct curl_slist *h[2]; | |
| 1773 struct curl_slist *headers; | |
| 1774 int numlists = 1; /* by default */ | |
| 1775 struct Curl_easy *data = conn->data; | |
| 1776 int i; | |
| 1777 | |
| 1778 enum proxy_use proxy; | |
| 1779 | |
| 1780 if(is_connect) | |
| 1781 proxy = HEADER_CONNECT; | |
| 1782 else | |
| 1783 proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? | |
| 1784 HEADER_PROXY:HEADER_SERVER; | |
| 1785 | |
| 1786 switch(proxy) { | |
| 1787 case HEADER_SERVER: | |
| 1788 h[0] = data->set.headers; | |
| 1789 break; | |
| 1790 case HEADER_PROXY: | |
| 1791 h[0] = data->set.headers; | |
| 1792 if(data->set.sep_headers) { | |
| 1793 h[1] = data->set.proxyheaders; | |
| 1794 numlists++; | |
| 1795 } | |
| 1796 break; | |
| 1797 case HEADER_CONNECT: | |
| 1798 if(data->set.sep_headers) | |
| 1799 h[0] = data->set.proxyheaders; | |
| 1800 else | |
| 1801 h[0] = data->set.headers; | |
| 1802 break; | |
| 1803 } | |
| 1804 | |
| 1805 /* loop through one or two lists */ | |
| 1806 for(i = 0; i < numlists; i++) { | |
| 1807 headers = h[i]; | |
| 1808 | |
| 1809 while(headers) { | |
| 1810 char *semicolonp = NULL; | |
| 1811 ptr = strchr(headers->data, ':'); | |
| 1812 if(!ptr) { | |
| 1813 char *optr; | |
| 1814 /* no colon, semicolon? */ | |
| 1815 ptr = strchr(headers->data, ';'); | |
| 1816 if(ptr) { | |
| 1817 optr = ptr; | |
| 1818 ptr++; /* pass the semicolon */ | |
| 1819 while(*ptr && ISSPACE(*ptr)) | |
| 1820 ptr++; | |
| 1821 | |
| 1822 if(*ptr) { | |
| 1823 /* this may be used for something else in the future */ | |
| 1824 optr = NULL; | |
| 1825 } | |
| 1826 else { | |
| 1827 if(*(--ptr) == ';') { | |
| 1828 /* copy the source */ | |
| 1829 semicolonp = strdup(headers->data); | |
| 1830 if(!semicolonp) { | |
| 1831 Curl_add_buffer_free(&req_buffer); | |
| 1832 return CURLE_OUT_OF_MEMORY; | |
| 1833 } | |
| 1834 /* put a colon where the semicolon is */ | |
| 1835 semicolonp[ptr - headers->data] = ':'; | |
| 1836 /* point at the colon */ | |
| 1837 optr = &semicolonp [ptr - headers->data]; | |
| 1838 } | |
| 1839 } | |
| 1840 ptr = optr; | |
| 1841 } | |
| 1842 } | |
| 1843 if(ptr) { | |
| 1844 /* we require a colon for this to be a true header */ | |
| 1845 | |
| 1846 ptr++; /* pass the colon */ | |
| 1847 while(*ptr && ISSPACE(*ptr)) | |
| 1848 ptr++; | |
| 1849 | |
| 1850 if(*ptr || semicolonp) { | |
| 1851 /* only send this if the contents was non-blank or done special */ | |
| 1852 CURLcode result = CURLE_OK; | |
| 1853 char *compare = semicolonp ? semicolonp : headers->data; | |
| 1854 | |
| 1855 if(conn->allocptr.host && | |
| 1856 /* a Host: header was sent already, don't pass on any custom Host: | |
| 1857 header as that will produce *two* in the same request! */ | |
| 1858 checkprefix("Host:", compare)) | |
| 1859 ; | |
| 1860 else if(data->set.httpreq == HTTPREQ_POST_FORM && | |
| 1861 /* this header (extended by formdata.c) is sent later */ | |
| 1862 checkprefix("Content-Type:", compare)) | |
| 1863 ; | |
| 1864 else if(data->set.httpreq == HTTPREQ_POST_MIME && | |
| 1865 /* this header is sent later */ | |
| 1866 checkprefix("Content-Type:", compare)) | |
| 1867 ; | |
| 1868 else if(conn->bits.authneg && | |
| 1869 /* while doing auth neg, don't allow the custom length since | |
| 1870 we will force length zero then */ | |
| 1871 checkprefix("Content-Length:", compare)) | |
| 1872 ; | |
| 1873 else if(conn->allocptr.te && | |
| 1874 /* when asking for Transfer-Encoding, don't pass on a custom | |
| 1875 Connection: */ | |
| 1876 checkprefix("Connection:", compare)) | |
| 1877 ; | |
| 1878 else if((conn->httpversion >= 20) && | |
| 1879 checkprefix("Transfer-Encoding:", compare)) | |
| 1880 /* HTTP/2 doesn't support chunked requests */ | |
| 1881 ; | |
| 1882 else if((checkprefix("Authorization:", compare) || | |
| 1883 checkprefix("Cookie:", compare)) && | |
| 1884 /* be careful of sending this potentially sensitive header to | |
| 1885 other hosts */ | |
| 1886 (data->state.this_is_a_follow && | |
| 1887 data->state.first_host && | |
| 1888 !data->set.allow_auth_to_other_hosts && | |
| 1889 !strcasecompare(data->state.first_host, conn->host.name))) | |
| 1890 ; | |
| 1891 else { | |
| 1892 result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); | |
| 1893 } | |
| 1894 if(semicolonp) | |
| 1895 free(semicolonp); | |
| 1896 if(result) | |
| 1897 return result; | |
| 1898 } | |
| 1899 } | |
| 1900 headers = headers->next; | |
| 1901 } | |
| 1902 } | |
| 1903 | |
| 1904 return CURLE_OK; | |
| 1905 } | |
| 1906 | |
| 1907 #ifndef CURL_DISABLE_PARSEDATE | |
| 1908 CURLcode Curl_add_timecondition(const struct connectdata *conn, | |
| 1909 Curl_send_buffer *req_buffer) | |
| 1910 { | |
| 1911 struct Curl_easy *data = conn->data; | |
| 1912 const struct tm *tm; | |
| 1913 struct tm keeptime; | |
| 1914 CURLcode result; | |
| 1915 char datestr[80]; | |
| 1916 const char *condp; | |
| 1917 | |
| 1918 if(data->set.timecondition == CURL_TIMECOND_NONE) | |
| 1919 /* no condition was asked for */ | |
| 1920 return CURLE_OK; | |
| 1921 | |
| 1922 result = Curl_gmtime(data->set.timevalue, &keeptime); | |
| 1923 if(result) { | |
| 1924 failf(data, "Invalid TIMEVALUE"); | |
| 1925 return result; | |
| 1926 } | |
| 1927 tm = &keeptime; | |
| 1928 | |
| 1929 switch(data->set.timecondition) { | |
| 1930 default: | |
| 1931 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 1932 | |
| 1933 case CURL_TIMECOND_IFMODSINCE: | |
| 1934 condp = "If-Modified-Since"; | |
| 1935 break; | |
| 1936 case CURL_TIMECOND_IFUNMODSINCE: | |
| 1937 condp = "If-Unmodified-Since"; | |
| 1938 break; | |
| 1939 case CURL_TIMECOND_LASTMOD: | |
| 1940 condp = "Last-Modified"; | |
| 1941 break; | |
| 1942 } | |
| 1943 | |
| 1944 if(Curl_checkheaders(conn, condp)) { | |
| 1945 /* A custom header was specified; it will be sent instead. */ | |
| 1946 return CURLE_OK; | |
| 1947 } | |
| 1948 | |
| 1949 /* The If-Modified-Since header family should have their times set in | |
| 1950 * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be | |
| 1951 * represented in Greenwich Mean Time (GMT), without exception. For the | |
| 1952 * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal | |
| 1953 * Time)." (see page 20 of RFC2616). | |
| 1954 */ | |
| 1955 | |
| 1956 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ | |
| 1957 msnprintf(datestr, sizeof(datestr), | |
| 1958 "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", | |
| 1959 condp, | |
| 1960 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], | |
| 1961 tm->tm_mday, | |
| 1962 Curl_month[tm->tm_mon], | |
| 1963 tm->tm_year + 1900, | |
| 1964 tm->tm_hour, | |
| 1965 tm->tm_min, | |
| 1966 tm->tm_sec); | |
| 1967 | |
| 1968 result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); | |
| 1969 | |
| 1970 return result; | |
| 1971 } | |
| 1972 #else | |
| 1973 /* disabled */ | |
| 1974 CURLcode Curl_add_timecondition(const struct connectdata *conn, | |
| 1975 Curl_send_buffer *req_buffer) | |
| 1976 { | |
| 1977 (void)conn; | |
| 1978 (void)req_buffer; | |
| 1979 return CURLE_OK; | |
| 1980 } | |
| 1981 #endif | |
| 1982 | |
| 1983 /* | |
| 1984 * Curl_http() gets called from the generic multi_do() function when a HTTP | |
| 1985 * request is to be performed. This creates and sends a properly constructed | |
| 1986 * HTTP request. | |
| 1987 */ | |
| 1988 CURLcode Curl_http(struct connectdata *conn, bool *done) | |
| 1989 { | |
| 1990 struct Curl_easy *data = conn->data; | |
| 1991 CURLcode result = CURLE_OK; | |
| 1992 struct HTTP *http; | |
| 1993 const char *path = data->state.up.path; | |
| 1994 const char *query = data->state.up.query; | |
| 1995 bool paste_ftp_userpwd = FALSE; | |
| 1996 char ftp_typecode[sizeof("/;type=?")] = ""; | |
| 1997 const char *host = conn->host.name; | |
| 1998 const char *te = ""; /* transfer-encoding */ | |
| 1999 const char *ptr; | |
| 2000 const char *request; | |
| 2001 Curl_HttpReq httpreq = data->set.httpreq; | |
| 2002 #if !defined(CURL_DISABLE_COOKIES) | |
| 2003 char *addcookies = NULL; | |
| 2004 #endif | |
| 2005 curl_off_t included_body = 0; | |
| 2006 const char *httpstring; | |
| 2007 Curl_send_buffer *req_buffer; | |
| 2008 curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ | |
| 2009 char *altused = NULL; | |
| 2010 | |
| 2011 /* Always consider the DO phase done after this function call, even if there | |
| 2012 may be parts of the request that is not yet sent, since we can deal with | |
| 2013 the rest of the request in the PERFORM phase. */ | |
| 2014 *done = TRUE; | |
| 2015 | |
| 2016 if(conn->transport != TRNSPRT_QUIC) { | |
| 2017 if(conn->httpversion < 20) { /* unless the connection is re-used and | |
| 2018 already http2 */ | |
| 2019 switch(conn->negnpn) { | |
| 2020 case CURL_HTTP_VERSION_2: | |
| 2021 conn->httpversion = 20; /* we know we're on HTTP/2 now */ | |
| 2022 | |
| 2023 result = Curl_http2_switched(conn, NULL, 0); | |
| 2024 if(result) | |
| 2025 return result; | |
| 2026 break; | |
| 2027 case CURL_HTTP_VERSION_1_1: | |
| 2028 /* continue with HTTP/1.1 when explicitly requested */ | |
| 2029 break; | |
| 2030 default: | |
| 2031 /* Check if user wants to use HTTP/2 with clear TCP*/ | |
| 2032 #ifdef USE_NGHTTP2 | |
| 2033 if(conn->data->set.httpversion == | |
| 2034 CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { | |
| 2035 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { | |
| 2036 /* We don't support HTTP/2 proxies yet. Also it's debatable | |
| 2037 whether or not this setting should apply to HTTP/2 proxies. */ | |
| 2038 infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n"); | |
| 2039 break; | |
| 2040 } | |
| 2041 | |
| 2042 DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); | |
| 2043 conn->httpversion = 20; | |
| 2044 | |
| 2045 result = Curl_http2_switched(conn, NULL, 0); | |
| 2046 if(result) | |
| 2047 return result; | |
| 2048 } | |
| 2049 #endif | |
| 2050 break; | |
| 2051 } | |
| 2052 } | |
| 2053 else { | |
| 2054 /* prepare for a http2 request */ | |
| 2055 result = Curl_http2_setup(conn); | |
| 2056 if(result) | |
| 2057 return result; | |
| 2058 } | |
| 2059 } | |
| 2060 http = data->req.protop; | |
| 2061 DEBUGASSERT(http); | |
| 2062 | |
| 2063 if(!data->state.this_is_a_follow) { | |
| 2064 /* Free to avoid leaking memory on multiple requests*/ | |
| 2065 free(data->state.first_host); | |
| 2066 | |
| 2067 data->state.first_host = strdup(conn->host.name); | |
| 2068 if(!data->state.first_host) | |
| 2069 return CURLE_OUT_OF_MEMORY; | |
| 2070 | |
| 2071 data->state.first_remote_port = conn->remote_port; | |
| 2072 } | |
| 2073 | |
| 2074 if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && | |
| 2075 data->set.upload) { | |
| 2076 httpreq = HTTPREQ_PUT; | |
| 2077 } | |
| 2078 | |
| 2079 /* Now set the 'request' pointer to the proper request string */ | |
| 2080 if(data->set.str[STRING_CUSTOMREQUEST]) | |
| 2081 request = data->set.str[STRING_CUSTOMREQUEST]; | |
| 2082 else { | |
| 2083 if(data->set.opt_no_body) | |
| 2084 request = "HEAD"; | |
| 2085 else { | |
| 2086 DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST)); | |
| 2087 switch(httpreq) { | |
| 2088 case HTTPREQ_POST: | |
| 2089 case HTTPREQ_POST_FORM: | |
| 2090 case HTTPREQ_POST_MIME: | |
| 2091 request = "POST"; | |
| 2092 break; | |
| 2093 case HTTPREQ_PUT: | |
| 2094 request = "PUT"; | |
| 2095 break; | |
| 2096 case HTTPREQ_OPTIONS: | |
| 2097 request = "OPTIONS"; | |
| 2098 break; | |
| 2099 default: /* this should never happen */ | |
| 2100 case HTTPREQ_GET: | |
| 2101 request = "GET"; | |
| 2102 break; | |
| 2103 case HTTPREQ_HEAD: | |
| 2104 request = "HEAD"; | |
| 2105 break; | |
| 2106 } | |
| 2107 } | |
| 2108 } | |
| 2109 | |
| 2110 /* The User-Agent string might have been allocated in url.c already, because | |
| 2111 it might have been used in the proxy connect, but if we have got a header | |
| 2112 with the user-agent string specified, we erase the previously made string | |
| 2113 here. */ | |
| 2114 if(Curl_checkheaders(conn, "User-Agent")) { | |
| 2115 free(conn->allocptr.uagent); | |
| 2116 conn->allocptr.uagent = NULL; | |
| 2117 } | |
| 2118 | |
| 2119 /* setup the authentication headers */ | |
| 2120 { | |
| 2121 char *pq = NULL; | |
| 2122 if(query && *query) { | |
| 2123 pq = aprintf("%s?%s", path, query); | |
| 2124 if(!pq) | |
| 2125 return CURLE_OUT_OF_MEMORY; | |
| 2126 } | |
| 2127 result = Curl_http_output_auth(conn, request, (pq ? pq : path), FALSE); | |
| 2128 free(pq); | |
| 2129 if(result) | |
| 2130 return result; | |
| 2131 } | |
| 2132 | |
| 2133 if(((data->state.authhost.multipass && !data->state.authhost.done) | |
| 2134 || (data->state.authproxy.multipass && !data->state.authproxy.done)) && | |
| 2135 (httpreq != HTTPREQ_GET) && | |
| 2136 (httpreq != HTTPREQ_HEAD)) { | |
| 2137 /* Auth is required and we are not authenticated yet. Make a PUT or POST | |
| 2138 with content-length zero as a "probe". */ | |
| 2139 conn->bits.authneg = TRUE; | |
| 2140 } | |
| 2141 else | |
| 2142 conn->bits.authneg = FALSE; | |
| 2143 | |
| 2144 Curl_safefree(conn->allocptr.ref); | |
| 2145 if(data->change.referer && !Curl_checkheaders(conn, "Referer")) { | |
| 2146 conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); | |
| 2147 if(!conn->allocptr.ref) | |
| 2148 return CURLE_OUT_OF_MEMORY; | |
| 2149 } | |
| 2150 else | |
| 2151 conn->allocptr.ref = NULL; | |
| 2152 | |
| 2153 #if !defined(CURL_DISABLE_COOKIES) | |
| 2154 if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie")) | |
| 2155 addcookies = data->set.str[STRING_COOKIE]; | |
| 2156 #endif | |
| 2157 | |
| 2158 if(!Curl_checkheaders(conn, "Accept-Encoding") && | |
| 2159 data->set.str[STRING_ENCODING]) { | |
| 2160 Curl_safefree(conn->allocptr.accept_encoding); | |
| 2161 conn->allocptr.accept_encoding = | |
| 2162 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); | |
| 2163 if(!conn->allocptr.accept_encoding) | |
| 2164 return CURLE_OUT_OF_MEMORY; | |
| 2165 } | |
| 2166 else { | |
| 2167 Curl_safefree(conn->allocptr.accept_encoding); | |
| 2168 conn->allocptr.accept_encoding = NULL; | |
| 2169 } | |
| 2170 | |
| 2171 #ifdef HAVE_LIBZ | |
| 2172 /* we only consider transfer-encoding magic if libz support is built-in */ | |
| 2173 | |
| 2174 if(!Curl_checkheaders(conn, "TE") && | |
| 2175 data->set.http_transfer_encoding) { | |
| 2176 /* When we are to insert a TE: header in the request, we must also insert | |
| 2177 TE in a Connection: header, so we need to merge the custom provided | |
| 2178 Connection: header and prevent the original to get sent. Note that if | |
| 2179 the user has inserted his/hers own TE: header we don't do this magic | |
| 2180 but then assume that the user will handle it all! */ | |
| 2181 char *cptr = Curl_checkheaders(conn, "Connection"); | |
| 2182 #define TE_HEADER "TE: gzip\r\n" | |
| 2183 | |
| 2184 Curl_safefree(conn->allocptr.te); | |
| 2185 | |
| 2186 if(cptr) { | |
| 2187 cptr = Curl_copy_header_value(cptr); | |
| 2188 if(!cptr) | |
| 2189 return CURLE_OUT_OF_MEMORY; | |
| 2190 } | |
| 2191 | |
| 2192 /* Create the (updated) Connection: header */ | |
| 2193 conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, | |
| 2194 cptr ? cptr : "", (cptr && *cptr) ? ", ":""); | |
| 2195 | |
| 2196 free(cptr); | |
| 2197 if(!conn->allocptr.te) | |
| 2198 return CURLE_OUT_OF_MEMORY; | |
| 2199 } | |
| 2200 #endif | |
| 2201 | |
| 2202 switch(httpreq) { | |
| 2203 case HTTPREQ_POST_MIME: | |
| 2204 http->sendit = &data->set.mimepost; | |
| 2205 break; | |
| 2206 case HTTPREQ_POST_FORM: | |
| 2207 /* Convert the form structure into a mime structure. */ | |
| 2208 Curl_mime_cleanpart(&http->form); | |
| 2209 result = Curl_getformdata(data, &http->form, data->set.httppost, | |
| 2210 data->state.fread_func); | |
| 2211 if(result) | |
| 2212 return result; | |
| 2213 http->sendit = &http->form; | |
| 2214 break; | |
| 2215 default: | |
| 2216 http->sendit = NULL; | |
| 2217 } | |
| 2218 | |
| 2219 #ifndef CURL_DISABLE_MIME | |
| 2220 if(http->sendit) { | |
| 2221 const char *cthdr = Curl_checkheaders(conn, "Content-Type"); | |
| 2222 | |
| 2223 /* Read and seek body only. */ | |
| 2224 http->sendit->flags |= MIME_BODY_ONLY; | |
| 2225 | |
| 2226 /* Prepare the mime structure headers & set content type. */ | |
| 2227 | |
| 2228 if(cthdr) | |
| 2229 for(cthdr += 13; *cthdr == ' '; cthdr++) | |
| 2230 ; | |
| 2231 else if(http->sendit->kind == MIMEKIND_MULTIPART) | |
| 2232 cthdr = "multipart/form-data"; | |
| 2233 | |
| 2234 curl_mime_headers(http->sendit, data->set.headers, 0); | |
| 2235 result = Curl_mime_prepare_headers(http->sendit, cthdr, | |
| 2236 NULL, MIMESTRATEGY_FORM); | |
| 2237 curl_mime_headers(http->sendit, NULL, 0); | |
| 2238 if(!result) | |
| 2239 result = Curl_mime_rewind(http->sendit); | |
| 2240 if(result) | |
| 2241 return result; | |
| 2242 http->postsize = Curl_mime_size(http->sendit); | |
| 2243 } | |
| 2244 #endif | |
| 2245 | |
| 2246 ptr = Curl_checkheaders(conn, "Transfer-Encoding"); | |
| 2247 if(ptr) { | |
| 2248 /* Some kind of TE is requested, check if 'chunked' is chosen */ | |
| 2249 data->req.upload_chunky = | |
| 2250 Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); | |
| 2251 } | |
| 2252 else { | |
| 2253 if((conn->handler->protocol & PROTO_FAMILY_HTTP) && | |
| 2254 (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && | |
| 2255 http->postsize < 0) || | |
| 2256 ((data->set.upload || httpreq == HTTPREQ_POST) && | |
| 2257 data->state.infilesize == -1))) { | |
| 2258 if(conn->bits.authneg) | |
| 2259 /* don't enable chunked during auth neg */ | |
| 2260 ; | |
| 2261 else if(use_http_1_1plus(data, conn)) { | |
| 2262 if(conn->httpversion < 20) | |
| 2263 /* HTTP, upload, unknown file size and not HTTP 1.0 */ | |
| 2264 data->req.upload_chunky = TRUE; | |
| 2265 } | |
| 2266 else { | |
| 2267 failf(data, "Chunky upload is not supported by HTTP 1.0"); | |
| 2268 return CURLE_UPLOAD_FAILED; | |
| 2269 } | |
| 2270 } | |
| 2271 else { | |
| 2272 /* else, no chunky upload */ | |
| 2273 data->req.upload_chunky = FALSE; | |
| 2274 } | |
| 2275 | |
| 2276 if(data->req.upload_chunky) | |
| 2277 te = "Transfer-Encoding: chunked\r\n"; | |
| 2278 } | |
| 2279 | |
| 2280 Curl_safefree(conn->allocptr.host); | |
| 2281 | |
| 2282 ptr = Curl_checkheaders(conn, "Host"); | |
| 2283 if(ptr && (!data->state.this_is_a_follow || | |
| 2284 strcasecompare(data->state.first_host, conn->host.name))) { | |
| 2285 #if !defined(CURL_DISABLE_COOKIES) | |
| 2286 /* If we have a given custom Host: header, we extract the host name in | |
| 2287 order to possibly use it for cookie reasons later on. We only allow the | |
| 2288 custom Host: header if this is NOT a redirect, as setting Host: in the | |
| 2289 redirected request is being out on thin ice. Except if the host name | |
| 2290 is the same as the first one! */ | |
| 2291 char *cookiehost = Curl_copy_header_value(ptr); | |
| 2292 if(!cookiehost) | |
| 2293 return CURLE_OUT_OF_MEMORY; | |
| 2294 if(!*cookiehost) | |
| 2295 /* ignore empty data */ | |
| 2296 free(cookiehost); | |
| 2297 else { | |
| 2298 /* If the host begins with '[', we start searching for the port after | |
| 2299 the bracket has been closed */ | |
| 2300 if(*cookiehost == '[') { | |
| 2301 char *closingbracket; | |
| 2302 /* since the 'cookiehost' is an allocated memory area that will be | |
| 2303 freed later we cannot simply increment the pointer */ | |
| 2304 memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); | |
| 2305 closingbracket = strchr(cookiehost, ']'); | |
| 2306 if(closingbracket) | |
| 2307 *closingbracket = 0; | |
| 2308 } | |
| 2309 else { | |
| 2310 int startsearch = 0; | |
| 2311 char *colon = strchr(cookiehost + startsearch, ':'); | |
| 2312 if(colon) | |
| 2313 *colon = 0; /* The host must not include an embedded port number */ | |
| 2314 } | |
| 2315 Curl_safefree(conn->allocptr.cookiehost); | |
| 2316 conn->allocptr.cookiehost = cookiehost; | |
| 2317 } | |
| 2318 #endif | |
| 2319 | |
| 2320 if(strcmp("Host:", ptr)) { | |
| 2321 conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]); | |
| 2322 if(!conn->allocptr.host) | |
| 2323 return CURLE_OUT_OF_MEMORY; | |
| 2324 } | |
| 2325 else | |
| 2326 /* when clearing the header */ | |
| 2327 conn->allocptr.host = NULL; | |
| 2328 } | |
| 2329 else { | |
| 2330 /* When building Host: headers, we must put the host name within | |
| 2331 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ | |
| 2332 | |
| 2333 if(((conn->given->protocol&CURLPROTO_HTTPS) && | |
| 2334 (conn->remote_port == PORT_HTTPS)) || | |
| 2335 ((conn->given->protocol&CURLPROTO_HTTP) && | |
| 2336 (conn->remote_port == PORT_HTTP)) ) | |
| 2337 /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include | |
| 2338 the port number in the host string */ | |
| 2339 conn->allocptr.host = aprintf("Host: %s%s%s\r\n", | |
| 2340 conn->bits.ipv6_ip?"[":"", | |
| 2341 host, | |
| 2342 conn->bits.ipv6_ip?"]":""); | |
| 2343 else | |
| 2344 conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", | |
| 2345 conn->bits.ipv6_ip?"[":"", | |
| 2346 host, | |
| 2347 conn->bits.ipv6_ip?"]":"", | |
| 2348 conn->remote_port); | |
| 2349 | |
| 2350 if(!conn->allocptr.host) | |
| 2351 /* without Host: we can't make a nice request */ | |
| 2352 return CURLE_OUT_OF_MEMORY; | |
| 2353 } | |
| 2354 | |
| 2355 #ifndef CURL_DISABLE_PROXY | |
| 2356 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { | |
| 2357 /* Using a proxy but does not tunnel through it */ | |
| 2358 | |
| 2359 /* The path sent to the proxy is in fact the entire URL. But if the remote | |
| 2360 host is a IDN-name, we must make sure that the request we produce only | |
| 2361 uses the encoded host name! */ | |
| 2362 | |
| 2363 /* and no fragment part */ | |
| 2364 CURLUcode uc; | |
| 2365 CURLU *h = curl_url_dup(data->state.uh); | |
| 2366 if(!h) | |
| 2367 return CURLE_OUT_OF_MEMORY; | |
| 2368 | |
| 2369 if(conn->host.dispname != conn->host.name) { | |
| 2370 uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); | |
| 2371 if(uc) { | |
| 2372 curl_url_cleanup(h); | |
| 2373 return CURLE_OUT_OF_MEMORY; | |
| 2374 } | |
| 2375 } | |
| 2376 uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0); | |
| 2377 if(uc) { | |
| 2378 curl_url_cleanup(h); | |
| 2379 return CURLE_OUT_OF_MEMORY; | |
| 2380 } | |
| 2381 | |
| 2382 if(strcasecompare("http", data->state.up.scheme)) { | |
| 2383 /* when getting HTTP, we don't want the userinfo the URL */ | |
| 2384 uc = curl_url_set(h, CURLUPART_USER, NULL, 0); | |
| 2385 if(uc) { | |
| 2386 curl_url_cleanup(h); | |
| 2387 return CURLE_OUT_OF_MEMORY; | |
| 2388 } | |
| 2389 uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0); | |
| 2390 if(uc) { | |
| 2391 curl_url_cleanup(h); | |
| 2392 return CURLE_OUT_OF_MEMORY; | |
| 2393 } | |
| 2394 } | |
| 2395 /* Extract the the URL to use in the request. Store in STRING_TEMP_URL for | |
| 2396 clean-up reasons if the function returns before the free() further | |
| 2397 down. */ | |
| 2398 uc = curl_url_get(h, CURLUPART_URL, &data->set.str[STRING_TEMP_URL], 0); | |
| 2399 if(uc) { | |
| 2400 curl_url_cleanup(h); | |
| 2401 return CURLE_OUT_OF_MEMORY; | |
| 2402 } | |
| 2403 | |
| 2404 curl_url_cleanup(h); | |
| 2405 | |
| 2406 if(strcasecompare("ftp", data->state.up.scheme)) { | |
| 2407 if(data->set.proxy_transfer_mode) { | |
| 2408 /* when doing ftp, append ;type=<a|i> if not present */ | |
| 2409 char *type = strstr(path, ";type="); | |
| 2410 if(type && type[6] && type[7] == 0) { | |
| 2411 switch(Curl_raw_toupper(type[6])) { | |
| 2412 case 'A': | |
| 2413 case 'D': | |
| 2414 case 'I': | |
| 2415 break; | |
| 2416 default: | |
| 2417 type = NULL; | |
| 2418 } | |
| 2419 } | |
| 2420 if(!type) { | |
| 2421 char *p = ftp_typecode; | |
| 2422 /* avoid sending invalid URLs like ftp://example.com;type=i if the | |
| 2423 * user specified ftp://example.com without the slash */ | |
| 2424 if(!*data->state.up.path && path[strlen(path) - 1] != '/') { | |
| 2425 *p++ = '/'; | |
| 2426 } | |
| 2427 msnprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", | |
| 2428 data->set.prefer_ascii ? 'a' : 'i'); | |
| 2429 } | |
| 2430 } | |
| 2431 if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) | |
| 2432 paste_ftp_userpwd = TRUE; | |
| 2433 } | |
| 2434 } | |
| 2435 #endif /* CURL_DISABLE_PROXY */ | |
| 2436 | |
| 2437 http->p_accept = Curl_checkheaders(conn, "Accept")?NULL:"Accept: */*\r\n"; | |
| 2438 | |
| 2439 if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && | |
| 2440 data->state.resume_from) { | |
| 2441 /********************************************************************** | |
| 2442 * Resuming upload in HTTP means that we PUT or POST and that we have | |
| 2443 * got a resume_from value set. The resume value has already created | |
| 2444 * a Range: header that will be passed along. We need to "fast forward" | |
| 2445 * the file the given number of bytes and decrease the assume upload | |
| 2446 * file size before we continue this venture in the dark lands of HTTP. | |
| 2447 * Resuming mime/form posting at an offset > 0 has no sense and is ignored. | |
| 2448 *********************************************************************/ | |
| 2449 | |
| 2450 if(data->state.resume_from < 0) { | |
| 2451 /* | |
| 2452 * This is meant to get the size of the present remote-file by itself. | |
| 2453 * We don't support this now. Bail out! | |
| 2454 */ | |
| 2455 data->state.resume_from = 0; | |
| 2456 } | |
| 2457 | |
| 2458 if(data->state.resume_from && !data->state.this_is_a_follow) { | |
| 2459 /* do we still game? */ | |
| 2460 | |
| 2461 /* Now, let's read off the proper amount of bytes from the | |
| 2462 input. */ | |
| 2463 int seekerr = CURL_SEEKFUNC_CANTSEEK; | |
| 2464 if(conn->seek_func) { | |
| 2465 Curl_set_in_callback(data, true); | |
| 2466 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, | |
| 2467 SEEK_SET); | |
| 2468 Curl_set_in_callback(data, false); | |
| 2469 } | |
| 2470 | |
| 2471 if(seekerr != CURL_SEEKFUNC_OK) { | |
| 2472 curl_off_t passed = 0; | |
| 2473 | |
| 2474 if(seekerr != CURL_SEEKFUNC_CANTSEEK) { | |
| 2475 failf(data, "Could not seek stream"); | |
| 2476 return CURLE_READ_ERROR; | |
| 2477 } | |
| 2478 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ | |
| 2479 do { | |
| 2480 size_t readthisamountnow = | |
| 2481 (data->state.resume_from - passed > data->set.buffer_size) ? | |
| 2482 (size_t)data->set.buffer_size : | |
| 2483 curlx_sotouz(data->state.resume_from - passed); | |
| 2484 | |
| 2485 size_t actuallyread = | |
| 2486 data->state.fread_func(data->state.buffer, 1, readthisamountnow, | |
| 2487 data->state.in); | |
| 2488 | |
| 2489 passed += actuallyread; | |
| 2490 if((actuallyread == 0) || (actuallyread > readthisamountnow)) { | |
| 2491 /* this checks for greater-than only to make sure that the | |
| 2492 CURL_READFUNC_ABORT return code still aborts */ | |
| 2493 failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T | |
| 2494 " bytes from the input", passed); | |
| 2495 return CURLE_READ_ERROR; | |
| 2496 } | |
| 2497 } while(passed < data->state.resume_from); | |
| 2498 } | |
| 2499 | |
| 2500 /* now, decrease the size of the read */ | |
| 2501 if(data->state.infilesize>0) { | |
| 2502 data->state.infilesize -= data->state.resume_from; | |
| 2503 | |
| 2504 if(data->state.infilesize <= 0) { | |
| 2505 failf(data, "File already completely uploaded"); | |
| 2506 return CURLE_PARTIAL_FILE; | |
| 2507 } | |
| 2508 } | |
| 2509 /* we've passed, proceed as normal */ | |
| 2510 } | |
| 2511 } | |
| 2512 if(data->state.use_range) { | |
| 2513 /* | |
| 2514 * A range is selected. We use different headers whether we're downloading | |
| 2515 * or uploading and we always let customized headers override our internal | |
| 2516 * ones if any such are specified. | |
| 2517 */ | |
| 2518 if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && | |
| 2519 !Curl_checkheaders(conn, "Range")) { | |
| 2520 /* if a line like this was already allocated, free the previous one */ | |
| 2521 free(conn->allocptr.rangeline); | |
| 2522 conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", | |
| 2523 data->state.range); | |
| 2524 } | |
| 2525 else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && | |
| 2526 !Curl_checkheaders(conn, "Content-Range")) { | |
| 2527 | |
| 2528 /* if a line like this was already allocated, free the previous one */ | |
| 2529 free(conn->allocptr.rangeline); | |
| 2530 | |
| 2531 if(data->set.set_resume_from < 0) { | |
| 2532 /* Upload resume was asked for, but we don't know the size of the | |
| 2533 remote part so we tell the server (and act accordingly) that we | |
| 2534 upload the whole file (again) */ | |
| 2535 conn->allocptr.rangeline = | |
| 2536 aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T | |
| 2537 "/%" CURL_FORMAT_CURL_OFF_T "\r\n", | |
| 2538 data->state.infilesize - 1, data->state.infilesize); | |
| 2539 | |
| 2540 } | |
| 2541 else if(data->state.resume_from) { | |
| 2542 /* This is because "resume" was selected */ | |
| 2543 curl_off_t total_expected_size = | |
| 2544 data->state.resume_from + data->state.infilesize; | |
| 2545 conn->allocptr.rangeline = | |
| 2546 aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T | |
| 2547 "/%" CURL_FORMAT_CURL_OFF_T "\r\n", | |
| 2548 data->state.range, total_expected_size-1, | |
| 2549 total_expected_size); | |
| 2550 } | |
| 2551 else { | |
| 2552 /* Range was selected and then we just pass the incoming range and | |
| 2553 append total size */ | |
| 2554 conn->allocptr.rangeline = | |
| 2555 aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", | |
| 2556 data->state.range, data->state.infilesize); | |
| 2557 } | |
| 2558 if(!conn->allocptr.rangeline) | |
| 2559 return CURLE_OUT_OF_MEMORY; | |
| 2560 } | |
| 2561 } | |
| 2562 | |
| 2563 httpstring = get_http_string(data, conn); | |
| 2564 | |
| 2565 /* initialize a dynamic send-buffer */ | |
| 2566 req_buffer = Curl_add_buffer_init(); | |
| 2567 | |
| 2568 if(!req_buffer) | |
| 2569 return CURLE_OUT_OF_MEMORY; | |
| 2570 | |
| 2571 /* add the main request stuff */ | |
| 2572 /* GET/HEAD/POST/PUT */ | |
| 2573 result = Curl_add_bufferf(&req_buffer, "%s ", request); | |
| 2574 if(result) | |
| 2575 return result; | |
| 2576 | |
| 2577 if(data->set.str[STRING_TARGET]) { | |
| 2578 path = data->set.str[STRING_TARGET]; | |
| 2579 query = NULL; | |
| 2580 } | |
| 2581 | |
| 2582 #ifndef CURL_DISABLE_PROXY | |
| 2583 /* url */ | |
| 2584 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { | |
| 2585 char *url = data->set.str[STRING_TEMP_URL]; | |
| 2586 result = Curl_add_buffer(&req_buffer, url, strlen(url)); | |
| 2587 Curl_safefree(data->set.str[STRING_TEMP_URL]); | |
| 2588 } | |
| 2589 else | |
| 2590 #endif | |
| 2591 if(paste_ftp_userpwd) | |
| 2592 result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", | |
| 2593 conn->user, conn->passwd, | |
| 2594 path + sizeof("ftp://") - 1); | |
| 2595 else { | |
| 2596 result = Curl_add_buffer(&req_buffer, path, strlen(path)); | |
| 2597 if(result) | |
| 2598 return result; | |
| 2599 if(query) | |
| 2600 result = Curl_add_bufferf(&req_buffer, "?%s", query); | |
| 2601 } | |
| 2602 if(result) | |
| 2603 return result; | |
| 2604 | |
| 2605 #ifdef USE_ALTSVC | |
| 2606 if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) { | |
| 2607 altused = aprintf("Alt-Used: %s:%d\r\n", | |
| 2608 conn->conn_to_host.name, conn->conn_to_port); | |
| 2609 if(!altused) | |
| 2610 return CURLE_OUT_OF_MEMORY; | |
| 2611 } | |
| 2612 #endif | |
| 2613 result = | |
| 2614 Curl_add_bufferf(&req_buffer, | |
| 2615 "%s" /* ftp typecode (;type=x) */ | |
| 2616 " HTTP/%s\r\n" /* HTTP version */ | |
| 2617 "%s" /* host */ | |
| 2618 "%s" /* proxyuserpwd */ | |
| 2619 "%s" /* userpwd */ | |
| 2620 "%s" /* range */ | |
| 2621 "%s" /* user agent */ | |
| 2622 "%s" /* accept */ | |
| 2623 "%s" /* TE: */ | |
| 2624 "%s" /* accept-encoding */ | |
| 2625 "%s" /* referer */ | |
| 2626 "%s" /* Proxy-Connection */ | |
| 2627 "%s" /* transfer-encoding */ | |
| 2628 "%s",/* Alt-Used */ | |
| 2629 | |
| 2630 ftp_typecode, | |
| 2631 httpstring, | |
| 2632 (conn->allocptr.host?conn->allocptr.host:""), | |
| 2633 conn->allocptr.proxyuserpwd? | |
| 2634 conn->allocptr.proxyuserpwd:"", | |
| 2635 conn->allocptr.userpwd?conn->allocptr.userpwd:"", | |
| 2636 (data->state.use_range && conn->allocptr.rangeline)? | |
| 2637 conn->allocptr.rangeline:"", | |
| 2638 (data->set.str[STRING_USERAGENT] && | |
| 2639 *data->set.str[STRING_USERAGENT] && | |
| 2640 conn->allocptr.uagent)? | |
| 2641 conn->allocptr.uagent:"", | |
| 2642 http->p_accept?http->p_accept:"", | |
| 2643 conn->allocptr.te?conn->allocptr.te:"", | |
| 2644 (data->set.str[STRING_ENCODING] && | |
| 2645 *data->set.str[STRING_ENCODING] && | |
| 2646 conn->allocptr.accept_encoding)? | |
| 2647 conn->allocptr.accept_encoding:"", | |
| 2648 (data->change.referer && conn->allocptr.ref)? | |
| 2649 conn->allocptr.ref:"" /* Referer: <data> */, | |
| 2650 (conn->bits.httpproxy && | |
| 2651 !conn->bits.tunnel_proxy && | |
| 2652 !Curl_checkProxyheaders(conn, "Proxy-Connection"))? | |
| 2653 "Proxy-Connection: Keep-Alive\r\n":"", | |
| 2654 te, | |
| 2655 altused ? altused : "" | |
| 2656 ); | |
| 2657 | |
| 2658 /* clear userpwd and proxyuserpwd to avoid re-using old credentials | |
| 2659 * from re-used connections */ | |
| 2660 Curl_safefree(conn->allocptr.userpwd); | |
| 2661 Curl_safefree(conn->allocptr.proxyuserpwd); | |
| 2662 free(altused); | |
| 2663 | |
| 2664 if(result) | |
| 2665 return result; | |
| 2666 | |
| 2667 if(!(conn->handler->flags&PROTOPT_SSL) && | |
| 2668 conn->httpversion != 20 && | |
| 2669 (data->set.httpversion == CURL_HTTP_VERSION_2)) { | |
| 2670 /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done | |
| 2671 over SSL */ | |
| 2672 result = Curl_http2_request_upgrade(req_buffer, conn); | |
| 2673 if(result) | |
| 2674 return result; | |
| 2675 } | |
| 2676 | |
| 2677 #if !defined(CURL_DISABLE_COOKIES) | |
| 2678 if(data->cookies || addcookies) { | |
| 2679 struct Cookie *co = NULL; /* no cookies from start */ | |
| 2680 int count = 0; | |
| 2681 | |
| 2682 if(data->cookies) { | |
| 2683 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); | |
| 2684 co = Curl_cookie_getlist(data->cookies, | |
| 2685 conn->allocptr.cookiehost? | |
| 2686 conn->allocptr.cookiehost:host, | |
| 2687 data->state.up.path, | |
| 2688 (conn->handler->protocol&CURLPROTO_HTTPS)? | |
| 2689 TRUE:FALSE); | |
| 2690 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); | |
| 2691 } | |
| 2692 if(co) { | |
| 2693 struct Cookie *store = co; | |
| 2694 /* now loop through all cookies that matched */ | |
| 2695 while(co) { | |
| 2696 if(co->value) { | |
| 2697 if(0 == count) { | |
| 2698 result = Curl_add_bufferf(&req_buffer, "Cookie: "); | |
| 2699 if(result) | |
| 2700 break; | |
| 2701 } | |
| 2702 result = Curl_add_bufferf(&req_buffer, | |
| 2703 "%s%s=%s", count?"; ":"", | |
| 2704 co->name, co->value); | |
| 2705 if(result) | |
| 2706 break; | |
| 2707 count++; | |
| 2708 } | |
| 2709 co = co->next; /* next cookie please */ | |
| 2710 } | |
| 2711 Curl_cookie_freelist(store); | |
| 2712 } | |
| 2713 if(addcookies && !result) { | |
| 2714 if(!count) | |
| 2715 result = Curl_add_bufferf(&req_buffer, "Cookie: "); | |
| 2716 if(!result) { | |
| 2717 result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"", | |
| 2718 addcookies); | |
| 2719 count++; | |
| 2720 } | |
| 2721 } | |
| 2722 if(count && !result) | |
| 2723 result = Curl_add_buffer(&req_buffer, "\r\n", 2); | |
| 2724 | |
| 2725 if(result) | |
| 2726 return result; | |
| 2727 } | |
| 2728 #endif | |
| 2729 | |
| 2730 result = Curl_add_timecondition(conn, req_buffer); | |
| 2731 if(result) | |
| 2732 return result; | |
| 2733 | |
| 2734 result = Curl_add_custom_headers(conn, FALSE, req_buffer); | |
| 2735 if(result) | |
| 2736 return result; | |
| 2737 | |
| 2738 http->postdata = NULL; /* nothing to post at this point */ | |
| 2739 Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */ | |
| 2740 | |
| 2741 /* If 'authdone' is FALSE, we must not set the write socket index to the | |
| 2742 Curl_transfer() call below, as we're not ready to actually upload any | |
| 2743 data yet. */ | |
| 2744 | |
| 2745 switch(httpreq) { | |
| 2746 | |
| 2747 case HTTPREQ_PUT: /* Let's PUT the data to the server! */ | |
| 2748 | |
| 2749 if(conn->bits.authneg) | |
| 2750 postsize = 0; | |
| 2751 else | |
| 2752 postsize = data->state.infilesize; | |
| 2753 | |
| 2754 if((postsize != -1) && !data->req.upload_chunky && | |
| 2755 (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { | |
| 2756 /* only add Content-Length if not uploading chunked */ | |
| 2757 result = Curl_add_bufferf(&req_buffer, | |
| 2758 "Content-Length: %" CURL_FORMAT_CURL_OFF_T | |
| 2759 "\r\n", postsize); | |
| 2760 if(result) | |
| 2761 return result; | |
| 2762 } | |
| 2763 | |
| 2764 if(postsize != 0) { | |
| 2765 result = expect100(data, conn, req_buffer); | |
| 2766 if(result) | |
| 2767 return result; | |
| 2768 } | |
| 2769 | |
| 2770 result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */ | |
| 2771 if(result) | |
| 2772 return result; | |
| 2773 | |
| 2774 /* set the upload size to the progress meter */ | |
| 2775 Curl_pgrsSetUploadSize(data, postsize); | |
| 2776 | |
| 2777 /* this sends the buffer and frees all the buffer resources */ | |
| 2778 result = Curl_add_buffer_send(&req_buffer, conn, | |
| 2779 &data->info.request_size, 0, FIRSTSOCKET); | |
| 2780 if(result) | |
| 2781 failf(data, "Failed sending PUT request"); | |
| 2782 else | |
| 2783 /* prepare for transfer */ | |
| 2784 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, | |
| 2785 postsize?FIRSTSOCKET:-1); | |
| 2786 if(result) | |
| 2787 return result; | |
| 2788 break; | |
| 2789 | |
| 2790 case HTTPREQ_POST_FORM: | |
| 2791 case HTTPREQ_POST_MIME: | |
| 2792 /* This is form posting using mime data. */ | |
| 2793 if(conn->bits.authneg) { | |
| 2794 /* nothing to post! */ | |
| 2795 result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n"); | |
| 2796 if(result) | |
| 2797 return result; | |
| 2798 | |
| 2799 result = Curl_add_buffer_send(&req_buffer, conn, | |
| 2800 &data->info.request_size, 0, FIRSTSOCKET); | |
| 2801 if(result) | |
| 2802 failf(data, "Failed sending POST request"); | |
| 2803 else | |
| 2804 /* setup variables for the upcoming transfer */ | |
| 2805 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); | |
| 2806 break; | |
| 2807 } | |
| 2808 | |
| 2809 data->state.infilesize = postsize = http->postsize; | |
| 2810 | |
| 2811 /* We only set Content-Length and allow a custom Content-Length if | |
| 2812 we don't upload data chunked, as RFC2616 forbids us to set both | |
| 2813 kinds of headers (Transfer-Encoding: chunked and Content-Length) */ | |
| 2814 if(postsize != -1 && !data->req.upload_chunky && | |
| 2815 (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { | |
| 2816 /* we allow replacing this header if not during auth negotiation, | |
| 2817 although it isn't very wise to actually set your own */ | |
| 2818 result = Curl_add_bufferf(&req_buffer, | |
| 2819 "Content-Length: %" CURL_FORMAT_CURL_OFF_T | |
| 2820 "\r\n", postsize); | |
| 2821 if(result) | |
| 2822 return result; | |
| 2823 } | |
| 2824 | |
| 2825 #ifndef CURL_DISABLE_MIME | |
| 2826 /* Output mime-generated headers. */ | |
| 2827 { | |
| 2828 struct curl_slist *hdr; | |
| 2829 | |
| 2830 for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { | |
| 2831 result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data); | |
| 2832 if(result) | |
| 2833 return result; | |
| 2834 } | |
| 2835 } | |
| 2836 #endif | |
| 2837 | |
| 2838 /* For really small posts we don't use Expect: headers at all, and for | |
| 2839 the somewhat bigger ones we allow the app to disable it. Just make | |
| 2840 sure that the expect100header is always set to the preferred value | |
| 2841 here. */ | |
| 2842 ptr = Curl_checkheaders(conn, "Expect"); | |
| 2843 if(ptr) { | |
| 2844 data->state.expect100header = | |
| 2845 Curl_compareheader(ptr, "Expect:", "100-continue"); | |
| 2846 } | |
| 2847 else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { | |
| 2848 result = expect100(data, conn, req_buffer); | |
| 2849 if(result) | |
| 2850 return result; | |
| 2851 } | |
| 2852 else | |
| 2853 data->state.expect100header = FALSE; | |
| 2854 | |
| 2855 /* make the request end in a true CRLF */ | |
| 2856 result = Curl_add_buffer(&req_buffer, "\r\n", 2); | |
| 2857 if(result) | |
| 2858 return result; | |
| 2859 | |
| 2860 /* set the upload size to the progress meter */ | |
| 2861 Curl_pgrsSetUploadSize(data, postsize); | |
| 2862 | |
| 2863 /* Read from mime structure. */ | |
| 2864 data->state.fread_func = (curl_read_callback) Curl_mime_read; | |
| 2865 data->state.in = (void *) http->sendit; | |
| 2866 http->sending = HTTPSEND_BODY; | |
| 2867 | |
| 2868 /* this sends the buffer and frees all the buffer resources */ | |
| 2869 result = Curl_add_buffer_send(&req_buffer, conn, | |
| 2870 &data->info.request_size, 0, FIRSTSOCKET); | |
| 2871 if(result) | |
| 2872 failf(data, "Failed sending POST request"); | |
| 2873 else | |
| 2874 /* prepare for transfer */ | |
| 2875 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, | |
| 2876 postsize?FIRSTSOCKET:-1); | |
| 2877 if(result) | |
| 2878 return result; | |
| 2879 | |
| 2880 break; | |
| 2881 | |
| 2882 case HTTPREQ_POST: | |
| 2883 /* this is the simple POST, using x-www-form-urlencoded style */ | |
| 2884 | |
| 2885 if(conn->bits.authneg) | |
| 2886 postsize = 0; | |
| 2887 else | |
| 2888 /* the size of the post body */ | |
| 2889 postsize = data->state.infilesize; | |
| 2890 | |
| 2891 /* We only set Content-Length and allow a custom Content-Length if | |
| 2892 we don't upload data chunked, as RFC2616 forbids us to set both | |
| 2893 kinds of headers (Transfer-Encoding: chunked and Content-Length) */ | |
| 2894 if((postsize != -1) && !data->req.upload_chunky && | |
| 2895 (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { | |
| 2896 /* we allow replacing this header if not during auth negotiation, | |
| 2897 although it isn't very wise to actually set your own */ | |
| 2898 result = Curl_add_bufferf(&req_buffer, | |
| 2899 "Content-Length: %" CURL_FORMAT_CURL_OFF_T | |
| 2900 "\r\n", postsize); | |
| 2901 if(result) | |
| 2902 return result; | |
| 2903 } | |
| 2904 | |
| 2905 if(!Curl_checkheaders(conn, "Content-Type")) { | |
| 2906 result = Curl_add_bufferf(&req_buffer, | |
| 2907 "Content-Type: application/" | |
| 2908 "x-www-form-urlencoded\r\n"); | |
| 2909 if(result) | |
| 2910 return result; | |
| 2911 } | |
| 2912 | |
| 2913 /* For really small posts we don't use Expect: headers at all, and for | |
| 2914 the somewhat bigger ones we allow the app to disable it. Just make | |
| 2915 sure that the expect100header is always set to the preferred value | |
| 2916 here. */ | |
| 2917 ptr = Curl_checkheaders(conn, "Expect"); | |
| 2918 if(ptr) { | |
| 2919 data->state.expect100header = | |
| 2920 Curl_compareheader(ptr, "Expect:", "100-continue"); | |
| 2921 } | |
| 2922 else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { | |
| 2923 result = expect100(data, conn, req_buffer); | |
| 2924 if(result) | |
| 2925 return result; | |
| 2926 } | |
| 2927 else | |
| 2928 data->state.expect100header = FALSE; | |
| 2929 | |
| 2930 if(data->set.postfields) { | |
| 2931 | |
| 2932 /* In HTTP2, we send request body in DATA frame regardless of | |
| 2933 its size. */ | |
| 2934 if(conn->httpversion != 20 && | |
| 2935 !data->state.expect100header && | |
| 2936 (postsize < MAX_INITIAL_POST_SIZE)) { | |
| 2937 /* if we don't use expect: 100 AND | |
| 2938 postsize is less than MAX_INITIAL_POST_SIZE | |
| 2939 | |
| 2940 then append the post data to the HTTP request header. This limit | |
| 2941 is no magic limit but only set to prevent really huge POSTs to | |
| 2942 get the data duplicated with malloc() and family. */ | |
| 2943 | |
| 2944 result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ | |
| 2945 if(result) | |
| 2946 return result; | |
| 2947 | |
| 2948 if(!data->req.upload_chunky) { | |
| 2949 /* We're not sending it 'chunked', append it to the request | |
| 2950 already now to reduce the number if send() calls */ | |
| 2951 result = Curl_add_buffer(&req_buffer, data->set.postfields, | |
| 2952 (size_t)postsize); | |
| 2953 included_body = postsize; | |
| 2954 } | |
| 2955 else { | |
| 2956 if(postsize) { | |
| 2957 /* Append the POST data chunky-style */ | |
| 2958 result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize); | |
| 2959 if(!result) { | |
| 2960 result = Curl_add_buffer(&req_buffer, data->set.postfields, | |
| 2961 (size_t)postsize); | |
| 2962 if(!result) | |
| 2963 result = Curl_add_buffer(&req_buffer, "\r\n", 2); | |
| 2964 included_body = postsize + 2; | |
| 2965 } | |
| 2966 } | |
| 2967 if(!result) | |
| 2968 result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); | |
| 2969 /* 0 CR LF CR LF */ | |
| 2970 included_body += 5; | |
| 2971 } | |
| 2972 if(result) | |
| 2973 return result; | |
| 2974 /* Make sure the progress information is accurate */ | |
| 2975 Curl_pgrsSetUploadSize(data, postsize); | |
| 2976 } | |
| 2977 else { | |
| 2978 /* A huge POST coming up, do data separate from the request */ | |
| 2979 http->postsize = postsize; | |
| 2980 http->postdata = data->set.postfields; | |
| 2981 | |
| 2982 http->sending = HTTPSEND_BODY; | |
| 2983 | |
| 2984 data->state.fread_func = (curl_read_callback)readmoredata; | |
| 2985 data->state.in = (void *)conn; | |
| 2986 | |
| 2987 /* set the upload size to the progress meter */ | |
| 2988 Curl_pgrsSetUploadSize(data, http->postsize); | |
| 2989 | |
| 2990 result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ | |
| 2991 if(result) | |
| 2992 return result; | |
| 2993 } | |
| 2994 } | |
| 2995 else { | |
| 2996 result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ | |
| 2997 if(result) | |
| 2998 return result; | |
| 2999 | |
| 3000 if(data->req.upload_chunky && conn->bits.authneg) { | |
| 3001 /* Chunky upload is selected and we're negotiating auth still, send | |
| 3002 end-of-data only */ | |
| 3003 result = Curl_add_buffer(&req_buffer, | |
| 3004 "\x30\x0d\x0a\x0d\x0a", 5); | |
| 3005 /* 0 CR LF CR LF */ | |
| 3006 if(result) | |
| 3007 return result; | |
| 3008 } | |
| 3009 | |
| 3010 else if(data->state.infilesize) { | |
| 3011 /* set the upload size to the progress meter */ | |
| 3012 Curl_pgrsSetUploadSize(data, postsize?postsize:-1); | |
| 3013 | |
| 3014 /* set the pointer to mark that we will send the post body using the | |
| 3015 read callback, but only if we're not in authenticate | |
| 3016 negotiation */ | |
| 3017 if(!conn->bits.authneg) { | |
| 3018 http->postdata = (char *)&http->postdata; | |
| 3019 http->postsize = postsize; | |
| 3020 } | |
| 3021 } | |
| 3022 } | |
| 3023 /* issue the request */ | |
| 3024 result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, | |
| 3025 (size_t)included_body, FIRSTSOCKET); | |
| 3026 | |
| 3027 if(result) | |
| 3028 failf(data, "Failed sending HTTP POST request"); | |
| 3029 else | |
| 3030 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, | |
| 3031 http->postdata?FIRSTSOCKET:-1); | |
| 3032 break; | |
| 3033 | |
| 3034 default: | |
| 3035 result = Curl_add_buffer(&req_buffer, "\r\n", 2); | |
| 3036 if(result) | |
| 3037 return result; | |
| 3038 | |
| 3039 /* issue the request */ | |
| 3040 result = Curl_add_buffer_send(&req_buffer, conn, | |
| 3041 &data->info.request_size, 0, FIRSTSOCKET); | |
| 3042 | |
| 3043 if(result) | |
| 3044 failf(data, "Failed sending HTTP request"); | |
| 3045 else | |
| 3046 /* HTTP GET/HEAD download: */ | |
| 3047 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, | |
| 3048 http->postdata?FIRSTSOCKET:-1); | |
| 3049 } | |
| 3050 if(result) | |
| 3051 return result; | |
| 3052 | |
| 3053 if(data->req.writebytecount) { | |
| 3054 /* if a request-body has been sent off, we make sure this progress is noted | |
| 3055 properly */ | |
| 3056 Curl_pgrsSetUploadCounter(data, data->req.writebytecount); | |
| 3057 if(Curl_pgrsUpdate(conn)) | |
| 3058 result = CURLE_ABORTED_BY_CALLBACK; | |
| 3059 | |
| 3060 if(data->req.writebytecount >= postsize) { | |
| 3061 /* already sent the entire request body, mark the "upload" as | |
| 3062 complete */ | |
| 3063 infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T | |
| 3064 " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n", | |
| 3065 data->req.writebytecount, postsize); | |
| 3066 data->req.upload_done = TRUE; | |
| 3067 data->req.keepon &= ~KEEP_SEND; /* we're done writing */ | |
| 3068 data->req.exp100 = EXP100_SEND_DATA; /* already sent */ | |
| 3069 Curl_expire_done(data, EXPIRE_100_TIMEOUT); | |
| 3070 } | |
| 3071 } | |
| 3072 | |
| 3073 if((conn->httpversion == 20) && data->req.upload_chunky) | |
| 3074 /* upload_chunky was set above to set up the request in a chunky fashion, | |
| 3075 but is disabled here again to avoid that the chunked encoded version is | |
| 3076 actually used when sending the request body over h2 */ | |
| 3077 data->req.upload_chunky = FALSE; | |
| 3078 return result; | |
| 3079 } | |
| 3080 | |
| 3081 typedef enum { | |
| 3082 STATUS_UNKNOWN, /* not enough data to tell yet */ | |
| 3083 STATUS_DONE, /* a status line was read */ | |
| 3084 STATUS_BAD /* not a status line */ | |
| 3085 } statusline; | |
| 3086 | |
| 3087 | |
| 3088 /* Check a string for a prefix. Check no more than 'len' bytes */ | |
| 3089 static bool checkprefixmax(const char *prefix, const char *buffer, size_t len) | |
| 3090 { | |
| 3091 size_t ch = CURLMIN(strlen(prefix), len); | |
| 3092 return curl_strnequal(prefix, buffer, ch); | |
| 3093 } | |
| 3094 | |
| 3095 /* | |
| 3096 * checkhttpprefix() | |
| 3097 * | |
| 3098 * Returns TRUE if member of the list matches prefix of string | |
| 3099 */ | |
| 3100 static statusline | |
| 3101 checkhttpprefix(struct Curl_easy *data, | |
| 3102 const char *s, size_t len) | |
| 3103 { | |
| 3104 struct curl_slist *head = data->set.http200aliases; | |
| 3105 statusline rc = STATUS_BAD; | |
| 3106 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; | |
| 3107 #ifdef CURL_DOES_CONVERSIONS | |
| 3108 /* convert from the network encoding using a scratch area */ | |
| 3109 char *scratch = strdup(s); | |
| 3110 if(NULL == scratch) { | |
| 3111 failf(data, "Failed to allocate memory for conversion!"); | |
| 3112 return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ | |
| 3113 } | |
| 3114 if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { | |
| 3115 /* Curl_convert_from_network calls failf if unsuccessful */ | |
| 3116 free(scratch); | |
| 3117 return FALSE; /* can't return CURLE_foobar so return FALSE */ | |
| 3118 } | |
| 3119 s = scratch; | |
| 3120 #endif /* CURL_DOES_CONVERSIONS */ | |
| 3121 | |
| 3122 while(head) { | |
| 3123 if(checkprefixmax(head->data, s, len)) { | |
| 3124 rc = onmatch; | |
| 3125 break; | |
| 3126 } | |
| 3127 head = head->next; | |
| 3128 } | |
| 3129 | |
| 3130 if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len))) | |
| 3131 rc = onmatch; | |
| 3132 | |
| 3133 #ifdef CURL_DOES_CONVERSIONS | |
| 3134 free(scratch); | |
| 3135 #endif /* CURL_DOES_CONVERSIONS */ | |
| 3136 return rc; | |
| 3137 } | |
| 3138 | |
| 3139 #ifndef CURL_DISABLE_RTSP | |
| 3140 static statusline | |
| 3141 checkrtspprefix(struct Curl_easy *data, | |
| 3142 const char *s, size_t len) | |
| 3143 { | |
| 3144 statusline result = STATUS_BAD; | |
| 3145 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; | |
| 3146 | |
| 3147 #ifdef CURL_DOES_CONVERSIONS | |
| 3148 /* convert from the network encoding using a scratch area */ | |
| 3149 char *scratch = strdup(s); | |
| 3150 if(NULL == scratch) { | |
| 3151 failf(data, "Failed to allocate memory for conversion!"); | |
| 3152 return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ | |
| 3153 } | |
| 3154 if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { | |
| 3155 /* Curl_convert_from_network calls failf if unsuccessful */ | |
| 3156 result = FALSE; /* can't return CURLE_foobar so return FALSE */ | |
| 3157 } | |
| 3158 else if(checkprefixmax("RTSP/", scratch, len)) | |
| 3159 result = onmatch; | |
| 3160 free(scratch); | |
| 3161 #else | |
| 3162 (void)data; /* unused */ | |
| 3163 if(checkprefixmax("RTSP/", s, len)) | |
| 3164 result = onmatch; | |
| 3165 #endif /* CURL_DOES_CONVERSIONS */ | |
| 3166 | |
| 3167 return result; | |
| 3168 } | |
| 3169 #endif /* CURL_DISABLE_RTSP */ | |
| 3170 | |
| 3171 static statusline | |
| 3172 checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, | |
| 3173 const char *s, size_t len) | |
| 3174 { | |
| 3175 #ifndef CURL_DISABLE_RTSP | |
| 3176 if(conn->handler->protocol & CURLPROTO_RTSP) | |
| 3177 return checkrtspprefix(data, s, len); | |
| 3178 #else | |
| 3179 (void)conn; | |
| 3180 #endif /* CURL_DISABLE_RTSP */ | |
| 3181 | |
| 3182 return checkhttpprefix(data, s, len); | |
| 3183 } | |
| 3184 | |
| 3185 /* | |
| 3186 * header_append() copies a chunk of data to the end of the already received | |
| 3187 * header. We make sure that the full string fit in the allocated header | |
| 3188 * buffer, or else we enlarge it. | |
| 3189 */ | |
| 3190 static CURLcode header_append(struct Curl_easy *data, | |
| 3191 struct SingleRequest *k, | |
| 3192 size_t length) | |
| 3193 { | |
| 3194 /* length is at most the size of a full read buffer, for which the upper | |
| 3195 bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this | |
| 3196 calculation. */ | |
| 3197 size_t newsize = k->hbuflen + length; | |
| 3198 if(newsize > CURL_MAX_HTTP_HEADER) { | |
| 3199 /* The reason to have a max limit for this is to avoid the risk of a bad | |
| 3200 server feeding libcurl with a never-ending header that will cause | |
| 3201 reallocs infinitely */ | |
| 3202 failf(data, "Rejected %zu bytes header (max is %d)!", newsize, | |
| 3203 CURL_MAX_HTTP_HEADER); | |
| 3204 return CURLE_OUT_OF_MEMORY; | |
| 3205 } | |
| 3206 if(newsize >= data->state.headersize) { | |
| 3207 /* We enlarge the header buffer as it is too small */ | |
| 3208 char *newbuff; | |
| 3209 size_t hbufp_index; | |
| 3210 | |
| 3211 newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); | |
| 3212 hbufp_index = k->hbufp - data->state.headerbuff; | |
| 3213 newbuff = realloc(data->state.headerbuff, newsize); | |
| 3214 if(!newbuff) { | |
| 3215 failf(data, "Failed to alloc memory for big header!"); | |
| 3216 return CURLE_OUT_OF_MEMORY; | |
| 3217 } | |
| 3218 data->state.headersize = newsize; | |
| 3219 data->state.headerbuff = newbuff; | |
| 3220 k->hbufp = data->state.headerbuff + hbufp_index; | |
| 3221 } | |
| 3222 memcpy(k->hbufp, k->str_start, length); | |
| 3223 k->hbufp += length; | |
| 3224 k->hbuflen += length; | |
| 3225 *k->hbufp = 0; | |
| 3226 | |
| 3227 return CURLE_OK; | |
| 3228 } | |
| 3229 | |
| 3230 static void print_http_error(struct Curl_easy *data) | |
| 3231 { | |
| 3232 struct SingleRequest *k = &data->req; | |
| 3233 char *beg = k->p; | |
| 3234 | |
| 3235 /* make sure that data->req.p points to the HTTP status line */ | |
| 3236 if(!strncmp(beg, "HTTP", 4)) { | |
| 3237 | |
| 3238 /* skip to HTTP status code */ | |
| 3239 beg = strchr(beg, ' '); | |
| 3240 if(beg && *++beg) { | |
| 3241 | |
| 3242 /* find trailing CR */ | |
| 3243 char end_char = '\r'; | |
| 3244 char *end = strchr(beg, end_char); | |
| 3245 if(!end) { | |
| 3246 /* try to find LF (workaround for non-compliant HTTP servers) */ | |
| 3247 end_char = '\n'; | |
| 3248 end = strchr(beg, end_char); | |
| 3249 } | |
| 3250 | |
| 3251 if(end) { | |
| 3252 /* temporarily replace CR or LF by NUL and print the error message */ | |
| 3253 *end = '\0'; | |
| 3254 failf(data, "The requested URL returned error: %s", beg); | |
| 3255 | |
| 3256 /* restore the previously replaced CR or LF */ | |
| 3257 *end = end_char; | |
| 3258 return; | |
| 3259 } | |
| 3260 } | |
| 3261 } | |
| 3262 | |
| 3263 /* fall-back to printing the HTTP status code only */ | |
| 3264 failf(data, "The requested URL returned error: %d", k->httpcode); | |
| 3265 } | |
| 3266 | |
| 3267 /* | |
| 3268 * Read any HTTP header lines from the server and pass them to the client app. | |
| 3269 */ | |
| 3270 CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, | |
| 3271 struct connectdata *conn, | |
| 3272 ssize_t *nread, | |
| 3273 bool *stop_reading) | |
| 3274 { | |
| 3275 CURLcode result; | |
| 3276 struct SingleRequest *k = &data->req; | |
| 3277 ssize_t onread = *nread; | |
| 3278 char *ostr = k->str; | |
| 3279 | |
| 3280 /* header line within buffer loop */ | |
| 3281 do { | |
| 3282 size_t rest_length; | |
| 3283 size_t full_length; | |
| 3284 int writetype; | |
| 3285 | |
| 3286 /* str_start is start of line within buf */ | |
| 3287 k->str_start = k->str; | |
| 3288 | |
| 3289 /* data is in network encoding so use 0x0a instead of '\n' */ | |
| 3290 k->end_ptr = memchr(k->str_start, 0x0a, *nread); | |
| 3291 | |
| 3292 if(!k->end_ptr) { | |
| 3293 /* Not a complete header line within buffer, append the data to | |
| 3294 the end of the headerbuff. */ | |
| 3295 result = header_append(data, k, *nread); | |
| 3296 if(result) | |
| 3297 return result; | |
| 3298 | |
| 3299 if(!k->headerline) { | |
| 3300 /* check if this looks like a protocol header */ | |
| 3301 statusline st = checkprotoprefix(data, conn, data->state.headerbuff, | |
| 3302 k->hbuflen); | |
| 3303 if(st == STATUS_BAD) { | |
| 3304 /* this is not the beginning of a protocol first header line */ | |
| 3305 k->header = FALSE; | |
| 3306 k->badheader = HEADER_ALLBAD; | |
| 3307 streamclose(conn, "bad HTTP: No end-of-message indicator"); | |
| 3308 if(!data->set.http09_allowed) { | |
| 3309 failf(data, "Received HTTP/0.9 when not allowed\n"); | |
| 3310 return CURLE_UNSUPPORTED_PROTOCOL; | |
| 3311 } | |
| 3312 break; | |
| 3313 } | |
| 3314 } | |
| 3315 | |
| 3316 break; /* read more and try again */ | |
| 3317 } | |
| 3318 | |
| 3319 /* decrease the size of the remaining (supposed) header line */ | |
| 3320 rest_length = (k->end_ptr - k->str) + 1; | |
| 3321 *nread -= (ssize_t)rest_length; | |
| 3322 | |
| 3323 k->str = k->end_ptr + 1; /* move past new line */ | |
| 3324 | |
| 3325 full_length = k->str - k->str_start; | |
| 3326 | |
| 3327 result = header_append(data, k, full_length); | |
| 3328 if(result) | |
| 3329 return result; | |
| 3330 | |
| 3331 k->end_ptr = k->hbufp; | |
| 3332 k->p = data->state.headerbuff; | |
| 3333 | |
| 3334 /**** | |
| 3335 * We now have a FULL header line that p points to | |
| 3336 *****/ | |
| 3337 | |
| 3338 if(!k->headerline) { | |
| 3339 /* the first read header */ | |
| 3340 statusline st = checkprotoprefix(data, conn, data->state.headerbuff, | |
| 3341 k->hbuflen); | |
| 3342 if(st == STATUS_BAD) { | |
| 3343 streamclose(conn, "bad HTTP: No end-of-message indicator"); | |
| 3344 /* this is not the beginning of a protocol first header line */ | |
| 3345 if(!data->set.http09_allowed) { | |
| 3346 failf(data, "Received HTTP/0.9 when not allowed\n"); | |
| 3347 return CURLE_UNSUPPORTED_PROTOCOL; | |
| 3348 } | |
| 3349 k->header = FALSE; | |
| 3350 if(*nread) | |
| 3351 /* since there's more, this is a partial bad header */ | |
| 3352 k->badheader = HEADER_PARTHEADER; | |
| 3353 else { | |
| 3354 /* this was all we read so it's all a bad header */ | |
| 3355 k->badheader = HEADER_ALLBAD; | |
| 3356 *nread = onread; | |
| 3357 k->str = ostr; | |
| 3358 return CURLE_OK; | |
| 3359 } | |
| 3360 break; | |
| 3361 } | |
| 3362 } | |
| 3363 | |
| 3364 /* headers are in network encoding so | |
| 3365 use 0x0a and 0x0d instead of '\n' and '\r' */ | |
| 3366 if((0x0a == *k->p) || (0x0d == *k->p)) { | |
| 3367 size_t headerlen; | |
| 3368 /* Zero-length header line means end of headers! */ | |
| 3369 | |
| 3370 #ifdef CURL_DOES_CONVERSIONS | |
| 3371 if(0x0d == *k->p) { | |
| 3372 *k->p = '\r'; /* replace with CR in host encoding */ | |
| 3373 k->p++; /* pass the CR byte */ | |
| 3374 } | |
| 3375 if(0x0a == *k->p) { | |
| 3376 *k->p = '\n'; /* replace with LF in host encoding */ | |
| 3377 k->p++; /* pass the LF byte */ | |
| 3378 } | |
| 3379 #else | |
| 3380 if('\r' == *k->p) | |
| 3381 k->p++; /* pass the \r byte */ | |
| 3382 if('\n' == *k->p) | |
| 3383 k->p++; /* pass the \n byte */ | |
| 3384 #endif /* CURL_DOES_CONVERSIONS */ | |
| 3385 | |
| 3386 if(100 <= k->httpcode && 199 >= k->httpcode) { | |
| 3387 /* "A user agent MAY ignore unexpected 1xx status responses." */ | |
| 3388 switch(k->httpcode) { | |
| 3389 case 100: | |
| 3390 /* | |
| 3391 * We have made a HTTP PUT or POST and this is 1.1-lingo | |
| 3392 * that tells us that the server is OK with this and ready | |
| 3393 * to receive the data. | |
| 3394 * However, we'll get more headers now so we must get | |
| 3395 * back into the header-parsing state! | |
| 3396 */ | |
| 3397 k->header = TRUE; | |
| 3398 k->headerline = 0; /* restart the header line counter */ | |
| 3399 | |
| 3400 /* if we did wait for this do enable write now! */ | |
| 3401 if(k->exp100 > EXP100_SEND_DATA) { | |
| 3402 k->exp100 = EXP100_SEND_DATA; | |
| 3403 k->keepon |= KEEP_SEND; | |
| 3404 Curl_expire_done(data, EXPIRE_100_TIMEOUT); | |
| 3405 } | |
| 3406 break; | |
| 3407 case 101: | |
| 3408 /* Switching Protocols */ | |
| 3409 if(k->upgr101 == UPGR101_REQUESTED) { | |
| 3410 /* Switching to HTTP/2 */ | |
| 3411 infof(data, "Received 101\n"); | |
| 3412 k->upgr101 = UPGR101_RECEIVED; | |
| 3413 | |
| 3414 /* we'll get more headers (HTTP/2 response) */ | |
| 3415 k->header = TRUE; | |
| 3416 k->headerline = 0; /* restart the header line counter */ | |
| 3417 | |
| 3418 /* switch to http2 now. The bytes after response headers | |
| 3419 are also processed here, otherwise they are lost. */ | |
| 3420 result = Curl_http2_switched(conn, k->str, *nread); | |
| 3421 if(result) | |
| 3422 return result; | |
| 3423 *nread = 0; | |
| 3424 } | |
| 3425 else { | |
| 3426 /* Switching to another protocol (e.g. WebSocket) */ | |
| 3427 k->header = FALSE; /* no more header to parse! */ | |
| 3428 } | |
| 3429 break; | |
| 3430 default: | |
| 3431 /* the status code 1xx indicates a provisional response, so | |
| 3432 we'll get another set of headers */ | |
| 3433 k->header = TRUE; | |
| 3434 k->headerline = 0; /* restart the header line counter */ | |
| 3435 break; | |
| 3436 } | |
| 3437 } | |
| 3438 else { | |
| 3439 k->header = FALSE; /* no more header to parse! */ | |
| 3440 | |
| 3441 if((k->size == -1) && !k->chunk && !conn->bits.close && | |
| 3442 (conn->httpversion == 11) && | |
| 3443 !(conn->handler->protocol & CURLPROTO_RTSP) && | |
| 3444 data->set.httpreq != HTTPREQ_HEAD) { | |
| 3445 /* On HTTP 1.1, when connection is not to get closed, but no | |
| 3446 Content-Length nor Transfer-Encoding chunked have been | |
| 3447 received, according to RFC2616 section 4.4 point 5, we | |
| 3448 assume that the server will close the connection to | |
| 3449 signal the end of the document. */ | |
| 3450 infof(data, "no chunk, no close, no size. Assume close to " | |
| 3451 "signal end\n"); | |
| 3452 streamclose(conn, "HTTP: No end-of-message indicator"); | |
| 3453 } | |
| 3454 } | |
| 3455 | |
| 3456 /* At this point we have some idea about the fate of the connection. | |
| 3457 If we are closing the connection it may result auth failure. */ | |
| 3458 #if defined(USE_NTLM) | |
| 3459 if(conn->bits.close && | |
| 3460 (((data->req.httpcode == 401) && | |
| 3461 (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || | |
| 3462 ((data->req.httpcode == 407) && | |
| 3463 (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) { | |
| 3464 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); | |
| 3465 data->state.authproblem = TRUE; | |
| 3466 } | |
| 3467 #endif | |
| 3468 #if defined(USE_SPNEGO) | |
| 3469 if(conn->bits.close && | |
| 3470 (((data->req.httpcode == 401) && | |
| 3471 (conn->http_negotiate_state == GSS_AUTHRECV)) || | |
| 3472 ((data->req.httpcode == 407) && | |
| 3473 (conn->proxy_negotiate_state == GSS_AUTHRECV)))) { | |
| 3474 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); | |
| 3475 data->state.authproblem = TRUE; | |
| 3476 } | |
| 3477 if((conn->http_negotiate_state == GSS_AUTHDONE) && | |
| 3478 (data->req.httpcode != 401)) { | |
| 3479 conn->http_negotiate_state = GSS_AUTHSUCC; | |
| 3480 } | |
| 3481 if((conn->proxy_negotiate_state == GSS_AUTHDONE) && | |
| 3482 (data->req.httpcode != 407)) { | |
| 3483 conn->proxy_negotiate_state = GSS_AUTHSUCC; | |
| 3484 } | |
| 3485 #endif | |
| 3486 /* | |
| 3487 * When all the headers have been parsed, see if we should give | |
| 3488 * up and return an error. | |
| 3489 */ | |
| 3490 if(http_should_fail(conn)) { | |
| 3491 failf(data, "The requested URL returned error: %d", | |
| 3492 k->httpcode); | |
| 3493 return CURLE_HTTP_RETURNED_ERROR; | |
| 3494 } | |
| 3495 | |
| 3496 /* now, only output this if the header AND body are requested: | |
| 3497 */ | |
| 3498 writetype = CLIENTWRITE_HEADER; | |
| 3499 if(data->set.include_header) | |
| 3500 writetype |= CLIENTWRITE_BODY; | |
| 3501 | |
| 3502 headerlen = k->p - data->state.headerbuff; | |
| 3503 | |
| 3504 result = Curl_client_write(conn, writetype, | |
| 3505 data->state.headerbuff, | |
| 3506 headerlen); | |
| 3507 if(result) | |
| 3508 return result; | |
| 3509 | |
| 3510 data->info.header_size += (long)headerlen; | |
| 3511 data->req.headerbytecount += (long)headerlen; | |
| 3512 | |
| 3513 data->req.deductheadercount = | |
| 3514 (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; | |
| 3515 | |
| 3516 /* Curl_http_auth_act() checks what authentication methods | |
| 3517 * that are available and decides which one (if any) to | |
| 3518 * use. It will set 'newurl' if an auth method was picked. */ | |
| 3519 result = Curl_http_auth_act(conn); | |
| 3520 | |
| 3521 if(result) | |
| 3522 return result; | |
| 3523 | |
| 3524 if(k->httpcode >= 300) { | |
| 3525 if((!conn->bits.authneg) && !conn->bits.close && | |
| 3526 !conn->bits.rewindaftersend) { | |
| 3527 /* | |
| 3528 * General treatment of errors when about to send data. Including : | |
| 3529 * "417 Expectation Failed", while waiting for 100-continue. | |
| 3530 * | |
| 3531 * The check for close above is done simply because of something | |
| 3532 * else has already deemed the connection to get closed then | |
| 3533 * something else should've considered the big picture and we | |
| 3534 * avoid this check. | |
| 3535 * | |
| 3536 * rewindaftersend indicates that something has told libcurl to | |
| 3537 * continue sending even if it gets discarded | |
| 3538 */ | |
| 3539 | |
| 3540 switch(data->set.httpreq) { | |
| 3541 case HTTPREQ_PUT: | |
| 3542 case HTTPREQ_POST: | |
| 3543 case HTTPREQ_POST_FORM: | |
| 3544 case HTTPREQ_POST_MIME: | |
| 3545 /* We got an error response. If this happened before the whole | |
| 3546 * request body has been sent we stop sending and mark the | |
| 3547 * connection for closure after we've read the entire response. | |
| 3548 */ | |
| 3549 Curl_expire_done(data, EXPIRE_100_TIMEOUT); | |
| 3550 if(!k->upload_done) { | |
| 3551 if(data->set.http_keep_sending_on_error) { | |
| 3552 infof(data, "HTTP error before end of send, keep sending\n"); | |
| 3553 if(k->exp100 > EXP100_SEND_DATA) { | |
| 3554 k->exp100 = EXP100_SEND_DATA; | |
| 3555 k->keepon |= KEEP_SEND; | |
| 3556 } | |
| 3557 } | |
| 3558 else { | |
| 3559 infof(data, "HTTP error before end of send, stop sending\n"); | |
| 3560 streamclose(conn, "Stop sending data before everything sent"); | |
| 3561 result = Curl_done_sending(conn, k); | |
| 3562 if(result) | |
| 3563 return result; | |
| 3564 k->upload_done = TRUE; | |
| 3565 if(data->state.expect100header) | |
| 3566 k->exp100 = EXP100_FAILED; | |
| 3567 } | |
| 3568 } | |
| 3569 break; | |
| 3570 | |
| 3571 default: /* default label present to avoid compiler warnings */ | |
| 3572 break; | |
| 3573 } | |
| 3574 } | |
| 3575 | |
| 3576 if(conn->bits.rewindaftersend) { | |
| 3577 /* We rewind after a complete send, so thus we continue | |
| 3578 sending now */ | |
| 3579 infof(data, "Keep sending data to get tossed away!\n"); | |
| 3580 k->keepon |= KEEP_SEND; | |
| 3581 } | |
| 3582 } | |
| 3583 | |
| 3584 if(!k->header) { | |
| 3585 /* | |
| 3586 * really end-of-headers. | |
| 3587 * | |
| 3588 * If we requested a "no body", this is a good time to get | |
| 3589 * out and return home. | |
| 3590 */ | |
| 3591 if(data->set.opt_no_body) | |
| 3592 *stop_reading = TRUE; | |
| 3593 #ifndef CURL_DISABLE_RTSP | |
| 3594 else if((conn->handler->protocol & CURLPROTO_RTSP) && | |
| 3595 (data->set.rtspreq == RTSPREQ_DESCRIBE) && | |
| 3596 (k->size <= -1)) | |
| 3597 /* Respect section 4.4 of rfc2326: If the Content-Length header is | |
| 3598 absent, a length 0 must be assumed. It will prevent libcurl from | |
| 3599 hanging on DESCRIBE request that got refused for whatever | |
| 3600 reason */ | |
| 3601 *stop_reading = TRUE; | |
| 3602 #endif | |
| 3603 else { | |
| 3604 /* If we know the expected size of this document, we set the | |
| 3605 maximum download size to the size of the expected | |
| 3606 document or else, we won't know when to stop reading! | |
| 3607 | |
| 3608 Note that we set the download maximum even if we read a | |
| 3609 "Connection: close" header, to make sure that | |
| 3610 "Content-Length: 0" still prevents us from attempting to | |
| 3611 read the (missing) response-body. | |
| 3612 */ | |
| 3613 /* According to RFC2616 section 4.4, we MUST ignore | |
| 3614 Content-Length: headers if we are now receiving data | |
| 3615 using chunked Transfer-Encoding. | |
| 3616 */ | |
| 3617 if(k->chunk) | |
| 3618 k->maxdownload = k->size = -1; | |
| 3619 } | |
| 3620 if(-1 != k->size) { | |
| 3621 /* We do this operation even if no_body is true, since this | |
| 3622 data might be retrieved later with curl_easy_getinfo() | |
| 3623 and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ | |
| 3624 | |
| 3625 Curl_pgrsSetDownloadSize(data, k->size); | |
| 3626 k->maxdownload = k->size; | |
| 3627 } | |
| 3628 | |
| 3629 /* If max download size is *zero* (nothing) we already have | |
| 3630 nothing and can safely return ok now! But for HTTP/2, we'd | |
| 3631 like to call http2_handle_stream_close to properly close a | |
| 3632 stream. In order to do this, we keep reading until we | |
| 3633 close the stream. */ | |
| 3634 if(0 == k->maxdownload | |
| 3635 #if defined(USE_NGHTTP2) | |
| 3636 && !((conn->handler->protocol & PROTO_FAMILY_HTTP) && | |
| 3637 conn->httpversion == 20) | |
| 3638 #endif | |
| 3639 ) | |
| 3640 *stop_reading = TRUE; | |
| 3641 | |
| 3642 if(*stop_reading) { | |
| 3643 /* we make sure that this socket isn't read more now */ | |
| 3644 k->keepon &= ~KEEP_RECV; | |
| 3645 } | |
| 3646 | |
| 3647 if(data->set.verbose) | |
| 3648 Curl_debug(data, CURLINFO_HEADER_IN, | |
| 3649 k->str_start, headerlen); | |
| 3650 break; /* exit header line loop */ | |
| 3651 } | |
| 3652 | |
| 3653 /* We continue reading headers, so reset the line-based | |
| 3654 header parsing variables hbufp && hbuflen */ | |
| 3655 k->hbufp = data->state.headerbuff; | |
| 3656 k->hbuflen = 0; | |
| 3657 continue; | |
| 3658 } | |
| 3659 | |
| 3660 /* | |
| 3661 * Checks for special headers coming up. | |
| 3662 */ | |
| 3663 | |
| 3664 if(!k->headerline++) { | |
| 3665 /* This is the first header, it MUST be the error code line | |
| 3666 or else we consider this to be the body right away! */ | |
| 3667 int httpversion_major; | |
| 3668 int rtspversion_major; | |
| 3669 int nc = 0; | |
| 3670 #ifdef CURL_DOES_CONVERSIONS | |
| 3671 #define HEADER1 scratch | |
| 3672 #define SCRATCHSIZE 21 | |
| 3673 CURLcode res; | |
| 3674 char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ | |
| 3675 /* We can't really convert this yet because we | |
| 3676 don't know if it's the 1st header line or the body. | |
| 3677 So we do a partial conversion into a scratch area, | |
| 3678 leaving the data at k->p as-is. | |
| 3679 */ | |
| 3680 strncpy(&scratch[0], k->p, SCRATCHSIZE); | |
| 3681 scratch[SCRATCHSIZE] = 0; /* null terminate */ | |
| 3682 res = Curl_convert_from_network(data, | |
| 3683 &scratch[0], | |
| 3684 SCRATCHSIZE); | |
| 3685 if(res) | |
| 3686 /* Curl_convert_from_network calls failf if unsuccessful */ | |
| 3687 return res; | |
| 3688 #else | |
| 3689 #define HEADER1 k->p /* no conversion needed, just use k->p */ | |
| 3690 #endif /* CURL_DOES_CONVERSIONS */ | |
| 3691 | |
| 3692 if(conn->handler->protocol & PROTO_FAMILY_HTTP) { | |
| 3693 /* | |
| 3694 * https://tools.ietf.org/html/rfc7230#section-3.1.2 | |
| 3695 * | |
| 3696 * The response code is always a three-digit number in HTTP as the spec | |
| 3697 * says. We try to allow any number here, but we cannot make | |
| 3698 * guarantees on future behaviors since it isn't within the protocol. | |
| 3699 */ | |
| 3700 char separator; | |
| 3701 char twoorthree[2]; | |
| 3702 nc = sscanf(HEADER1, | |
| 3703 " HTTP/%1d.%1d%c%3d", | |
| 3704 &httpversion_major, | |
| 3705 &conn->httpversion, | |
| 3706 &separator, | |
| 3707 &k->httpcode); | |
| 3708 | |
| 3709 if(nc == 1 && httpversion_major >= 2 && | |
| 3710 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) { | |
| 3711 conn->httpversion = 0; | |
| 3712 nc = 4; | |
| 3713 separator = ' '; | |
| 3714 } | |
| 3715 | |
| 3716 if((nc == 4) && (' ' == separator)) { | |
| 3717 conn->httpversion += 10 * httpversion_major; | |
| 3718 | |
| 3719 if(k->upgr101 == UPGR101_RECEIVED) { | |
| 3720 /* supposedly upgraded to http2 now */ | |
| 3721 if(conn->httpversion != 20) | |
| 3722 infof(data, "Lying server, not serving HTTP/2\n"); | |
| 3723 } | |
| 3724 if(conn->httpversion < 20) { | |
| 3725 conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; | |
| 3726 infof(data, "Mark bundle as not supporting multiuse\n"); | |
| 3727 } | |
| 3728 } | |
| 3729 else if(!nc) { | |
| 3730 /* this is the real world, not a Nirvana | |
| 3731 NCSA 1.5.x returns this crap when asked for HTTP/1.1 | |
| 3732 */ | |
| 3733 nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); | |
| 3734 conn->httpversion = 10; | |
| 3735 | |
| 3736 /* If user has set option HTTP200ALIASES, | |
| 3737 compare header line against list of aliases | |
| 3738 */ | |
| 3739 if(!nc) { | |
| 3740 if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) { | |
| 3741 nc = 1; | |
| 3742 k->httpcode = 200; | |
| 3743 conn->httpversion = 10; | |
| 3744 } | |
| 3745 } | |
| 3746 } | |
| 3747 else { | |
| 3748 failf(data, "Unsupported HTTP version in response"); | |
| 3749 return CURLE_UNSUPPORTED_PROTOCOL; | |
| 3750 } | |
| 3751 } | |
| 3752 else if(conn->handler->protocol & CURLPROTO_RTSP) { | |
| 3753 char separator; | |
| 3754 nc = sscanf(HEADER1, | |
| 3755 " RTSP/%1d.%1d%c%3d", | |
| 3756 &rtspversion_major, | |
| 3757 &conn->rtspversion, | |
| 3758 &separator, | |
| 3759 &k->httpcode); | |
| 3760 if((nc == 4) && (' ' == separator)) { | |
| 3761 conn->rtspversion += 10 * rtspversion_major; | |
| 3762 conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ | |
| 3763 } | |
| 3764 else { | |
| 3765 nc = 0; | |
| 3766 } | |
| 3767 } | |
| 3768 | |
| 3769 if(nc) { | |
| 3770 data->info.httpcode = k->httpcode; | |
| 3771 | |
| 3772 data->info.httpversion = conn->httpversion; | |
| 3773 if(!data->state.httpversion || | |
| 3774 data->state.httpversion > conn->httpversion) | |
| 3775 /* store the lowest server version we encounter */ | |
| 3776 data->state.httpversion = conn->httpversion; | |
| 3777 | |
| 3778 /* | |
| 3779 * This code executes as part of processing the header. As a | |
| 3780 * result, it's not totally clear how to interpret the | |
| 3781 * response code yet as that depends on what other headers may | |
| 3782 * be present. 401 and 407 may be errors, but may be OK | |
| 3783 * depending on how authentication is working. Other codes | |
| 3784 * are definitely errors, so give up here. | |
| 3785 */ | |
| 3786 if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET && | |
| 3787 k->httpcode == 416) { | |
| 3788 /* "Requested Range Not Satisfiable", just proceed and | |
| 3789 pretend this is no error */ | |
| 3790 k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ | |
| 3791 } | |
| 3792 else if(data->set.http_fail_on_error && (k->httpcode >= 400) && | |
| 3793 ((k->httpcode != 401) || !conn->bits.user_passwd) && | |
| 3794 ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { | |
| 3795 /* serious error, go home! */ | |
| 3796 print_http_error(data); | |
| 3797 return CURLE_HTTP_RETURNED_ERROR; | |
| 3798 } | |
| 3799 | |
| 3800 if(conn->httpversion == 10) { | |
| 3801 /* Default action for HTTP/1.0 must be to close, unless | |
| 3802 we get one of those fancy headers that tell us the | |
| 3803 server keeps it open for us! */ | |
| 3804 infof(data, "HTTP 1.0, assume close after body\n"); | |
| 3805 connclose(conn, "HTTP/1.0 close after body"); | |
| 3806 } | |
| 3807 else if(conn->httpversion == 20 || | |
| 3808 (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { | |
| 3809 DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); | |
| 3810 | |
| 3811 /* HTTP/2 cannot blacklist multiplexing since it is a core | |
| 3812 functionality of the protocol */ | |
| 3813 conn->bundle->multiuse = BUNDLE_MULTIPLEX; | |
| 3814 } | |
| 3815 else if(conn->httpversion >= 11 && | |
| 3816 !conn->bits.close) { | |
| 3817 /* If HTTP version is >= 1.1 and connection is persistent */ | |
| 3818 DEBUGF(infof(data, | |
| 3819 "HTTP 1.1 or later with persistent connection\n")); | |
| 3820 } | |
| 3821 | |
| 3822 k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; | |
| 3823 switch(k->httpcode) { | |
| 3824 case 304: | |
| 3825 /* (quote from RFC2616, section 10.3.5): The 304 response | |
| 3826 * MUST NOT contain a message-body, and thus is always | |
| 3827 * terminated by the first empty line after the header | |
| 3828 * fields. */ | |
| 3829 if(data->set.timecondition) | |
| 3830 data->info.timecond = TRUE; | |
| 3831 /* FALLTHROUGH */ | |
| 3832 case 204: | |
| 3833 /* (quote from RFC2616, section 10.2.5): The server has | |
| 3834 * fulfilled the request but does not need to return an | |
| 3835 * entity-body ... The 204 response MUST NOT include a | |
| 3836 * message-body, and thus is always terminated by the first | |
| 3837 * empty line after the header fields. */ | |
| 3838 k->size = 0; | |
| 3839 k->maxdownload = 0; | |
| 3840 k->http_bodyless = TRUE; | |
| 3841 break; | |
| 3842 default: | |
| 3843 break; | |
| 3844 } | |
| 3845 } | |
| 3846 else { | |
| 3847 k->header = FALSE; /* this is not a header line */ | |
| 3848 break; | |
| 3849 } | |
| 3850 } | |
| 3851 | |
| 3852 result = Curl_convert_from_network(data, k->p, strlen(k->p)); | |
| 3853 /* Curl_convert_from_network calls failf if unsuccessful */ | |
| 3854 if(result) | |
| 3855 return result; | |
| 3856 | |
| 3857 /* Check for Content-Length: header lines to get size */ | |
| 3858 if(!k->http_bodyless && | |
| 3859 !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { | |
| 3860 curl_off_t contentlength; | |
| 3861 CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength); | |
| 3862 | |
| 3863 if(offt == CURL_OFFT_OK) { | |
| 3864 if(data->set.max_filesize && | |
| 3865 contentlength > data->set.max_filesize) { | |
| 3866 failf(data, "Maximum file size exceeded"); | |
| 3867 return CURLE_FILESIZE_EXCEEDED; | |
| 3868 } | |
| 3869 k->size = contentlength; | |
| 3870 k->maxdownload = k->size; | |
| 3871 /* we set the progress download size already at this point | |
| 3872 just to make it easier for apps/callbacks to extract this | |
| 3873 info as soon as possible */ | |
| 3874 Curl_pgrsSetDownloadSize(data, k->size); | |
| 3875 } | |
| 3876 else if(offt == CURL_OFFT_FLOW) { | |
| 3877 /* out of range */ | |
| 3878 if(data->set.max_filesize) { | |
| 3879 failf(data, "Maximum file size exceeded"); | |
| 3880 return CURLE_FILESIZE_EXCEEDED; | |
| 3881 } | |
| 3882 streamclose(conn, "overflow content-length"); | |
| 3883 infof(data, "Overflow Content-Length: value!\n"); | |
| 3884 } | |
| 3885 else { | |
| 3886 /* negative or just rubbish - bad HTTP */ | |
| 3887 failf(data, "Invalid Content-Length: value"); | |
| 3888 return CURLE_WEIRD_SERVER_REPLY; | |
| 3889 } | |
| 3890 } | |
| 3891 /* check for Content-Type: header lines to get the MIME-type */ | |
| 3892 else if(checkprefix("Content-Type:", k->p)) { | |
| 3893 char *contenttype = Curl_copy_header_value(k->p); | |
| 3894 if(!contenttype) | |
| 3895 return CURLE_OUT_OF_MEMORY; | |
| 3896 if(!*contenttype) | |
| 3897 /* ignore empty data */ | |
| 3898 free(contenttype); | |
| 3899 else { | |
| 3900 Curl_safefree(data->info.contenttype); | |
| 3901 data->info.contenttype = contenttype; | |
| 3902 } | |
| 3903 } | |
| 3904 else if((conn->httpversion == 10) && | |
| 3905 conn->bits.httpproxy && | |
| 3906 Curl_compareheader(k->p, | |
| 3907 "Proxy-Connection:", "keep-alive")) { | |
| 3908 /* | |
| 3909 * When a HTTP/1.0 reply comes when using a proxy, the | |
| 3910 * 'Proxy-Connection: keep-alive' line tells us the | |
| 3911 * connection will be kept alive for our pleasure. | |
| 3912 * Default action for 1.0 is to close. | |
| 3913 */ | |
| 3914 connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ | |
| 3915 infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); | |
| 3916 } | |
| 3917 else if((conn->httpversion == 11) && | |
| 3918 conn->bits.httpproxy && | |
| 3919 Curl_compareheader(k->p, | |
| 3920 "Proxy-Connection:", "close")) { | |
| 3921 /* | |
| 3922 * We get a HTTP/1.1 response from a proxy and it says it'll | |
| 3923 * close down after this transfer. | |
| 3924 */ | |
| 3925 connclose(conn, "Proxy-Connection: asked to close after done"); | |
| 3926 infof(data, "HTTP/1.1 proxy connection set close!\n"); | |
| 3927 } | |
| 3928 else if((conn->httpversion == 10) && | |
| 3929 Curl_compareheader(k->p, "Connection:", "keep-alive")) { | |
| 3930 /* | |
| 3931 * A HTTP/1.0 reply with the 'Connection: keep-alive' line | |
| 3932 * tells us the connection will be kept alive for our | |
| 3933 * pleasure. Default action for 1.0 is to close. | |
| 3934 * | |
| 3935 * [RFC2068, section 19.7.1] */ | |
| 3936 connkeep(conn, "Connection keep-alive"); | |
| 3937 infof(data, "HTTP/1.0 connection set to keep alive!\n"); | |
| 3938 } | |
| 3939 else if(Curl_compareheader(k->p, "Connection:", "close")) { | |
| 3940 /* | |
| 3941 * [RFC 2616, section 8.1.2.1] | |
| 3942 * "Connection: close" is HTTP/1.1 language and means that | |
| 3943 * the connection will close when this request has been | |
| 3944 * served. | |
| 3945 */ | |
| 3946 streamclose(conn, "Connection: close used"); | |
| 3947 } | |
| 3948 else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) { | |
| 3949 /* One or more encodings. We check for chunked and/or a compression | |
| 3950 algorithm. */ | |
| 3951 /* | |
| 3952 * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding | |
| 3953 * means that the server will send a series of "chunks". Each | |
| 3954 * chunk starts with line with info (including size of the | |
| 3955 * coming block) (terminated with CRLF), then a block of data | |
| 3956 * with the previously mentioned size. There can be any amount | |
| 3957 * of chunks, and a chunk-data set to zero signals the | |
| 3958 * end-of-chunks. */ | |
| 3959 | |
| 3960 result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE); | |
| 3961 if(result) | |
| 3962 return result; | |
| 3963 } | |
| 3964 else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) && | |
| 3965 data->set.str[STRING_ENCODING]) { | |
| 3966 /* | |
| 3967 * Process Content-Encoding. Look for the values: identity, | |
| 3968 * gzip, deflate, compress, x-gzip and x-compress. x-gzip and | |
| 3969 * x-compress are the same as gzip and compress. (Sec 3.5 RFC | |
| 3970 * 2616). zlib cannot handle compress. However, errors are | |
| 3971 * handled further down when the response body is processed | |
| 3972 */ | |
| 3973 result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE); | |
| 3974 if(result) | |
| 3975 return result; | |
| 3976 } | |
| 3977 else if(checkprefix("Retry-After:", k->p)) { | |
| 3978 /* Retry-After = HTTP-date / delay-seconds */ | |
| 3979 curl_off_t retry_after = 0; /* zero for unknown or "now" */ | |
| 3980 time_t date = curl_getdate(&k->p[12], NULL); | |
| 3981 if(-1 == date) { | |
| 3982 /* not a date, try it as a decimal number */ | |
| 3983 (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); | |
| 3984 } | |
| 3985 else | |
| 3986 /* convert date to number of seconds into the future */ | |
| 3987 retry_after = date - time(NULL); | |
| 3988 data->info.retry_after = retry_after; /* store it */ | |
| 3989 } | |
| 3990 else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) { | |
| 3991 /* Content-Range: bytes [num]- | |
| 3992 Content-Range: bytes: [num]- | |
| 3993 Content-Range: [num]- | |
| 3994 Content-Range: [asterisk]/[total] | |
| 3995 | |
| 3996 The second format was added since Sun's webserver | |
| 3997 JavaWebServer/1.1.1 obviously sends the header this way! | |
| 3998 The third added since some servers use that! | |
| 3999 The forth means the requested range was unsatisfied. | |
| 4000 */ | |
| 4001 | |
| 4002 char *ptr = k->p + 14; | |
| 4003 | |
| 4004 /* Move forward until first digit or asterisk */ | |
| 4005 while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') | |
| 4006 ptr++; | |
| 4007 | |
| 4008 /* if it truly stopped on a digit */ | |
| 4009 if(ISDIGIT(*ptr)) { | |
| 4010 if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { | |
| 4011 if(data->state.resume_from == k->offset) | |
| 4012 /* we asked for a resume and we got it */ | |
| 4013 k->content_range = TRUE; | |
| 4014 } | |
| 4015 } | |
| 4016 else | |
| 4017 data->state.resume_from = 0; /* get everything */ | |
| 4018 } | |
| 4019 #if !defined(CURL_DISABLE_COOKIES) | |
| 4020 else if(data->cookies && | |
| 4021 checkprefix("Set-Cookie:", k->p)) { | |
| 4022 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, | |
| 4023 CURL_LOCK_ACCESS_SINGLE); | |
| 4024 Curl_cookie_add(data, | |
| 4025 data->cookies, TRUE, FALSE, k->p + 11, | |
| 4026 /* If there is a custom-set Host: name, use it | |
| 4027 here, or else use real peer host name. */ | |
| 4028 conn->allocptr.cookiehost? | |
| 4029 conn->allocptr.cookiehost:conn->host.name, | |
| 4030 data->state.up.path, | |
| 4031 (conn->handler->protocol&CURLPROTO_HTTPS)? | |
| 4032 TRUE:FALSE); | |
| 4033 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); | |
| 4034 } | |
| 4035 #endif | |
| 4036 else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && | |
| 4037 (data->set.timecondition || data->set.get_filetime) ) { | |
| 4038 time_t secs = time(NULL); | |
| 4039 k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"), | |
| 4040 &secs); | |
| 4041 if(data->set.get_filetime) | |
| 4042 data->info.filetime = k->timeofdoc; | |
| 4043 } | |
| 4044 else if((checkprefix("WWW-Authenticate:", k->p) && | |
| 4045 (401 == k->httpcode)) || | |
| 4046 (checkprefix("Proxy-authenticate:", k->p) && | |
| 4047 (407 == k->httpcode))) { | |
| 4048 | |
| 4049 bool proxy = (k->httpcode == 407) ? TRUE : FALSE; | |
| 4050 char *auth = Curl_copy_header_value(k->p); | |
| 4051 if(!auth) | |
| 4052 return CURLE_OUT_OF_MEMORY; | |
| 4053 | |
| 4054 result = Curl_http_input_auth(conn, proxy, auth); | |
| 4055 | |
| 4056 free(auth); | |
| 4057 | |
| 4058 if(result) | |
| 4059 return result; | |
| 4060 } | |
| 4061 #ifdef USE_SPNEGO | |
| 4062 else if(checkprefix("Persistent-Auth", k->p)) { | |
| 4063 struct negotiatedata *negdata = &conn->negotiate; | |
| 4064 struct auth *authp = &data->state.authhost; | |
| 4065 if(authp->picked == CURLAUTH_NEGOTIATE) { | |
| 4066 char *persistentauth = Curl_copy_header_value(k->p); | |
| 4067 if(!persistentauth) | |
| 4068 return CURLE_OUT_OF_MEMORY; | |
| 4069 negdata->noauthpersist = checkprefix("false", persistentauth); | |
| 4070 negdata->havenoauthpersist = TRUE; | |
| 4071 infof(data, "Negotiate: noauthpersist -> %d, header part: %s", | |
| 4072 negdata->noauthpersist, persistentauth); | |
| 4073 free(persistentauth); | |
| 4074 } | |
| 4075 } | |
| 4076 #endif | |
| 4077 else if((k->httpcode >= 300 && k->httpcode < 400) && | |
| 4078 checkprefix("Location:", k->p) && | |
| 4079 !data->req.location) { | |
| 4080 /* this is the URL that the server advises us to use instead */ | |
| 4081 char *location = Curl_copy_header_value(k->p); | |
| 4082 if(!location) | |
| 4083 return CURLE_OUT_OF_MEMORY; | |
| 4084 if(!*location) | |
| 4085 /* ignore empty data */ | |
| 4086 free(location); | |
| 4087 else { | |
| 4088 data->req.location = location; | |
| 4089 | |
| 4090 if(data->set.http_follow_location) { | |
| 4091 DEBUGASSERT(!data->req.newurl); | |
| 4092 data->req.newurl = strdup(data->req.location); /* clone */ | |
| 4093 if(!data->req.newurl) | |
| 4094 return CURLE_OUT_OF_MEMORY; | |
| 4095 | |
| 4096 /* some cases of POST and PUT etc needs to rewind the data | |
| 4097 stream at this point */ | |
| 4098 result = http_perhapsrewind(conn); | |
| 4099 if(result) | |
| 4100 return result; | |
| 4101 } | |
| 4102 } | |
| 4103 } | |
| 4104 #ifdef USE_ALTSVC | |
| 4105 /* If enabled, the header is incoming and this is over HTTPS */ | |
| 4106 else if(data->asi && checkprefix("Alt-Svc:", k->p) && | |
| 4107 ((conn->handler->flags & PROTOPT_SSL) || | |
| 4108 #ifdef CURLDEBUG | |
| 4109 /* allow debug builds to circumvent the HTTPS restriction */ | |
| 4110 getenv("CURL_ALTSVC_HTTP") | |
| 4111 #else | |
| 4112 0 | |
| 4113 #endif | |
| 4114 )) { | |
| 4115 /* the ALPN of the current request */ | |
| 4116 enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; | |
| 4117 result = Curl_altsvc_parse(data, data->asi, | |
| 4118 &k->p[ strlen("Alt-Svc:") ], | |
| 4119 id, conn->host.name, | |
| 4120 curlx_uitous(conn->remote_port)); | |
| 4121 if(result) | |
| 4122 return result; | |
| 4123 } | |
| 4124 #endif | |
| 4125 else if(conn->handler->protocol & CURLPROTO_RTSP) { | |
| 4126 result = Curl_rtsp_parseheader(conn, k->p); | |
| 4127 if(result) | |
| 4128 return result; | |
| 4129 } | |
| 4130 | |
| 4131 /* | |
| 4132 * End of header-checks. Write them to the client. | |
| 4133 */ | |
| 4134 | |
| 4135 writetype = CLIENTWRITE_HEADER; | |
| 4136 if(data->set.include_header) | |
| 4137 writetype |= CLIENTWRITE_BODY; | |
| 4138 | |
| 4139 if(data->set.verbose) | |
| 4140 Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen); | |
| 4141 | |
| 4142 result = Curl_client_write(conn, writetype, k->p, k->hbuflen); | |
| 4143 if(result) | |
| 4144 return result; | |
| 4145 | |
| 4146 data->info.header_size += (long)k->hbuflen; | |
| 4147 data->req.headerbytecount += (long)k->hbuflen; | |
| 4148 | |
| 4149 /* reset hbufp pointer && hbuflen */ | |
| 4150 k->hbufp = data->state.headerbuff; | |
| 4151 k->hbuflen = 0; | |
| 4152 } | |
| 4153 while(*k->str); /* header line within buffer */ | |
| 4154 | |
| 4155 /* We might have reached the end of the header part here, but | |
| 4156 there might be a non-header part left in the end of the read | |
| 4157 buffer. */ | |
| 4158 | |
| 4159 return CURLE_OK; | |
| 4160 } | |
| 4161 | |
| 4162 #endif /* CURL_DISABLE_HTTP */ |
