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