| 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 |  |