request.c (13314B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 27 #include "urldata.h" 28 #include "cfilters.h" 29 #include "curlx/dynbuf.h" 30 #include "doh.h" 31 #include "multiif.h" 32 #include "progress.h" 33 #include "request.h" 34 #include "sendf.h" 35 #include "transfer.h" 36 #include "url.h" 37 #include "curlx/strparse.h" 38 39 /* The last 3 #include files should be in this order */ 40 #include "curl_printf.h" 41 #include "curl_memory.h" 42 #include "memdebug.h" 43 44 void Curl_req_init(struct SingleRequest *req) 45 { 46 memset(req, 0, sizeof(*req)); 47 } 48 49 CURLcode Curl_req_soft_reset(struct SingleRequest *req, 50 struct Curl_easy *data) 51 { 52 CURLcode result; 53 54 req->done = FALSE; 55 req->upload_done = FALSE; 56 req->upload_aborted = FALSE; 57 req->download_done = FALSE; 58 req->eos_written = FALSE; 59 req->eos_read = FALSE; 60 req->eos_sent = FALSE; 61 req->ignorebody = FALSE; 62 req->shutdown = FALSE; 63 req->bytecount = 0; 64 req->writebytecount = 0; 65 req->header = TRUE; /* assume header */ 66 req->headerline = 0; 67 req->headerbytecount = 0; 68 req->allheadercount = 0; 69 req->deductheadercount = 0; 70 req->httpversion_sent = 0; 71 req->httpversion = 0; 72 req->sendbuf_hds_len = 0; 73 74 result = Curl_client_start(data); 75 if(result) 76 return result; 77 78 if(!req->sendbuf_init) { 79 Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1, 80 BUFQ_OPT_SOFT_LIMIT); 81 req->sendbuf_init = TRUE; 82 } 83 else { 84 Curl_bufq_reset(&req->sendbuf); 85 if(data->set.upload_buffer_size != req->sendbuf.chunk_size) { 86 Curl_bufq_free(&req->sendbuf); 87 Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1, 88 BUFQ_OPT_SOFT_LIMIT); 89 } 90 } 91 92 return CURLE_OK; 93 } 94 95 CURLcode Curl_req_start(struct SingleRequest *req, 96 struct Curl_easy *data) 97 { 98 req->start = curlx_now(); 99 return Curl_req_soft_reset(req, data); 100 } 101 102 static CURLcode req_flush(struct Curl_easy *data); 103 104 CURLcode Curl_req_done(struct SingleRequest *req, 105 struct Curl_easy *data, bool aborted) 106 { 107 (void)req; 108 if(!aborted) 109 (void)req_flush(data); 110 Curl_client_reset(data); 111 #ifndef CURL_DISABLE_DOH 112 Curl_doh_close(data); 113 #endif 114 return CURLE_OK; 115 } 116 117 void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) 118 { 119 struct curltime t0 = {0, 0}; 120 121 Curl_safefree(req->newurl); 122 Curl_client_reset(data); 123 if(req->sendbuf_init) 124 Curl_bufq_reset(&req->sendbuf); 125 126 #ifndef CURL_DISABLE_DOH 127 Curl_doh_close(data); 128 #endif 129 /* Can no longer memset() this struct as we need to keep some state */ 130 req->size = -1; 131 req->maxdownload = -1; 132 req->bytecount = 0; 133 req->writebytecount = 0; 134 req->start = t0; 135 req->headerbytecount = 0; 136 req->allheadercount = 0; 137 req->deductheadercount = 0; 138 req->headerline = 0; 139 req->offset = 0; 140 req->httpcode = 0; 141 req->keepon = 0; 142 req->upgr101 = UPGR101_INIT; 143 req->sendbuf_hds_len = 0; 144 req->timeofdoc = 0; 145 req->location = NULL; 146 req->newurl = NULL; 147 #ifndef CURL_DISABLE_COOKIES 148 req->setcookies = 0; 149 #endif 150 req->header = FALSE; 151 req->content_range = FALSE; 152 req->download_done = FALSE; 153 req->eos_written = FALSE; 154 req->eos_read = FALSE; 155 req->eos_sent = FALSE; 156 req->upload_done = FALSE; 157 req->upload_aborted = FALSE; 158 req->ignorebody = FALSE; 159 req->http_bodyless = FALSE; 160 req->chunk = FALSE; 161 req->ignore_cl = FALSE; 162 req->upload_chunky = FALSE; 163 req->getheader = FALSE; 164 req->no_body = data->set.opt_no_body; 165 req->authneg = FALSE; 166 req->shutdown = FALSE; 167 } 168 169 void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data) 170 { 171 Curl_safefree(req->newurl); 172 if(req->sendbuf_init) 173 Curl_bufq_free(&req->sendbuf); 174 Curl_client_cleanup(data); 175 } 176 177 static CURLcode xfer_send(struct Curl_easy *data, 178 const char *buf, size_t blen, 179 size_t hds_len, size_t *pnwritten) 180 { 181 CURLcode result = CURLE_OK; 182 bool eos = FALSE; 183 184 *pnwritten = 0; 185 DEBUGASSERT(hds_len <= blen); 186 #ifdef DEBUGBUILD 187 { 188 /* Allow debug builds to override this logic to force short initial 189 sends */ 190 size_t body_len = blen - hds_len; 191 if(body_len) { 192 const char *p = getenv("CURL_SMALLREQSEND"); 193 if(p) { 194 curl_off_t body_small; 195 if(!curlx_str_number(&p, &body_small, body_len)) 196 blen = hds_len + (size_t)body_small; 197 } 198 } 199 } 200 #endif 201 /* Make sure this does not send more body bytes than what the max send 202 speed says. The headers do not count to the max speed. */ 203 if(data->set.max_send_speed) { 204 size_t body_bytes = blen - hds_len; 205 if((curl_off_t)body_bytes > data->set.max_send_speed) 206 blen = hds_len + (size_t)data->set.max_send_speed; 207 } 208 209 if(data->req.eos_read && 210 (Curl_bufq_is_empty(&data->req.sendbuf) || 211 Curl_bufq_len(&data->req.sendbuf) == blen)) { 212 DEBUGF(infof(data, "sending last upload chunk of %zu bytes", blen)); 213 eos = TRUE; 214 } 215 result = Curl_xfer_send(data, buf, blen, eos, pnwritten); 216 if(!result) { 217 if(eos && (blen == *pnwritten)) 218 data->req.eos_sent = TRUE; 219 if(*pnwritten) { 220 if(hds_len) 221 Curl_debug(data, CURLINFO_HEADER_OUT, buf, 222 CURLMIN(hds_len, *pnwritten)); 223 if(*pnwritten > hds_len) { 224 size_t body_len = *pnwritten - hds_len; 225 Curl_debug(data, CURLINFO_DATA_OUT, buf + hds_len, body_len); 226 data->req.writebytecount += body_len; 227 Curl_pgrsSetUploadCounter(data, data->req.writebytecount); 228 } 229 } 230 } 231 return result; 232 } 233 234 static CURLcode req_send_buffer_flush(struct Curl_easy *data) 235 { 236 CURLcode result = CURLE_OK; 237 const unsigned char *buf; 238 size_t blen; 239 240 while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) { 241 size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, blen); 242 result = xfer_send(data, (const char *)buf, blen, hds_len, &nwritten); 243 if(result) 244 break; 245 246 Curl_bufq_skip(&data->req.sendbuf, nwritten); 247 if(hds_len) { 248 data->req.sendbuf_hds_len -= CURLMIN(hds_len, nwritten); 249 } 250 /* leave if we could not send all. Maybe network blocking or 251 * speed limits on transfer */ 252 if(nwritten < blen) 253 break; 254 } 255 return result; 256 } 257 258 static CURLcode req_set_upload_done(struct Curl_easy *data) 259 { 260 DEBUGASSERT(!data->req.upload_done); 261 data->req.upload_done = TRUE; 262 data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we are done sending */ 263 264 Curl_pgrsTime(data, TIMER_POSTRANSFER); 265 Curl_creader_done(data, data->req.upload_aborted); 266 267 if(data->req.upload_aborted) { 268 Curl_bufq_reset(&data->req.sendbuf); 269 if(data->req.writebytecount) 270 infof(data, "abort upload after having sent %" FMT_OFF_T " bytes", 271 data->req.writebytecount); 272 else 273 infof(data, "abort upload"); 274 } 275 else if(data->req.writebytecount) 276 infof(data, "upload completely sent off: %" FMT_OFF_T " bytes", 277 data->req.writebytecount); 278 else if(!data->req.download_done) { 279 DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf)); 280 infof(data, Curl_creader_total_length(data) ? 281 "We are completely uploaded and fine" : 282 "Request completely sent off"); 283 } 284 285 return Curl_xfer_send_close(data); 286 } 287 288 static CURLcode req_flush(struct Curl_easy *data) 289 { 290 CURLcode result; 291 292 if(!data || !data->conn) 293 return CURLE_FAILED_INIT; 294 295 if(!Curl_bufq_is_empty(&data->req.sendbuf)) { 296 result = req_send_buffer_flush(data); 297 if(result) 298 return result; 299 if(!Curl_bufq_is_empty(&data->req.sendbuf)) { 300 DEBUGF(infof(data, "Curl_req_flush(len=%zu) -> EAGAIN", 301 Curl_bufq_len(&data->req.sendbuf))); 302 return CURLE_AGAIN; 303 } 304 } 305 else if(Curl_xfer_needs_flush(data)) { 306 DEBUGF(infof(data, "Curl_req_flush(), xfer send_pending")); 307 return Curl_xfer_flush(data); 308 } 309 310 if(data->req.eos_read && !data->req.eos_sent) { 311 char tmp; 312 size_t nwritten; 313 result = xfer_send(data, &tmp, 0, 0, &nwritten); 314 if(result) 315 return result; 316 DEBUGASSERT(data->req.eos_sent); 317 } 318 319 if(!data->req.upload_done && data->req.eos_read && data->req.eos_sent) { 320 DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf)); 321 if(data->req.shutdown) { 322 bool done; 323 result = Curl_xfer_send_shutdown(data, &done); 324 if(result && data->req.shutdown_err_ignore) { 325 infof(data, "Shutdown send direction error: %d. Broken server? " 326 "Proceeding as if everything is ok.", result); 327 result = CURLE_OK; 328 done = TRUE; 329 } 330 331 if(result) 332 return result; 333 if(!done) 334 return CURLE_AGAIN; 335 } 336 return req_set_upload_done(data); 337 } 338 return CURLE_OK; 339 } 340 341 static CURLcode add_from_client(void *reader_ctx, 342 unsigned char *buf, size_t buflen, 343 size_t *pnread) 344 { 345 struct Curl_easy *data = reader_ctx; 346 CURLcode result; 347 bool eos; 348 349 result = Curl_client_read(data, (char *)buf, buflen, pnread, &eos); 350 if(!result && eos) 351 data->req.eos_read = TRUE; 352 return result; 353 } 354 355 static CURLcode req_send_buffer_add(struct Curl_easy *data, 356 const char *buf, size_t blen, 357 size_t hds_len) 358 { 359 CURLcode result = CURLE_OK; 360 size_t n; 361 result = Curl_bufq_cwrite(&data->req.sendbuf, buf, blen, &n); 362 if(result) 363 return result; 364 /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */ 365 DEBUGASSERT(n == blen); 366 data->req.sendbuf_hds_len += hds_len; 367 return CURLE_OK; 368 } 369 370 CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *req, 371 unsigned char httpversion) 372 { 373 CURLcode result; 374 const char *buf; 375 size_t blen, nwritten; 376 377 if(!data || !data->conn) 378 return CURLE_FAILED_INIT; 379 380 data->req.httpversion_sent = httpversion; 381 buf = curlx_dyn_ptr(req); 382 blen = curlx_dyn_len(req); 383 if(!Curl_creader_total_length(data)) { 384 /* Request without body. Try to send directly from the buf given. */ 385 data->req.eos_read = TRUE; 386 result = xfer_send(data, buf, blen, blen, &nwritten); 387 if(result) 388 return result; 389 buf += nwritten; 390 blen -= nwritten; 391 } 392 393 if(blen) { 394 /* Either we have a request body, or we could not send the complete 395 * request in one go. Buffer the remainder and try to add as much 396 * body bytes as room is left in the buffer. Then flush. */ 397 result = req_send_buffer_add(data, buf, blen, blen); 398 if(result) 399 return result; 400 401 return Curl_req_send_more(data); 402 } 403 return CURLE_OK; 404 } 405 406 bool Curl_req_sendbuf_empty(struct Curl_easy *data) 407 { 408 return !data->req.sendbuf_init || Curl_bufq_is_empty(&data->req.sendbuf); 409 } 410 411 bool Curl_req_want_send(struct Curl_easy *data) 412 { 413 /* Not done and 414 * - KEEP_SEND and not PAUSEd. 415 * - or request has buffered data to send 416 * - or transfer connection has pending data to send */ 417 return !data->req.done && 418 (((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) || 419 !Curl_req_sendbuf_empty(data) || 420 Curl_xfer_needs_flush(data)); 421 } 422 423 bool Curl_req_done_sending(struct Curl_easy *data) 424 { 425 return data->req.upload_done && !Curl_req_want_send(data); 426 } 427 428 CURLcode Curl_req_send_more(struct Curl_easy *data) 429 { 430 CURLcode result; 431 432 /* Fill our send buffer if more from client can be read. */ 433 if(!data->req.upload_aborted && 434 !data->req.eos_read && 435 !Curl_xfer_send_is_paused(data) && 436 !Curl_bufq_is_full(&data->req.sendbuf)) { 437 size_t nread; 438 result = Curl_bufq_sipn(&data->req.sendbuf, 0, 439 add_from_client, data, &nread); 440 if(result && result != CURLE_AGAIN) 441 return result; 442 } 443 444 result = req_flush(data); 445 if(result == CURLE_AGAIN) 446 result = CURLE_OK; 447 448 return result; 449 } 450 451 CURLcode Curl_req_abort_sending(struct Curl_easy *data) 452 { 453 if(!data->req.upload_done) { 454 Curl_bufq_reset(&data->req.sendbuf); 455 data->req.upload_aborted = TRUE; 456 /* no longer KEEP_SEND and KEEP_SEND_PAUSE */ 457 data->req.keepon &= ~KEEP_SENDBITS; 458 return req_set_upload_done(data); 459 } 460 return CURLE_OK; 461 } 462 463 CURLcode Curl_req_stop_send_recv(struct Curl_easy *data) 464 { 465 /* stop receiving and ALL sending as well, including PAUSE and HOLD. 466 * We might still be paused on receive client writes though, so 467 * keep those bits around. */ 468 data->req.keepon &= ~(KEEP_RECV|KEEP_SENDBITS); 469 return Curl_req_abort_sending(data); 470 }