1 /* 2 * QEMU Block driver for CURL images 3 * 4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qapi/error.h" 27 #include "qemu/error-report.h" 28 #include "qemu/module.h" 29 #include "qemu/option.h" 30 #include "block/block-io.h" 31 #include "block/block_int.h" 32 #include "qapi/qmp/qdict.h" 33 #include "qapi/qmp/qstring.h" 34 #include "crypto/secret.h" 35 #include <curl/curl.h> 36 #include "qemu/cutils.h" 37 #include "trace.h" 38 39 // #define DEBUG_VERBOSE 40 41 /* CURL 7.85.0 switches to a string based API for specifying 42 * the desired protocols. 43 */ 44 #if LIBCURL_VERSION_NUM >= 0x075500 45 #define PROTOCOLS "HTTP,HTTPS,FTP,FTPS" 46 #else 47 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ 48 CURLPROTO_FTP | CURLPROTO_FTPS) 49 #endif 50 51 #define CURL_NUM_STATES 8 52 #define CURL_NUM_ACB 8 53 #define CURL_TIMEOUT_MAX 10000 54 55 #define CURL_BLOCK_OPT_URL "url" 56 #define CURL_BLOCK_OPT_READAHEAD "readahead" 57 #define CURL_BLOCK_OPT_SSLVERIFY "sslverify" 58 #define CURL_BLOCK_OPT_TIMEOUT "timeout" 59 #define CURL_BLOCK_OPT_COOKIE "cookie" 60 #define CURL_BLOCK_OPT_COOKIE_SECRET "cookie-secret" 61 #define CURL_BLOCK_OPT_USERNAME "username" 62 #define CURL_BLOCK_OPT_PASSWORD_SECRET "password-secret" 63 #define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username" 64 #define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret" 65 66 #define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024) 67 #define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true 68 #define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5 69 70 struct BDRVCURLState; 71 struct CURLState; 72 73 static bool libcurl_initialized; 74 75 typedef struct CURLAIOCB { 76 Coroutine *co; 77 QEMUIOVector *qiov; 78 79 uint64_t offset; 80 uint64_t bytes; 81 int ret; 82 83 size_t start; 84 size_t end; 85 } CURLAIOCB; 86 87 typedef struct CURLSocket { 88 int fd; 89 struct BDRVCURLState *s; 90 } CURLSocket; 91 92 typedef struct CURLState 93 { 94 struct BDRVCURLState *s; 95 CURLAIOCB *acb[CURL_NUM_ACB]; 96 CURL *curl; 97 char *orig_buf; 98 uint64_t buf_start; 99 size_t buf_off; 100 size_t buf_len; 101 char range[128]; 102 char errmsg[CURL_ERROR_SIZE]; 103 char in_use; 104 } CURLState; 105 106 typedef struct BDRVCURLState { 107 CURLM *multi; 108 QEMUTimer timer; 109 uint64_t len; 110 CURLState states[CURL_NUM_STATES]; 111 GHashTable *sockets; /* GINT_TO_POINTER(fd) -> socket */ 112 char *url; 113 size_t readahead_size; 114 bool sslverify; 115 uint64_t timeout; 116 char *cookie; 117 bool accept_range; 118 AioContext *aio_context; 119 QemuMutex mutex; 120 CoQueue free_state_waitq; 121 char *username; 122 char *password; 123 char *proxyusername; 124 char *proxypassword; 125 } BDRVCURLState; 126 127 static void curl_clean_state(CURLState *s); 128 static void curl_multi_do(void *arg); 129 130 static gboolean curl_drop_socket(void *key, void *value, void *opaque) 131 { 132 CURLSocket *socket = value; 133 BDRVCURLState *s = socket->s; 134 135 aio_set_fd_handler(s->aio_context, socket->fd, 136 NULL, NULL, NULL, NULL, NULL); 137 return true; 138 } 139 140 static void curl_drop_all_sockets(GHashTable *sockets) 141 { 142 g_hash_table_foreach_remove(sockets, curl_drop_socket, NULL); 143 } 144 145 /* Called from curl_multi_do_locked, with s->mutex held. */ 146 static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque) 147 { 148 BDRVCURLState *s = opaque; 149 150 trace_curl_timer_cb(timeout_ms); 151 if (timeout_ms == -1) { 152 timer_del(&s->timer); 153 } else { 154 int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000; 155 timer_mod(&s->timer, 156 qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns); 157 } 158 return 0; 159 } 160 161 /* Called from curl_multi_do_locked, with s->mutex held. */ 162 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, 163 void *userp, void *sp) 164 { 165 BDRVCURLState *s; 166 CURLState *state = NULL; 167 CURLSocket *socket; 168 169 curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state); 170 s = state->s; 171 172 socket = g_hash_table_lookup(s->sockets, GINT_TO_POINTER(fd)); 173 if (!socket) { 174 socket = g_new0(CURLSocket, 1); 175 socket->fd = fd; 176 socket->s = s; 177 g_hash_table_insert(s->sockets, GINT_TO_POINTER(fd), socket); 178 } 179 180 trace_curl_sock_cb(action, (int)fd); 181 switch (action) { 182 case CURL_POLL_IN: 183 aio_set_fd_handler(s->aio_context, fd, 184 curl_multi_do, NULL, NULL, NULL, socket); 185 break; 186 case CURL_POLL_OUT: 187 aio_set_fd_handler(s->aio_context, fd, 188 NULL, curl_multi_do, NULL, NULL, socket); 189 break; 190 case CURL_POLL_INOUT: 191 aio_set_fd_handler(s->aio_context, fd, 192 curl_multi_do, curl_multi_do, 193 NULL, NULL, socket); 194 break; 195 case CURL_POLL_REMOVE: 196 aio_set_fd_handler(s->aio_context, fd, 197 NULL, NULL, NULL, NULL, NULL); 198 break; 199 } 200 201 if (action == CURL_POLL_REMOVE) { 202 g_hash_table_remove(s->sockets, GINT_TO_POINTER(fd)); 203 } 204 205 return 0; 206 } 207 208 /* Called from curl_multi_do_locked, with s->mutex held. */ 209 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 210 { 211 BDRVCURLState *s = opaque; 212 size_t realsize = size * nmemb; 213 const char *header = (char *)ptr; 214 const char *end = header + realsize; 215 const char *accept_ranges = "accept-ranges:"; 216 const char *bytes = "bytes"; 217 218 if (realsize >= strlen(accept_ranges) 219 && g_ascii_strncasecmp(header, accept_ranges, 220 strlen(accept_ranges)) == 0) { 221 222 char *p = strchr(header, ':') + 1; 223 224 /* Skip whitespace between the header name and value. */ 225 while (p < end && *p && g_ascii_isspace(*p)) { 226 p++; 227 } 228 229 if (end - p >= strlen(bytes) 230 && strncmp(p, bytes, strlen(bytes)) == 0) { 231 232 /* Check that there is nothing but whitespace after the value. */ 233 p += strlen(bytes); 234 while (p < end && *p && g_ascii_isspace(*p)) { 235 p++; 236 } 237 238 if (p == end || !*p) { 239 s->accept_range = true; 240 } 241 } 242 } 243 244 return realsize; 245 } 246 247 /* Called from curl_multi_do_locked, with s->mutex held. */ 248 static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque) 249 { 250 CURLState *s = ((CURLState*)opaque); 251 size_t realsize = size * nmemb; 252 253 trace_curl_read_cb(realsize); 254 255 if (!s || !s->orig_buf) { 256 goto read_end; 257 } 258 259 if (s->buf_off >= s->buf_len) { 260 /* buffer full, read nothing */ 261 goto read_end; 262 } 263 realsize = MIN(realsize, s->buf_len - s->buf_off); 264 memcpy(s->orig_buf + s->buf_off, ptr, realsize); 265 s->buf_off += realsize; 266 267 read_end: 268 /* curl will error out if we do not return this value */ 269 return size * nmemb; 270 } 271 272 /* Called with s->mutex held. */ 273 static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len, 274 CURLAIOCB *acb) 275 { 276 int i; 277 uint64_t end = start + len; 278 uint64_t clamped_end = MIN(end, s->len); 279 uint64_t clamped_len = clamped_end - start; 280 281 for (i=0; i<CURL_NUM_STATES; i++) { 282 CURLState *state = &s->states[i]; 283 uint64_t buf_end = (state->buf_start + state->buf_off); 284 uint64_t buf_fend = (state->buf_start + state->buf_len); 285 286 if (!state->orig_buf) 287 continue; 288 if (!state->buf_off) 289 continue; 290 291 // Does the existing buffer cover our section? 292 if ((start >= state->buf_start) && 293 (start <= buf_end) && 294 (clamped_end >= state->buf_start) && 295 (clamped_end <= buf_end)) 296 { 297 char *buf = state->orig_buf + (start - state->buf_start); 298 299 qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len); 300 if (clamped_len < len) { 301 qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len); 302 } 303 acb->ret = 0; 304 return true; 305 } 306 307 // Wait for unfinished chunks 308 if (state->in_use && 309 (start >= state->buf_start) && 310 (start <= buf_fend) && 311 (clamped_end >= state->buf_start) && 312 (clamped_end <= buf_fend)) 313 { 314 int j; 315 316 acb->start = start - state->buf_start; 317 acb->end = acb->start + clamped_len; 318 319 for (j=0; j<CURL_NUM_ACB; j++) { 320 if (!state->acb[j]) { 321 state->acb[j] = acb; 322 return true; 323 } 324 } 325 } 326 } 327 328 return false; 329 } 330 331 /* Called with s->mutex held. */ 332 static void curl_multi_check_completion(BDRVCURLState *s) 333 { 334 int msgs_in_queue; 335 336 /* Try to find done transfers, so we can free the easy 337 * handle again. */ 338 for (;;) { 339 CURLMsg *msg; 340 msg = curl_multi_info_read(s->multi, &msgs_in_queue); 341 342 /* Quit when there are no more completions */ 343 if (!msg) 344 break; 345 346 if (msg->msg == CURLMSG_DONE) { 347 int i; 348 CURLState *state = NULL; 349 bool error = msg->data.result != CURLE_OK; 350 351 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, 352 (char **)&state); 353 354 if (error) { 355 static int errcount = 100; 356 357 /* Don't lose the original error message from curl, since 358 * it contains extra data. 359 */ 360 if (errcount > 0) { 361 error_report("curl: %s", state->errmsg); 362 if (--errcount == 0) { 363 error_report("curl: further errors suppressed"); 364 } 365 } 366 } 367 368 for (i = 0; i < CURL_NUM_ACB; i++) { 369 CURLAIOCB *acb = state->acb[i]; 370 371 if (acb == NULL) { 372 continue; 373 } 374 375 if (!error) { 376 /* Assert that we have read all data */ 377 assert(state->buf_off >= acb->end); 378 379 qemu_iovec_from_buf(acb->qiov, 0, 380 state->orig_buf + acb->start, 381 acb->end - acb->start); 382 383 if (acb->end - acb->start < acb->bytes) { 384 size_t offset = acb->end - acb->start; 385 qemu_iovec_memset(acb->qiov, offset, 0, 386 acb->bytes - offset); 387 } 388 } 389 390 acb->ret = error ? -EIO : 0; 391 state->acb[i] = NULL; 392 qemu_mutex_unlock(&s->mutex); 393 aio_co_wake(acb->co); 394 qemu_mutex_lock(&s->mutex); 395 } 396 397 curl_clean_state(state); 398 break; 399 } 400 } 401 } 402 403 /* Called with s->mutex held. */ 404 static void curl_multi_do_locked(CURLSocket *socket) 405 { 406 BDRVCURLState *s = socket->s; 407 int running; 408 int r; 409 410 if (!s->multi) { 411 return; 412 } 413 414 do { 415 r = curl_multi_socket_action(s->multi, socket->fd, 0, &running); 416 } while (r == CURLM_CALL_MULTI_PERFORM); 417 } 418 419 static void curl_multi_do(void *arg) 420 { 421 CURLSocket *socket = arg; 422 BDRVCURLState *s = socket->s; 423 424 qemu_mutex_lock(&s->mutex); 425 curl_multi_do_locked(socket); 426 curl_multi_check_completion(s); 427 qemu_mutex_unlock(&s->mutex); 428 } 429 430 static void curl_multi_timeout_do(void *arg) 431 { 432 BDRVCURLState *s = (BDRVCURLState *)arg; 433 int running; 434 435 if (!s->multi) { 436 return; 437 } 438 439 qemu_mutex_lock(&s->mutex); 440 curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running); 441 442 curl_multi_check_completion(s); 443 qemu_mutex_unlock(&s->mutex); 444 } 445 446 /* Called with s->mutex held. */ 447 static CURLState *curl_find_state(BDRVCURLState *s) 448 { 449 CURLState *state = NULL; 450 int i; 451 452 for (i = 0; i < CURL_NUM_STATES; i++) { 453 if (!s->states[i].in_use) { 454 state = &s->states[i]; 455 state->in_use = 1; 456 break; 457 } 458 } 459 return state; 460 } 461 462 static int curl_init_state(BDRVCURLState *s, CURLState *state) 463 { 464 if (!state->curl) { 465 state->curl = curl_easy_init(); 466 if (!state->curl) { 467 return -EIO; 468 } 469 if (curl_easy_setopt(state->curl, CURLOPT_URL, s->url) || 470 curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER, 471 (long) s->sslverify) || 472 curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYHOST, 473 s->sslverify ? 2L : 0L)) { 474 goto err; 475 } 476 if (s->cookie) { 477 if (curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie)) { 478 goto err; 479 } 480 } 481 if (curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout) || 482 curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, 483 (void *)curl_read_cb) || 484 curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state) || 485 curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state) || 486 curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1) || 487 curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1) || 488 curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1) || 489 curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg) || 490 curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1)) { 491 goto err; 492 } 493 if (s->username) { 494 if (curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username)) { 495 goto err; 496 } 497 } 498 if (s->password) { 499 if (curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password)) { 500 goto err; 501 } 502 } 503 if (s->proxyusername) { 504 if (curl_easy_setopt(state->curl, 505 CURLOPT_PROXYUSERNAME, s->proxyusername)) { 506 goto err; 507 } 508 } 509 if (s->proxypassword) { 510 if (curl_easy_setopt(state->curl, 511 CURLOPT_PROXYPASSWORD, s->proxypassword)) { 512 goto err; 513 } 514 } 515 516 /* Restrict supported protocols to avoid security issues in the more 517 * obscure protocols. For example, do not allow POP3/SMTP/IMAP see 518 * CVE-2013-0249. 519 * 520 * Restricting protocols is only supported from 7.19.4 upwards. Note: 521 * version 7.85.0 deprecates CURLOPT_*PROTOCOLS in favour of a string 522 * based CURLOPT_*PROTOCOLS_STR API. 523 */ 524 #if LIBCURL_VERSION_NUM >= 0x075500 525 if (curl_easy_setopt(state->curl, 526 CURLOPT_PROTOCOLS_STR, PROTOCOLS) || 527 curl_easy_setopt(state->curl, 528 CURLOPT_REDIR_PROTOCOLS_STR, PROTOCOLS)) { 529 goto err; 530 } 531 #elif LIBCURL_VERSION_NUM >= 0x071304 532 if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) || 533 curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) { 534 goto err; 535 } 536 #endif 537 538 #ifdef DEBUG_VERBOSE 539 if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) { 540 goto err; 541 } 542 #endif 543 } 544 545 state->s = s; 546 547 return 0; 548 549 err: 550 curl_easy_cleanup(state->curl); 551 state->curl = NULL; 552 return -EIO; 553 } 554 555 /* Called with s->mutex held. */ 556 static void curl_clean_state(CURLState *s) 557 { 558 int j; 559 for (j = 0; j < CURL_NUM_ACB; j++) { 560 assert(!s->acb[j]); 561 } 562 563 if (s->s->multi) 564 curl_multi_remove_handle(s->s->multi, s->curl); 565 566 s->in_use = 0; 567 568 qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex); 569 } 570 571 static void curl_parse_filename(const char *filename, QDict *options, 572 Error **errp) 573 { 574 qdict_put_str(options, CURL_BLOCK_OPT_URL, filename); 575 } 576 577 static void curl_detach_aio_context(BlockDriverState *bs) 578 { 579 BDRVCURLState *s = bs->opaque; 580 int i; 581 582 WITH_QEMU_LOCK_GUARD(&s->mutex) { 583 curl_drop_all_sockets(s->sockets); 584 for (i = 0; i < CURL_NUM_STATES; i++) { 585 if (s->states[i].in_use) { 586 curl_clean_state(&s->states[i]); 587 } 588 if (s->states[i].curl) { 589 curl_easy_cleanup(s->states[i].curl); 590 s->states[i].curl = NULL; 591 } 592 g_free(s->states[i].orig_buf); 593 s->states[i].orig_buf = NULL; 594 } 595 if (s->multi) { 596 curl_multi_cleanup(s->multi); 597 s->multi = NULL; 598 } 599 } 600 601 timer_del(&s->timer); 602 } 603 604 static void curl_attach_aio_context(BlockDriverState *bs, 605 AioContext *new_context) 606 { 607 BDRVCURLState *s = bs->opaque; 608 609 aio_timer_init(new_context, &s->timer, 610 QEMU_CLOCK_REALTIME, SCALE_NS, 611 curl_multi_timeout_do, s); 612 613 assert(!s->multi); 614 s->multi = curl_multi_init(); 615 s->aio_context = new_context; 616 curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); 617 curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s); 618 curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb); 619 } 620 621 static QemuOptsList runtime_opts = { 622 .name = "curl", 623 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 624 .desc = { 625 { 626 .name = CURL_BLOCK_OPT_URL, 627 .type = QEMU_OPT_STRING, 628 .help = "URL to open", 629 }, 630 { 631 .name = CURL_BLOCK_OPT_READAHEAD, 632 .type = QEMU_OPT_SIZE, 633 .help = "Readahead size", 634 }, 635 { 636 .name = CURL_BLOCK_OPT_SSLVERIFY, 637 .type = QEMU_OPT_BOOL, 638 .help = "Verify SSL certificate" 639 }, 640 { 641 .name = CURL_BLOCK_OPT_TIMEOUT, 642 .type = QEMU_OPT_NUMBER, 643 .help = "Curl timeout" 644 }, 645 { 646 .name = CURL_BLOCK_OPT_COOKIE, 647 .type = QEMU_OPT_STRING, 648 .help = "Pass the cookie or list of cookies with each request" 649 }, 650 { 651 .name = CURL_BLOCK_OPT_COOKIE_SECRET, 652 .type = QEMU_OPT_STRING, 653 .help = "ID of secret used as cookie passed with each request" 654 }, 655 { 656 .name = CURL_BLOCK_OPT_USERNAME, 657 .type = QEMU_OPT_STRING, 658 .help = "Username for HTTP auth" 659 }, 660 { 661 .name = CURL_BLOCK_OPT_PASSWORD_SECRET, 662 .type = QEMU_OPT_STRING, 663 .help = "ID of secret used as password for HTTP auth", 664 }, 665 { 666 .name = CURL_BLOCK_OPT_PROXY_USERNAME, 667 .type = QEMU_OPT_STRING, 668 .help = "Username for HTTP proxy auth" 669 }, 670 { 671 .name = CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET, 672 .type = QEMU_OPT_STRING, 673 .help = "ID of secret used as password for HTTP proxy auth", 674 }, 675 { /* end of list */ } 676 }, 677 }; 678 679 680 static int curl_open(BlockDriverState *bs, QDict *options, int flags, 681 Error **errp) 682 { 683 BDRVCURLState *s = bs->opaque; 684 CURLState *state = NULL; 685 QemuOpts *opts; 686 const char *file; 687 const char *cookie; 688 const char *cookie_secret; 689 /* CURL >= 7.55.0 uses curl_off_t for content length instead of a double */ 690 #if LIBCURL_VERSION_NUM >= 0x073700 691 curl_off_t cl; 692 #else 693 double cl; 694 #endif 695 const char *secretid; 696 const char *protocol_delimiter; 697 int ret; 698 699 bdrv_graph_rdlock_main_loop(); 700 ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes", 701 errp); 702 bdrv_graph_rdunlock_main_loop(); 703 if (ret < 0) { 704 return ret; 705 } 706 707 if (!libcurl_initialized) { 708 ret = curl_global_init(CURL_GLOBAL_ALL); 709 if (ret) { 710 error_setg(errp, "libcurl initialization failed with %d", ret); 711 return -EIO; 712 } 713 libcurl_initialized = true; 714 } 715 716 qemu_mutex_init(&s->mutex); 717 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 718 if (!qemu_opts_absorb_qdict(opts, options, errp)) { 719 goto out_noclean; 720 } 721 722 s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, 723 CURL_BLOCK_OPT_READAHEAD_DEFAULT); 724 if ((s->readahead_size & 0x1ff) != 0) { 725 error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", 726 s->readahead_size); 727 goto out_noclean; 728 } 729 730 s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT, 731 CURL_BLOCK_OPT_TIMEOUT_DEFAULT); 732 if (s->timeout > CURL_TIMEOUT_MAX) { 733 error_setg(errp, "timeout parameter is too large or negative"); 734 goto out_noclean; 735 } 736 737 s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, 738 CURL_BLOCK_OPT_SSLVERIFY_DEFAULT); 739 740 cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE); 741 cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET); 742 743 if (cookie && cookie_secret) { 744 error_setg(errp, 745 "curl driver cannot handle both cookie and cookie secret"); 746 goto out_noclean; 747 } 748 749 if (cookie_secret) { 750 s->cookie = qcrypto_secret_lookup_as_utf8(cookie_secret, errp); 751 if (!s->cookie) { 752 goto out_noclean; 753 } 754 } else { 755 s->cookie = g_strdup(cookie); 756 } 757 758 file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL); 759 if (file == NULL) { 760 error_setg(errp, "curl block driver requires an 'url' option"); 761 goto out_noclean; 762 } 763 764 if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) || 765 !strstart(protocol_delimiter, "://", NULL)) 766 { 767 error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not " 768 "start with '%s://')", bs->drv->protocol_name, file, 769 bs->drv->protocol_name); 770 goto out_noclean; 771 } 772 773 s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME)); 774 secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET); 775 776 if (secretid) { 777 s->password = qcrypto_secret_lookup_as_utf8(secretid, errp); 778 if (!s->password) { 779 goto out_noclean; 780 } 781 } 782 783 s->proxyusername = g_strdup( 784 qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_USERNAME)); 785 secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET); 786 if (secretid) { 787 s->proxypassword = qcrypto_secret_lookup_as_utf8(secretid, errp); 788 if (!s->proxypassword) { 789 goto out_noclean; 790 } 791 } 792 793 trace_curl_open(file); 794 qemu_co_queue_init(&s->free_state_waitq); 795 s->aio_context = bdrv_get_aio_context(bs); 796 s->url = g_strdup(file); 797 s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free); 798 qemu_mutex_lock(&s->mutex); 799 state = curl_find_state(s); 800 qemu_mutex_unlock(&s->mutex); 801 if (!state) { 802 goto out_noclean; 803 } 804 805 // Get file size 806 807 if (curl_init_state(s, state) < 0) { 808 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 809 "curl library initialization failed."); 810 goto out; 811 } 812 813 s->accept_range = false; 814 if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) || 815 curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) || 816 curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) { 817 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 818 "curl library initialization failed."); 819 goto out; 820 } 821 if (curl_easy_perform(state->curl)) 822 goto out; 823 /* CURL 7.55.0 deprecates CURLINFO_CONTENT_LENGTH_DOWNLOAD in favour of 824 * the *_T version which returns a more sensible type for content length. 825 */ 826 #if LIBCURL_VERSION_NUM >= 0x073700 827 if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl)) { 828 goto out; 829 } 830 #else 831 if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl)) { 832 goto out; 833 } 834 #endif 835 /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not 836 * know or the size is zero. From 7.19.4 CURL returns -1 if size is not 837 * known and zero if it is really zero-length file. */ 838 #if LIBCURL_VERSION_NUM >= 0x071304 839 if (cl < 0) { 840 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 841 "Server didn't report file size."); 842 goto out; 843 } 844 #else 845 if (cl <= 0) { 846 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 847 "Unknown file size or zero-length file."); 848 goto out; 849 } 850 #endif 851 852 s->len = cl; 853 854 if ((!strncasecmp(s->url, "http://", strlen("http://")) 855 || !strncasecmp(s->url, "https://", strlen("https://"))) 856 && !s->accept_range) { 857 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 858 "Server does not support 'range' (byte ranges)."); 859 goto out; 860 } 861 trace_curl_open_size(s->len); 862 863 qemu_mutex_lock(&s->mutex); 864 curl_clean_state(state); 865 qemu_mutex_unlock(&s->mutex); 866 curl_easy_cleanup(state->curl); 867 state->curl = NULL; 868 869 curl_attach_aio_context(bs, bdrv_get_aio_context(bs)); 870 871 qemu_opts_del(opts); 872 return 0; 873 874 out: 875 error_setg(errp, "CURL: Error opening file: %s", state->errmsg); 876 curl_easy_cleanup(state->curl); 877 state->curl = NULL; 878 out_noclean: 879 qemu_mutex_destroy(&s->mutex); 880 g_free(s->cookie); 881 g_free(s->url); 882 g_free(s->username); 883 g_free(s->proxyusername); 884 g_free(s->proxypassword); 885 if (s->sockets) { 886 curl_drop_all_sockets(s->sockets); 887 g_hash_table_destroy(s->sockets); 888 } 889 qemu_opts_del(opts); 890 return -EINVAL; 891 } 892 893 static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) 894 { 895 CURLState *state; 896 int running; 897 898 BDRVCURLState *s = bs->opaque; 899 900 uint64_t start = acb->offset; 901 uint64_t end; 902 903 qemu_mutex_lock(&s->mutex); 904 905 // In case we have the requested data already (e.g. read-ahead), 906 // we can just call the callback and be done. 907 if (curl_find_buf(s, start, acb->bytes, acb)) { 908 goto out; 909 } 910 911 // No cache found, so let's start a new request 912 for (;;) { 913 state = curl_find_state(s); 914 if (state) { 915 break; 916 } 917 qemu_co_queue_wait(&s->free_state_waitq, &s->mutex); 918 } 919 920 if (curl_init_state(s, state) < 0) { 921 curl_clean_state(state); 922 acb->ret = -EIO; 923 goto out; 924 } 925 926 acb->start = 0; 927 acb->end = MIN(acb->bytes, s->len - start); 928 929 state->buf_off = 0; 930 g_free(state->orig_buf); 931 state->buf_start = start; 932 state->buf_len = MIN(acb->end + s->readahead_size, s->len - start); 933 end = start + state->buf_len - 1; 934 state->orig_buf = g_try_malloc(state->buf_len); 935 if (state->buf_len && state->orig_buf == NULL) { 936 curl_clean_state(state); 937 acb->ret = -ENOMEM; 938 goto out; 939 } 940 state->acb[0] = acb; 941 942 snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end); 943 trace_curl_setup_preadv(acb->bytes, start, state->range); 944 if (curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range) || 945 curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) { 946 state->acb[0] = NULL; 947 acb->ret = -EIO; 948 949 curl_clean_state(state); 950 goto out; 951 } 952 953 /* Tell curl it needs to kick things off */ 954 curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running); 955 956 out: 957 qemu_mutex_unlock(&s->mutex); 958 } 959 960 static int coroutine_fn curl_co_preadv(BlockDriverState *bs, 961 int64_t offset, int64_t bytes, QEMUIOVector *qiov, 962 BdrvRequestFlags flags) 963 { 964 CURLAIOCB acb = { 965 .co = qemu_coroutine_self(), 966 .ret = -EINPROGRESS, 967 .qiov = qiov, 968 .offset = offset, 969 .bytes = bytes 970 }; 971 972 curl_setup_preadv(bs, &acb); 973 while (acb.ret == -EINPROGRESS) { 974 qemu_coroutine_yield(); 975 } 976 return acb.ret; 977 } 978 979 static void curl_close(BlockDriverState *bs) 980 { 981 BDRVCURLState *s = bs->opaque; 982 983 trace_curl_close(); 984 curl_detach_aio_context(bs); 985 qemu_mutex_destroy(&s->mutex); 986 987 g_hash_table_destroy(s->sockets); 988 g_free(s->cookie); 989 g_free(s->url); 990 g_free(s->username); 991 g_free(s->proxyusername); 992 g_free(s->proxypassword); 993 } 994 995 static int64_t coroutine_fn curl_co_getlength(BlockDriverState *bs) 996 { 997 BDRVCURLState *s = bs->opaque; 998 return s->len; 999 } 1000 1001 static void curl_refresh_filename(BlockDriverState *bs) 1002 { 1003 BDRVCURLState *s = bs->opaque; 1004 1005 /* "readahead" and "timeout" do not change the guest-visible data, 1006 * so ignore them */ 1007 if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT || 1008 s->cookie || s->username || s->password || s->proxyusername || 1009 s->proxypassword) 1010 { 1011 return; 1012 } 1013 1014 pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url); 1015 } 1016 1017 1018 static const char *const curl_strong_runtime_opts[] = { 1019 CURL_BLOCK_OPT_URL, 1020 CURL_BLOCK_OPT_SSLVERIFY, 1021 CURL_BLOCK_OPT_COOKIE, 1022 CURL_BLOCK_OPT_COOKIE_SECRET, 1023 CURL_BLOCK_OPT_USERNAME, 1024 CURL_BLOCK_OPT_PASSWORD_SECRET, 1025 CURL_BLOCK_OPT_PROXY_USERNAME, 1026 CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET, 1027 1028 NULL 1029 }; 1030 1031 static BlockDriver bdrv_http = { 1032 .format_name = "http", 1033 .protocol_name = "http", 1034 1035 .instance_size = sizeof(BDRVCURLState), 1036 .bdrv_parse_filename = curl_parse_filename, 1037 .bdrv_file_open = curl_open, 1038 .bdrv_close = curl_close, 1039 .bdrv_co_getlength = curl_co_getlength, 1040 1041 .bdrv_co_preadv = curl_co_preadv, 1042 1043 .bdrv_detach_aio_context = curl_detach_aio_context, 1044 .bdrv_attach_aio_context = curl_attach_aio_context, 1045 1046 .bdrv_refresh_filename = curl_refresh_filename, 1047 .strong_runtime_opts = curl_strong_runtime_opts, 1048 }; 1049 1050 static BlockDriver bdrv_https = { 1051 .format_name = "https", 1052 .protocol_name = "https", 1053 1054 .instance_size = sizeof(BDRVCURLState), 1055 .bdrv_parse_filename = curl_parse_filename, 1056 .bdrv_file_open = curl_open, 1057 .bdrv_close = curl_close, 1058 .bdrv_co_getlength = curl_co_getlength, 1059 1060 .bdrv_co_preadv = curl_co_preadv, 1061 1062 .bdrv_detach_aio_context = curl_detach_aio_context, 1063 .bdrv_attach_aio_context = curl_attach_aio_context, 1064 1065 .bdrv_refresh_filename = curl_refresh_filename, 1066 .strong_runtime_opts = curl_strong_runtime_opts, 1067 }; 1068 1069 static BlockDriver bdrv_ftp = { 1070 .format_name = "ftp", 1071 .protocol_name = "ftp", 1072 1073 .instance_size = sizeof(BDRVCURLState), 1074 .bdrv_parse_filename = curl_parse_filename, 1075 .bdrv_file_open = curl_open, 1076 .bdrv_close = curl_close, 1077 .bdrv_co_getlength = curl_co_getlength, 1078 1079 .bdrv_co_preadv = curl_co_preadv, 1080 1081 .bdrv_detach_aio_context = curl_detach_aio_context, 1082 .bdrv_attach_aio_context = curl_attach_aio_context, 1083 1084 .bdrv_refresh_filename = curl_refresh_filename, 1085 .strong_runtime_opts = curl_strong_runtime_opts, 1086 }; 1087 1088 static BlockDriver bdrv_ftps = { 1089 .format_name = "ftps", 1090 .protocol_name = "ftps", 1091 1092 .instance_size = sizeof(BDRVCURLState), 1093 .bdrv_parse_filename = curl_parse_filename, 1094 .bdrv_file_open = curl_open, 1095 .bdrv_close = curl_close, 1096 .bdrv_co_getlength = curl_co_getlength, 1097 1098 .bdrv_co_preadv = curl_co_preadv, 1099 1100 .bdrv_detach_aio_context = curl_detach_aio_context, 1101 .bdrv_attach_aio_context = curl_attach_aio_context, 1102 1103 .bdrv_refresh_filename = curl_refresh_filename, 1104 .strong_runtime_opts = curl_strong_runtime_opts, 1105 }; 1106 1107 static void curl_block_init(void) 1108 { 1109 bdrv_register(&bdrv_http); 1110 bdrv_register(&bdrv_https); 1111 bdrv_register(&bdrv_ftp); 1112 bdrv_register(&bdrv_ftps); 1113 } 1114 1115 block_init(curl_block_init); 1116