VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/c-hyper.c@ 97122

最後變更 在這個檔案從97122是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 33.3 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, 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#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
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 <hyper.h>
49#include "urldata.h"
50#include "sendf.h"
51#include "transfer.h"
52#include "multiif.h"
53#include "progress.h"
54#include "content_encoding.h"
55
56/* The last 3 #include files should be in this order */
57#include "curl_printf.h"
58#include "curl_memory.h"
59#include "memdebug.h"
60
61size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
62 uint8_t *buf, size_t buflen)
63{
64 struct Curl_easy *data = userp;
65 struct connectdata *conn = data->conn;
66 CURLcode result;
67 ssize_t nread;
68 DEBUGASSERT(conn);
69 (void)ctx;
70
71 result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
72 if(result == CURLE_AGAIN) {
73 /* would block, register interest */
74 if(data->hyp.read_waker)
75 hyper_waker_free(data->hyp.read_waker);
76 data->hyp.read_waker = hyper_context_waker(ctx);
77 if(!data->hyp.read_waker) {
78 failf(data, "Couldn't make the read hyper_context_waker");
79 return HYPER_IO_ERROR;
80 }
81 return HYPER_IO_PENDING;
82 }
83 else if(result) {
84 failf(data, "Curl_read failed");
85 return HYPER_IO_ERROR;
86 }
87 return (size_t)nread;
88}
89
90size_t Curl_hyper_send(void *userp, hyper_context *ctx,
91 const uint8_t *buf, size_t buflen)
92{
93 struct Curl_easy *data = userp;
94 struct connectdata *conn = data->conn;
95 CURLcode result;
96 ssize_t nwrote;
97
98 result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
99 if(result == CURLE_AGAIN) {
100 /* would block, register interest */
101 if(data->hyp.write_waker)
102 hyper_waker_free(data->hyp.write_waker);
103 data->hyp.write_waker = hyper_context_waker(ctx);
104 if(!data->hyp.write_waker) {
105 failf(data, "Couldn't make the write hyper_context_waker");
106 return HYPER_IO_ERROR;
107 }
108 return HYPER_IO_PENDING;
109 }
110 else if(result) {
111 failf(data, "Curl_write failed");
112 return HYPER_IO_ERROR;
113 }
114 return (size_t)nwrote;
115}
116
117static int hyper_each_header(void *userdata,
118 const uint8_t *name,
119 size_t name_len,
120 const uint8_t *value,
121 size_t value_len)
122{
123 struct Curl_easy *data = (struct Curl_easy *)userdata;
124 size_t len;
125 char *headp;
126 CURLcode result;
127 int writetype;
128
129 if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
130 failf(data, "Too long response header");
131 data->state.hresult = CURLE_OUT_OF_MEMORY;
132 return HYPER_ITER_BREAK;
133 }
134
135 if(!data->req.bytecount)
136 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
137
138 Curl_dyn_reset(&data->state.headerb);
139 if(name_len) {
140 if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
141 (int) name_len, name, (int) value_len, value))
142 return HYPER_ITER_BREAK;
143 }
144 else {
145 if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n")))
146 return HYPER_ITER_BREAK;
147 }
148 len = Curl_dyn_len(&data->state.headerb);
149 headp = Curl_dyn_ptr(&data->state.headerb);
150
151 result = Curl_http_header(data, data->conn, headp);
152 if(result) {
153 data->state.hresult = result;
154 return HYPER_ITER_BREAK;
155 }
156
157 Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
158
159 if(!data->state.hconnect || !data->set.suppress_connect_headers) {
160 writetype = CLIENTWRITE_HEADER;
161 if(data->set.include_header)
162 writetype |= CLIENTWRITE_BODY;
163 result = Curl_client_write(data, writetype, headp, len);
164 if(result) {
165 data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
166 return HYPER_ITER_BREAK;
167 }
168 }
169
170 data->info.header_size += (long)len;
171 data->req.headerbytecount += (long)len;
172 return HYPER_ITER_CONTINUE;
173}
174
175static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
176{
177 char *buf = (char *)hyper_buf_bytes(chunk);
178 size_t len = hyper_buf_len(chunk);
179 struct Curl_easy *data = (struct Curl_easy *)userdata;
180 struct SingleRequest *k = &data->req;
181 CURLcode result = CURLE_OK;
182
183 if(0 == k->bodywrites++) {
184 bool done = FALSE;
185#if defined(USE_NTLM)
186 struct connectdata *conn = data->conn;
187 if(conn->bits.close &&
188 (((data->req.httpcode == 401) &&
189 (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
190 ((data->req.httpcode == 407) &&
191 (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
192 infof(data, "Connection closed while negotiating NTLM");
193 data->state.authproblem = TRUE;
194 Curl_safefree(data->req.newurl);
195 }
196#endif
197 if(data->state.expect100header) {
198 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
199 if(data->req.httpcode < 400) {
200 k->exp100 = EXP100_SEND_DATA;
201 if(data->hyp.exp100_waker) {
202 hyper_waker_wake(data->hyp.exp100_waker);
203 data->hyp.exp100_waker = NULL;
204 }
205 }
206 else { /* >= 4xx */
207 k->exp100 = EXP100_FAILED;
208 }
209 }
210 if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
211 data->state.authproxy.done) {
212 done = TRUE;
213 result = CURLE_OK;
214 }
215 else
216 result = Curl_http_firstwrite(data, data->conn, &done);
217 if(result || done) {
218 infof(data, "Return early from hyper_body_chunk");
219 data->state.hresult = result;
220 return HYPER_ITER_BREAK;
221 }
222 }
223 if(k->ignorebody)
224 return HYPER_ITER_CONTINUE;
225 if(0 == len)
226 return HYPER_ITER_CONTINUE;
227 Curl_debug(data, CURLINFO_DATA_IN, buf, len);
228 if(!data->set.http_ce_skip && k->writer_stack)
229 /* content-encoded data */
230 result = Curl_unencode_write(data, k->writer_stack, buf, len);
231 else
232 result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
233
234 if(result) {
235 data->state.hresult = result;
236 return HYPER_ITER_BREAK;
237 }
238
239 data->req.bytecount += len;
240 Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
241 return HYPER_ITER_CONTINUE;
242}
243
244/*
245 * Hyper does not consider the status line, the first line in a HTTP/1
246 * response, to be a header. The libcurl API does. This function sends the
247 * status line in the header callback. */
248static CURLcode status_line(struct Curl_easy *data,
249 struct connectdata *conn,
250 uint16_t http_status,
251 int http_version,
252 const uint8_t *reason, size_t rlen)
253{
254 CURLcode result;
255 size_t len;
256 const char *vstr;
257 int writetype;
258 vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
259 (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
260 conn->httpversion =
261 http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
262 (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
263 if(http_version == HYPER_HTTP_VERSION_1_0)
264 data->state.httpwant = CURL_HTTP_VERSION_1_0;
265
266 if(data->state.hconnect)
267 /* CONNECT */
268 data->info.httpproxycode = http_status;
269
270 /* We need to set 'httpcodeq' for functions that check the response code in
271 a single place. */
272 data->req.httpcode = http_status;
273
274 result = Curl_http_statusline(data, conn);
275 if(result)
276 return result;
277
278 Curl_dyn_reset(&data->state.headerb);
279
280 result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
281 vstr,
282 (int)http_status,
283 (int)rlen, reason);
284 if(result)
285 return result;
286 len = Curl_dyn_len(&data->state.headerb);
287 Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
288 len);
289
290 if(!data->state.hconnect || !data->set.suppress_connect_headers) {
291 writetype = CLIENTWRITE_HEADER;
292 if(data->set.include_header)
293 writetype |= CLIENTWRITE_BODY;
294 result = Curl_client_write(data, writetype,
295 Curl_dyn_ptr(&data->state.headerb), len);
296 if(result)
297 return result;
298 }
299 data->info.header_size += (long)len;
300 data->req.headerbytecount += (long)len;
301 data->req.httpcode = http_status;
302 return CURLE_OK;
303}
304
305/*
306 * Hyper does not pass on the last empty response header. The libcurl API
307 * does. This function sends an empty header in the header callback.
308 */
309static CURLcode empty_header(struct Curl_easy *data)
310{
311 CURLcode result = Curl_http_size(data);
312 if(!result) {
313 result = hyper_each_header(data, NULL, 0, NULL, 0) ?
314 CURLE_WRITE_ERROR : CURLE_OK;
315 if(result)
316 failf(data, "hyperstream: couldn't pass blank header");
317 }
318 return result;
319}
320
321CURLcode Curl_hyper_stream(struct Curl_easy *data,
322 struct connectdata *conn,
323 int *didwhat,
324 bool *done,
325 int select_res)
326{
327 hyper_response *resp = NULL;
328 uint16_t http_status;
329 int http_version;
330 hyper_headers *headers = NULL;
331 hyper_body *resp_body = NULL;
332 struct hyptransfer *h = &data->hyp;
333 hyper_task *task;
334 hyper_task *foreach;
335 hyper_error *hypererr = NULL;
336 const uint8_t *reasonp;
337 size_t reason_len;
338 CURLcode result = CURLE_OK;
339 struct SingleRequest *k = &data->req;
340 (void)conn;
341
342 if(k->exp100 > EXP100_SEND_DATA) {
343 struct curltime now = Curl_now();
344 timediff_t ms = Curl_timediff(now, k->start100);
345 if(ms >= data->set.expect_100_timeout) {
346 /* we've waited long enough, continue anyway */
347 k->exp100 = EXP100_SEND_DATA;
348 k->keepon |= KEEP_SEND;
349 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
350 infof(data, "Done waiting for 100-continue");
351 if(data->hyp.exp100_waker) {
352 hyper_waker_wake(data->hyp.exp100_waker);
353 data->hyp.exp100_waker = NULL;
354 }
355 }
356 }
357
358 if(select_res & CURL_CSELECT_IN) {
359 if(h->read_waker)
360 hyper_waker_wake(h->read_waker);
361 h->read_waker = NULL;
362 }
363 if(select_res & CURL_CSELECT_OUT) {
364 if(h->write_waker)
365 hyper_waker_wake(h->write_waker);
366 h->write_waker = NULL;
367 }
368
369 *done = FALSE;
370 do {
371 hyper_task_return_type t;
372 task = hyper_executor_poll(h->exec);
373 if(!task) {
374 *didwhat = KEEP_RECV;
375 break;
376 }
377 t = hyper_task_type(task);
378 switch(t) {
379 case HYPER_TASK_ERROR:
380 hypererr = hyper_task_value(task);
381 break;
382 case HYPER_TASK_RESPONSE:
383 resp = hyper_task_value(task);
384 break;
385 default:
386 break;
387 }
388 hyper_task_free(task);
389
390 if(t == HYPER_TASK_ERROR) {
391 if(data->state.hresult) {
392 /* override Hyper's view, might not even be an error */
393 result = data->state.hresult;
394 infof(data, "hyperstream is done (by early callback)");
395 }
396 else {
397 uint8_t errbuf[256];
398 size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
399 hyper_code code = hyper_error_code(hypererr);
400 failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
401 if(code == HYPERE_ABORTED_BY_CALLBACK)
402 result = CURLE_OK;
403 else if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
404 result = CURLE_GOT_NOTHING;
405 else if(code == HYPERE_INVALID_PEER_MESSAGE)
406 result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
407 else
408 result = CURLE_RECV_ERROR;
409 }
410 *done = TRUE;
411 hyper_error_free(hypererr);
412 break;
413 }
414 else if(h->endtask == task) {
415 /* end of transfer */
416 *done = TRUE;
417 infof(data, "hyperstream is done");
418 if(!k->bodywrites) {
419 /* hyper doesn't always call the body write callback */
420 bool stilldone;
421 result = Curl_http_firstwrite(data, data->conn, &stilldone);
422 }
423 break;
424 }
425 else if(t != HYPER_TASK_RESPONSE) {
426 *didwhat = KEEP_RECV;
427 break;
428 }
429 /* HYPER_TASK_RESPONSE */
430
431 *didwhat = KEEP_RECV;
432 if(!resp) {
433 failf(data, "hyperstream: couldn't get response");
434 return CURLE_RECV_ERROR;
435 }
436
437 http_status = hyper_response_status(resp);
438 http_version = hyper_response_version(resp);
439 reasonp = hyper_response_reason_phrase(resp);
440 reason_len = hyper_response_reason_phrase_len(resp);
441
442 if(http_status == 417 && data->state.expect100header) {
443 infof(data, "Got 417 while waiting for a 100");
444 data->state.disableexpect = TRUE;
445 data->req.newurl = strdup(data->state.url);
446 Curl_done_sending(data, k);
447 }
448
449 result = status_line(data, conn,
450 http_status, http_version, reasonp, reason_len);
451 if(result)
452 break;
453
454 headers = hyper_response_headers(resp);
455 if(!headers) {
456 failf(data, "hyperstream: couldn't get response headers");
457 result = CURLE_RECV_ERROR;
458 break;
459 }
460
461 /* the headers are already received */
462 hyper_headers_foreach(headers, hyper_each_header, data);
463 if(data->state.hresult) {
464 result = data->state.hresult;
465 break;
466 }
467
468 result = empty_header(data);
469 if(result)
470 break;
471
472 /* Curl_http_auth_act() checks what authentication methods that are
473 * available and decides which one (if any) to use. It will set 'newurl'
474 * if an auth method was picked. */
475 result = Curl_http_auth_act(data);
476 if(result)
477 break;
478
479 resp_body = hyper_response_body(resp);
480 if(!resp_body) {
481 failf(data, "hyperstream: couldn't get response body");
482 result = CURLE_RECV_ERROR;
483 break;
484 }
485 foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
486 if(!foreach) {
487 failf(data, "hyperstream: body foreach failed");
488 result = CURLE_OUT_OF_MEMORY;
489 break;
490 }
491 DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
492 if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
493 failf(data, "Couldn't hyper_executor_push the body-foreach");
494 result = CURLE_OUT_OF_MEMORY;
495 break;
496 }
497 h->endtask = foreach;
498
499 hyper_response_free(resp);
500 resp = NULL;
501 } while(1);
502 if(resp)
503 hyper_response_free(resp);
504 return result;
505}
506
507static CURLcode debug_request(struct Curl_easy *data,
508 const char *method,
509 const char *path,
510 bool h2)
511{
512 char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
513 h2?"2":"1.1");
514 if(!req)
515 return CURLE_OUT_OF_MEMORY;
516 Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
517 free(req);
518 return CURLE_OK;
519}
520
521/*
522 * Given a full header line "name: value" (optional CRLF in the input, should
523 * be in the output), add to Hyper and send to the debug callback.
524 *
525 * Supports multiple headers.
526 */
527
528CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
529 const char *line)
530{
531 const char *p;
532 const char *n;
533 size_t nlen;
534 const char *v;
535 size_t vlen;
536 bool newline = TRUE;
537 int numh = 0;
538
539 if(!line)
540 return CURLE_OK;
541 n = line;
542 do {
543 size_t linelen = 0;
544
545 p = strchr(n, ':');
546 if(!p)
547 /* this is fine if we already added at least one header */
548 return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
549 nlen = p - n;
550 p++; /* move past the colon */
551 while(*p == ' ')
552 p++;
553 v = p;
554 p = strchr(v, '\r');
555 if(!p) {
556 p = strchr(v, '\n');
557 if(p)
558 linelen = 1; /* LF only */
559 else {
560 p = strchr(v, '\0');
561 newline = FALSE; /* no newline */
562 }
563 }
564 else
565 linelen = 2; /* CRLF ending */
566 linelen += (p - n);
567 vlen = p - v;
568
569 if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
570 (uint8_t *)v, vlen)) {
571 failf(data, "hyper refused to add header '%s'", line);
572 return CURLE_OUT_OF_MEMORY;
573 }
574 if(data->set.verbose) {
575 char *ptr = NULL;
576 if(!newline) {
577 ptr = aprintf("%.*s\r\n", (int)linelen, line);
578 if(!ptr)
579 return CURLE_OUT_OF_MEMORY;
580 Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
581 free(ptr);
582 }
583 else
584 Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
585 }
586 numh++;
587 n += linelen;
588 } while(newline);
589 return CURLE_OK;
590}
591
592static CURLcode request_target(struct Curl_easy *data,
593 struct connectdata *conn,
594 const char *method,
595 bool h2,
596 hyper_request *req)
597{
598 CURLcode result;
599 struct dynbuf r;
600
601 Curl_dyn_init(&r, DYN_HTTP_REQUEST);
602
603 result = Curl_http_target(data, conn, &r);
604 if(result)
605 return result;
606
607 if(h2 && hyper_request_set_uri_parts(req,
608 /* scheme */
609 (uint8_t *)data->state.up.scheme,
610 strlen(data->state.up.scheme),
611 /* authority */
612 (uint8_t *)conn->host.name,
613 strlen(conn->host.name),
614 /* path_and_query */
615 (uint8_t *)Curl_dyn_uptr(&r),
616 Curl_dyn_len(&r))) {
617 failf(data, "error setting uri parts to hyper");
618 result = CURLE_OUT_OF_MEMORY;
619 }
620 else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
621 Curl_dyn_len(&r))) {
622 failf(data, "error setting uri to hyper");
623 result = CURLE_OUT_OF_MEMORY;
624 }
625 else
626 result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
627
628 Curl_dyn_free(&r);
629
630 return result;
631}
632
633static int uploadpostfields(void *userdata, hyper_context *ctx,
634 hyper_buf **chunk)
635{
636 struct Curl_easy *data = (struct Curl_easy *)userdata;
637 (void)ctx;
638 if(data->req.exp100 > EXP100_SEND_DATA) {
639 if(data->req.exp100 == EXP100_FAILED)
640 return HYPER_POLL_ERROR;
641
642 /* still waiting confirmation */
643 if(data->hyp.exp100_waker)
644 hyper_waker_free(data->hyp.exp100_waker);
645 data->hyp.exp100_waker = hyper_context_waker(ctx);
646 return HYPER_POLL_PENDING;
647 }
648 if(data->req.upload_done)
649 *chunk = NULL; /* nothing more to deliver */
650 else {
651 /* send everything off in a single go */
652 hyper_buf *copy = hyper_buf_copy(data->set.postfields,
653 (size_t)data->req.p.http->postsize);
654 if(copy)
655 *chunk = copy;
656 else {
657 data->state.hresult = CURLE_OUT_OF_MEMORY;
658 return HYPER_POLL_ERROR;
659 }
660 /* increasing the writebytecount here is a little premature but we
661 don't know exactly when the body is sent*/
662 data->req.writebytecount += (size_t)data->req.p.http->postsize;
663 Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
664 data->req.upload_done = TRUE;
665 }
666 return HYPER_POLL_READY;
667}
668
669static int uploadstreamed(void *userdata, hyper_context *ctx,
670 hyper_buf **chunk)
671{
672 size_t fillcount;
673 struct Curl_easy *data = (struct Curl_easy *)userdata;
674 CURLcode result;
675 (void)ctx;
676
677 if(data->req.exp100 > EXP100_SEND_DATA) {
678 if(data->req.exp100 == EXP100_FAILED)
679 return HYPER_POLL_ERROR;
680
681 /* still waiting confirmation */
682 if(data->hyp.exp100_waker)
683 hyper_waker_free(data->hyp.exp100_waker);
684 data->hyp.exp100_waker = hyper_context_waker(ctx);
685 return HYPER_POLL_PENDING;
686 }
687
688 result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
689 if(result) {
690 data->state.hresult = result;
691 return HYPER_POLL_ERROR;
692 }
693 if(!fillcount)
694 /* done! */
695 *chunk = NULL;
696 else {
697 hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
698 if(copy)
699 *chunk = copy;
700 else {
701 data->state.hresult = CURLE_OUT_OF_MEMORY;
702 return HYPER_POLL_ERROR;
703 }
704 /* increasing the writebytecount here is a little premature but we
705 don't know exactly when the body is sent*/
706 data->req.writebytecount += fillcount;
707 Curl_pgrsSetUploadCounter(data, fillcount);
708 }
709 return HYPER_POLL_READY;
710}
711
712/*
713 * bodysend() sets up headers in the outgoing request for a HTTP transfer that
714 * sends a body
715 */
716
717static CURLcode bodysend(struct Curl_easy *data,
718 struct connectdata *conn,
719 hyper_headers *headers,
720 hyper_request *hyperreq,
721 Curl_HttpReq httpreq)
722{
723 struct HTTP *http = data->req.p.http;
724 CURLcode result = CURLE_OK;
725 struct dynbuf req;
726 if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
727 Curl_pgrsSetUploadSize(data, 0); /* no request body */
728 else {
729 hyper_body *body;
730 Curl_dyn_init(&req, DYN_HTTP_REQUEST);
731 result = Curl_http_bodysend(data, conn, &req, httpreq);
732
733 if(!result)
734 result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
735
736 Curl_dyn_free(&req);
737
738 body = hyper_body_new();
739 hyper_body_set_userdata(body, data);
740 if(data->set.postfields)
741 hyper_body_set_data_func(body, uploadpostfields);
742 else {
743 result = Curl_get_upload_buffer(data);
744 if(result)
745 return result;
746 /* init the "upload from here" pointer */
747 data->req.upload_fromhere = data->state.ulbuf;
748 hyper_body_set_data_func(body, uploadstreamed);
749 }
750 if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
751 /* fail */
752 hyper_body_free(body);
753 result = CURLE_OUT_OF_MEMORY;
754 }
755 }
756 http->sending = HTTPSEND_BODY;
757 return result;
758}
759
760static CURLcode cookies(struct Curl_easy *data,
761 struct connectdata *conn,
762 hyper_headers *headers)
763{
764 struct dynbuf req;
765 CURLcode result;
766 Curl_dyn_init(&req, DYN_HTTP_REQUEST);
767
768 result = Curl_http_cookies(data, conn, &req);
769 if(!result)
770 result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
771 Curl_dyn_free(&req);
772 return result;
773}
774
775/* called on 1xx responses */
776static void http1xx_cb(void *arg, struct hyper_response *resp)
777{
778 struct Curl_easy *data = (struct Curl_easy *)arg;
779 hyper_headers *headers = NULL;
780 CURLcode result = CURLE_OK;
781 uint16_t http_status;
782 int http_version;
783 const uint8_t *reasonp;
784 size_t reason_len;
785
786 infof(data, "Got HTTP 1xx informational");
787
788 http_status = hyper_response_status(resp);
789 http_version = hyper_response_version(resp);
790 reasonp = hyper_response_reason_phrase(resp);
791 reason_len = hyper_response_reason_phrase_len(resp);
792
793 result = status_line(data, data->conn,
794 http_status, http_version, reasonp, reason_len);
795 if(!result) {
796 headers = hyper_response_headers(resp);
797 if(!headers) {
798 failf(data, "hyperstream: couldn't get 1xx response headers");
799 result = CURLE_RECV_ERROR;
800 }
801 }
802 data->state.hresult = result;
803
804 if(!result) {
805 /* the headers are already received */
806 hyper_headers_foreach(headers, hyper_each_header, data);
807 /* this callback also sets data->state.hresult on error */
808
809 if(empty_header(data))
810 result = CURLE_OUT_OF_MEMORY;
811 }
812
813 if(data->state.hresult)
814 infof(data, "ERROR in 1xx, bail out");
815}
816
817/*
818 * Curl_http() gets called from the generic multi_do() function when a HTTP
819 * request is to be performed. This creates and sends a properly constructed
820 * HTTP request.
821 */
822CURLcode Curl_http(struct Curl_easy *data, bool *done)
823{
824 struct connectdata *conn = data->conn;
825 struct hyptransfer *h = &data->hyp;
826 hyper_io *io = NULL;
827 hyper_clientconn_options *options = NULL;
828 hyper_task *task = NULL; /* for the handshake */
829 hyper_task *sendtask = NULL; /* for the send */
830 hyper_clientconn *client = NULL;
831 hyper_request *req = NULL;
832 hyper_headers *headers = NULL;
833 hyper_task *handshake = NULL;
834 CURLcode result;
835 const char *p_accept; /* Accept: string */
836 const char *method;
837 Curl_HttpReq httpreq;
838 bool h2 = FALSE;
839 const char *te = NULL; /* transfer-encoding */
840 hyper_code rc;
841
842 /* Always consider the DO phase done after this function call, even if there
843 may be parts of the request that is not yet sent, since we can deal with
844 the rest of the request in the PERFORM phase. */
845 *done = TRUE;
846
847 infof(data, "Time for the Hyper dance");
848 memset(h, 0, sizeof(struct hyptransfer));
849
850 result = Curl_http_host(data, conn);
851 if(result)
852 return result;
853
854 Curl_http_method(data, conn, &method, &httpreq);
855
856 /* setup the authentication headers */
857 {
858 char *pq = NULL;
859 if(data->state.up.query) {
860 pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
861 if(!pq)
862 return CURLE_OUT_OF_MEMORY;
863 }
864 result = Curl_http_output_auth(data, conn, method, httpreq,
865 (pq ? pq : data->state.up.path), FALSE);
866 free(pq);
867 if(result)
868 return result;
869 }
870
871 result = Curl_http_resume(data, conn, httpreq);
872 if(result)
873 return result;
874
875 result = Curl_http_range(data, httpreq);
876 if(result)
877 return result;
878
879 result = Curl_http_useragent(data);
880 if(result)
881 return result;
882
883 io = hyper_io_new();
884 if(!io) {
885 failf(data, "Couldn't create hyper IO");
886 result = CURLE_OUT_OF_MEMORY;
887 goto error;
888 }
889 /* tell Hyper how to read/write network data */
890 hyper_io_set_userdata(io, data);
891 hyper_io_set_read(io, Curl_hyper_recv);
892 hyper_io_set_write(io, Curl_hyper_send);
893
894 /* create an executor to poll futures */
895 if(!h->exec) {
896 h->exec = hyper_executor_new();
897 if(!h->exec) {
898 failf(data, "Couldn't create hyper executor");
899 result = CURLE_OUT_OF_MEMORY;
900 goto error;
901 }
902 }
903
904 options = hyper_clientconn_options_new();
905 if(!options) {
906 failf(data, "Couldn't create hyper client options");
907 result = CURLE_OUT_OF_MEMORY;
908 goto error;
909 }
910 if(conn->negnpn == CURL_HTTP_VERSION_2) {
911 hyper_clientconn_options_http2(options, 1);
912 h2 = TRUE;
913 }
914 hyper_clientconn_options_set_preserve_header_case(options, 1);
915 hyper_clientconn_options_set_preserve_header_order(options, 1);
916
917 hyper_clientconn_options_exec(options, h->exec);
918
919 /* "Both the `io` and the `options` are consumed in this function call" */
920 handshake = hyper_clientconn_handshake(io, options);
921 if(!handshake) {
922 failf(data, "Couldn't create hyper client handshake");
923 result = CURLE_OUT_OF_MEMORY;
924 goto error;
925 }
926 io = NULL;
927 options = NULL;
928
929 if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
930 failf(data, "Couldn't hyper_executor_push the handshake");
931 result = CURLE_OUT_OF_MEMORY;
932 goto error;
933 }
934 handshake = NULL; /* ownership passed on */
935
936 task = hyper_executor_poll(h->exec);
937 if(!task) {
938 failf(data, "Couldn't hyper_executor_poll the handshake");
939 result = CURLE_OUT_OF_MEMORY;
940 goto error;
941 }
942
943 client = hyper_task_value(task);
944 hyper_task_free(task);
945
946 req = hyper_request_new();
947 if(!req) {
948 failf(data, "Couldn't hyper_request_new");
949 result = CURLE_OUT_OF_MEMORY;
950 goto error;
951 }
952
953 if(!Curl_use_http_1_1plus(data, conn)) {
954 if(HYPERE_OK != hyper_request_set_version(req,
955 HYPER_HTTP_VERSION_1_0)) {
956 failf(data, "error setting HTTP version");
957 result = CURLE_OUT_OF_MEMORY;
958 goto error;
959 }
960 }
961 else {
962 if(!h2 && !data->state.disableexpect) {
963 data->state.expect100header = TRUE;
964 }
965 }
966
967 if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
968 failf(data, "error setting method");
969 result = CURLE_OUT_OF_MEMORY;
970 goto error;
971 }
972
973 result = request_target(data, conn, method, h2, req);
974 if(result)
975 goto error;
976
977 headers = hyper_request_headers(req);
978 if(!headers) {
979 failf(data, "hyper_request_headers");
980 result = CURLE_OUT_OF_MEMORY;
981 goto error;
982 }
983
984 rc = hyper_request_on_informational(req, http1xx_cb, data);
985 if(rc) {
986 result = CURLE_OUT_OF_MEMORY;
987 goto error;
988 }
989
990 result = Curl_http_body(data, conn, httpreq, &te);
991 if(result)
992 goto error;
993
994 if(!h2) {
995 if(data->state.aptr.host) {
996 result = Curl_hyper_header(data, headers, data->state.aptr.host);
997 if(result)
998 goto error;
999 }
1000 }
1001 else {
1002 /* For HTTP/2, we show the Host: header as if we sent it, to make it look
1003 like for HTTP/1 but it isn't actually sent since :authority is then
1004 used. */
1005 result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host,
1006 strlen(data->state.aptr.host));
1007 if(result)
1008 goto error;
1009 }
1010
1011 if(data->state.aptr.proxyuserpwd) {
1012 result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
1013 if(result)
1014 goto error;
1015 }
1016
1017 if(data->state.aptr.userpwd) {
1018 result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
1019 if(result)
1020 goto error;
1021 }
1022
1023 if((data->state.use_range && data->state.aptr.rangeline)) {
1024 result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
1025 if(result)
1026 goto error;
1027 }
1028
1029 if(data->set.str[STRING_USERAGENT] &&
1030 *data->set.str[STRING_USERAGENT] &&
1031 data->state.aptr.uagent) {
1032 result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
1033 if(result)
1034 goto error;
1035 }
1036
1037 p_accept = Curl_checkheaders(data,
1038 STRCONST("Accept"))?NULL:"Accept: */*\r\n";
1039 if(p_accept) {
1040 result = Curl_hyper_header(data, headers, p_accept);
1041 if(result)
1042 goto error;
1043 }
1044 if(te) {
1045 result = Curl_hyper_header(data, headers, te);
1046 if(result)
1047 goto error;
1048 }
1049
1050#ifndef CURL_DISABLE_PROXY
1051 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
1052 !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
1053 !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
1054 result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
1055 if(result)
1056 goto error;
1057 }
1058#endif
1059
1060 Curl_safefree(data->state.aptr.ref);
1061 if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
1062 data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
1063 if(!data->state.aptr.ref)
1064 result = CURLE_OUT_OF_MEMORY;
1065 else
1066 result = Curl_hyper_header(data, headers, data->state.aptr.ref);
1067 if(result)
1068 goto error;
1069 }
1070
1071 if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
1072 data->set.str[STRING_ENCODING]) {
1073 Curl_safefree(data->state.aptr.accept_encoding);
1074 data->state.aptr.accept_encoding =
1075 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
1076 if(!data->state.aptr.accept_encoding)
1077 result = CURLE_OUT_OF_MEMORY;
1078 else
1079 result = Curl_hyper_header(data, headers,
1080 data->state.aptr.accept_encoding);
1081 if(result)
1082 goto error;
1083 }
1084 else
1085 Curl_safefree(data->state.aptr.accept_encoding);
1086
1087#ifdef HAVE_LIBZ
1088 /* we only consider transfer-encoding magic if libz support is built-in */
1089 result = Curl_transferencode(data);
1090 if(result)
1091 goto error;
1092 result = Curl_hyper_header(data, headers, data->state.aptr.te);
1093 if(result)
1094 goto error;
1095#endif
1096
1097 result = cookies(data, conn, headers);
1098 if(result)
1099 goto error;
1100
1101 result = Curl_add_timecondition(data, headers);
1102 if(result)
1103 goto error;
1104
1105 result = Curl_add_custom_headers(data, FALSE, headers);
1106 if(result)
1107 goto error;
1108
1109 result = bodysend(data, conn, headers, req, httpreq);
1110 if(result)
1111 goto error;
1112
1113 result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
1114 if(result)
1115 goto error;
1116
1117 data->req.upload_chunky = FALSE;
1118 sendtask = hyper_clientconn_send(client, req);
1119 if(!sendtask) {
1120 failf(data, "hyper_clientconn_send");
1121 result = CURLE_OUT_OF_MEMORY;
1122 goto error;
1123 }
1124
1125 if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
1126 failf(data, "Couldn't hyper_executor_push the send");
1127 result = CURLE_OUT_OF_MEMORY;
1128 goto error;
1129 }
1130
1131 hyper_clientconn_free(client);
1132
1133 if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
1134 /* HTTP GET/HEAD download */
1135 Curl_pgrsSetUploadSize(data, 0); /* nothing */
1136 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
1137 }
1138 conn->datastream = Curl_hyper_stream;
1139 if(data->state.expect100header)
1140 /* Timeout count starts now since with Hyper we don't know exactly when
1141 the full request has been sent. */
1142 data->req.start100 = Curl_now();
1143
1144 /* clear userpwd and proxyuserpwd to avoid re-using old credentials
1145 * from re-used connections */
1146 Curl_safefree(data->state.aptr.userpwd);
1147 Curl_safefree(data->state.aptr.proxyuserpwd);
1148 return CURLE_OK;
1149 error:
1150 DEBUGASSERT(result);
1151 if(io)
1152 hyper_io_free(io);
1153
1154 if(options)
1155 hyper_clientconn_options_free(options);
1156
1157 if(handshake)
1158 hyper_task_free(handshake);
1159
1160 return result;
1161}
1162
1163void Curl_hyper_done(struct Curl_easy *data)
1164{
1165 struct hyptransfer *h = &data->hyp;
1166 if(h->exec) {
1167 hyper_executor_free(h->exec);
1168 h->exec = NULL;
1169 }
1170 if(h->read_waker) {
1171 hyper_waker_free(h->read_waker);
1172 h->read_waker = NULL;
1173 }
1174 if(h->write_waker) {
1175 hyper_waker_free(h->write_waker);
1176 h->write_waker = NULL;
1177 }
1178 if(h->exp100_waker) {
1179 hyper_waker_free(h->exp100_waker);
1180 h->exp100_waker = NULL;
1181 }
1182}
1183
1184#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette