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 ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes", 700 errp); 701 if (ret < 0) { 702 return ret; 703 } 704 705 if (!libcurl_initialized) { 706 ret = curl_global_init(CURL_GLOBAL_ALL); 707 if (ret) { 708 error_setg(errp, "libcurl initialization failed with %d", ret); 709 return -EIO; 710 } 711 libcurl_initialized = true; 712 } 713 714 qemu_mutex_init(&s->mutex); 715 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 716 if (!qemu_opts_absorb_qdict(opts, options, errp)) { 717 goto out_noclean; 718 } 719 720 s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, 721 CURL_BLOCK_OPT_READAHEAD_DEFAULT); 722 if ((s->readahead_size & 0x1ff) != 0) { 723 error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", 724 s->readahead_size); 725 goto out_noclean; 726 } 727 728 s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT, 729 CURL_BLOCK_OPT_TIMEOUT_DEFAULT); 730 if (s->timeout > CURL_TIMEOUT_MAX) { 731 error_setg(errp, "timeout parameter is too large or negative"); 732 goto out_noclean; 733 } 734 735 s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, 736 CURL_BLOCK_OPT_SSLVERIFY_DEFAULT); 737 738 cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE); 739 cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET); 740 741 if (cookie && cookie_secret) { 742 error_setg(errp, 743 "curl driver cannot handle both cookie and cookie secret"); 744 goto out_noclean; 745 } 746 747 if (cookie_secret) { 748 s->cookie = qcrypto_secret_lookup_as_utf8(cookie_secret, errp); 749 if (!s->cookie) { 750 goto out_noclean; 751 } 752 } else { 753 s->cookie = g_strdup(cookie); 754 } 755 756 file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL); 757 if (file == NULL) { 758 error_setg(errp, "curl block driver requires an 'url' option"); 759 goto out_noclean; 760 } 761 762 if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) || 763 !strstart(protocol_delimiter, "://", NULL)) 764 { 765 error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not " 766 "start with '%s://')", bs->drv->protocol_name, file, 767 bs->drv->protocol_name); 768 goto out_noclean; 769 } 770 771 s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME)); 772 secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET); 773 774 if (secretid) { 775 s->password = qcrypto_secret_lookup_as_utf8(secretid, errp); 776 if (!s->password) { 777 goto out_noclean; 778 } 779 } 780 781 s->proxyusername = g_strdup( 782 qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_USERNAME)); 783 secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET); 784 if (secretid) { 785 s->proxypassword = qcrypto_secret_lookup_as_utf8(secretid, errp); 786 if (!s->proxypassword) { 787 goto out_noclean; 788 } 789 } 790 791 trace_curl_open(file); 792 qemu_co_queue_init(&s->free_state_waitq); 793 s->aio_context = bdrv_get_aio_context(bs); 794 s->url = g_strdup(file); 795 s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free); 796 qemu_mutex_lock(&s->mutex); 797 state = curl_find_state(s); 798 qemu_mutex_unlock(&s->mutex); 799 if (!state) { 800 goto out_noclean; 801 } 802 803 // Get file size 804 805 if (curl_init_state(s, state) < 0) { 806 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 807 "curl library initialization failed."); 808 goto out; 809 } 810 811 s->accept_range = false; 812 if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) || 813 curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) || 814 curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) { 815 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 816 "curl library initialization failed."); 817 goto out; 818 } 819 if (curl_easy_perform(state->curl)) 820 goto out; 821 /* CURL 7.55.0 deprecates CURLINFO_CONTENT_LENGTH_DOWNLOAD in favour of 822 * the *_T version which returns a more sensible type for content length. 823 */ 824 #if LIBCURL_VERSION_NUM >= 0x073700 825 if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl)) { 826 goto out; 827 } 828 #else 829 if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl)) { 830 goto out; 831 } 832 #endif 833 /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not 834 * know or the size is zero. From 7.19.4 CURL returns -1 if size is not 835 * known and zero if it is really zero-length file. */ 836 #if LIBCURL_VERSION_NUM >= 0x071304 837 if (cl < 0) { 838 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 839 "Server didn't report file size."); 840 goto out; 841 } 842 #else 843 if (cl <= 0) { 844 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 845 "Unknown file size or zero-length file."); 846 goto out; 847 } 848 #endif 849 850 s->len = cl; 851 852 if ((!strncasecmp(s->url, "http://", strlen("http://")) 853 || !strncasecmp(s->url, "https://", strlen("https://"))) 854 && !s->accept_range) { 855 pstrcpy(state->errmsg, CURL_ERROR_SIZE, 856 "Server does not support 'range' (byte ranges)."); 857 goto out; 858 } 859 trace_curl_open_size(s->len); 860 861 qemu_mutex_lock(&s->mutex); 862 curl_clean_state(state); 863 qemu_mutex_unlock(&s->mutex); 864 curl_easy_cleanup(state->curl); 865 state->curl = NULL; 866 867 curl_attach_aio_context(bs, bdrv_get_aio_context(bs)); 868 869 qemu_opts_del(opts); 870 return 0; 871 872 out: 873 error_setg(errp, "CURL: Error opening file: %s", state->errmsg); 874 curl_easy_cleanup(state->curl); 875 state->curl = NULL; 876 out_noclean: 877 qemu_mutex_destroy(&s->mutex); 878 g_free(s->cookie); 879 g_free(s->url); 880 g_free(s->username); 881 g_free(s->proxyusername); 882 g_free(s->proxypassword); 883 if (s->sockets) { 884 curl_drop_all_sockets(s->sockets); 885 g_hash_table_destroy(s->sockets); 886 } 887 qemu_opts_del(opts); 888 return -EINVAL; 889 } 890 891 static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb) 892 { 893 CURLState *state; 894 int running; 895 896 BDRVCURLState *s = bs->opaque; 897 898 uint64_t start = acb->offset; 899 uint64_t end; 900 901 qemu_mutex_lock(&s->mutex); 902 903 // In case we have the requested data already (e.g. read-ahead), 904 // we can just call the callback and be done. 905 if (curl_find_buf(s, start, acb->bytes, acb)) { 906 goto out; 907 } 908 909 // No cache found, so let's start a new request 910 for (;;) { 911 state = curl_find_state(s); 912 if (state) { 913 break; 914 } 915 qemu_co_queue_wait(&s->free_state_waitq, &s->mutex); 916 } 917 918 if (curl_init_state(s, state) < 0) { 919 curl_clean_state(state); 920 acb->ret = -EIO; 921 goto out; 922 } 923 924 acb->start = 0; 925 acb->end = MIN(acb->bytes, s->len - start); 926 927 state->buf_off = 0; 928 g_free(state->orig_buf); 929 state->buf_start = start; 930 state->buf_len = MIN(acb->end + s->readahead_size, s->len - start); 931 end = start + state->buf_len - 1; 932 state->orig_buf = g_try_malloc(state->buf_len); 933 if (state->buf_len && state->orig_buf == NULL) { 934 curl_clean_state(state); 935 acb->ret = -ENOMEM; 936 goto out; 937 } 938 state->acb[0] = acb; 939 940 snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end); 941 trace_curl_setup_preadv(acb->bytes, start, state->range); 942 if (curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range) || 943 curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) { 944 state->acb[0] = NULL; 945 acb->ret = -EIO; 946 947 curl_clean_state(state); 948 goto out; 949 } 950 951 /* Tell curl it needs to kick things off */ 952 curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running); 953 954 out: 955 qemu_mutex_unlock(&s->mutex); 956 } 957 958 static int coroutine_fn curl_co_preadv(BlockDriverState *bs, 959 int64_t offset, int64_t bytes, QEMUIOVector *qiov, 960 BdrvRequestFlags flags) 961 { 962 CURLAIOCB acb = { 963 .co = qemu_coroutine_self(), 964 .ret = -EINPROGRESS, 965 .qiov = qiov, 966 .offset = offset, 967 .bytes = bytes 968 }; 969 970 curl_setup_preadv(bs, &acb); 971 while (acb.ret == -EINPROGRESS) { 972 qemu_coroutine_yield(); 973 } 974 return acb.ret; 975 } 976 977 static void curl_close(BlockDriverState *bs) 978 { 979 BDRVCURLState *s = bs->opaque; 980 981 trace_curl_close(); 982 curl_detach_aio_context(bs); 983 qemu_mutex_destroy(&s->mutex); 984 985 g_hash_table_destroy(s->sockets); 986 g_free(s->cookie); 987 g_free(s->url); 988 g_free(s->username); 989 g_free(s->proxyusername); 990 g_free(s->proxypassword); 991 } 992 993 static int64_t coroutine_fn curl_co_getlength(BlockDriverState *bs) 994 { 995 BDRVCURLState *s = bs->opaque; 996 return s->len; 997 } 998 999 static void curl_refresh_filename(BlockDriverState *bs) 1000 { 1001 BDRVCURLState *s = bs->opaque; 1002 1003 /* "readahead" and "timeout" do not change the guest-visible data, 1004 * so ignore them */ 1005 if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT || 1006 s->cookie || s->username || s->password || s->proxyusername || 1007 s->proxypassword) 1008 { 1009 return; 1010 } 1011 1012 pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url); 1013 } 1014 1015 1016 static const char *const curl_strong_runtime_opts[] = { 1017 CURL_BLOCK_OPT_URL, 1018 CURL_BLOCK_OPT_SSLVERIFY, 1019 CURL_BLOCK_OPT_COOKIE, 1020 CURL_BLOCK_OPT_COOKIE_SECRET, 1021 CURL_BLOCK_OPT_USERNAME, 1022 CURL_BLOCK_OPT_PASSWORD_SECRET, 1023 CURL_BLOCK_OPT_PROXY_USERNAME, 1024 CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET, 1025 1026 NULL 1027 }; 1028 1029 static BlockDriver bdrv_http = { 1030 .format_name = "http", 1031 .protocol_name = "http", 1032 1033 .instance_size = sizeof(BDRVCURLState), 1034 .bdrv_parse_filename = curl_parse_filename, 1035 .bdrv_file_open = curl_open, 1036 .bdrv_close = curl_close, 1037 .bdrv_co_getlength = curl_co_getlength, 1038 1039 .bdrv_co_preadv = curl_co_preadv, 1040 1041 .bdrv_detach_aio_context = curl_detach_aio_context, 1042 .bdrv_attach_aio_context = curl_attach_aio_context, 1043 1044 .bdrv_refresh_filename = curl_refresh_filename, 1045 .strong_runtime_opts = curl_strong_runtime_opts, 1046 }; 1047 1048 static BlockDriver bdrv_https = { 1049 .format_name = "https", 1050 .protocol_name = "https", 1051 1052 .instance_size = sizeof(BDRVCURLState), 1053 .bdrv_parse_filename = curl_parse_filename, 1054 .bdrv_file_open = curl_open, 1055 .bdrv_close = curl_close, 1056 .bdrv_co_getlength = curl_co_getlength, 1057 1058 .bdrv_co_preadv = curl_co_preadv, 1059 1060 .bdrv_detach_aio_context = curl_detach_aio_context, 1061 .bdrv_attach_aio_context = curl_attach_aio_context, 1062 1063 .bdrv_refresh_filename = curl_refresh_filename, 1064 .strong_runtime_opts = curl_strong_runtime_opts, 1065 }; 1066 1067 static BlockDriver bdrv_ftp = { 1068 .format_name = "ftp", 1069 .protocol_name = "ftp", 1070 1071 .instance_size = sizeof(BDRVCURLState), 1072 .bdrv_parse_filename = curl_parse_filename, 1073 .bdrv_file_open = curl_open, 1074 .bdrv_close = curl_close, 1075 .bdrv_co_getlength = curl_co_getlength, 1076 1077 .bdrv_co_preadv = curl_co_preadv, 1078 1079 .bdrv_detach_aio_context = curl_detach_aio_context, 1080 .bdrv_attach_aio_context = curl_attach_aio_context, 1081 1082 .bdrv_refresh_filename = curl_refresh_filename, 1083 .strong_runtime_opts = curl_strong_runtime_opts, 1084 }; 1085 1086 static BlockDriver bdrv_ftps = { 1087 .format_name = "ftps", 1088 .protocol_name = "ftps", 1089 1090 .instance_size = sizeof(BDRVCURLState), 1091 .bdrv_parse_filename = curl_parse_filename, 1092 .bdrv_file_open = curl_open, 1093 .bdrv_close = curl_close, 1094 .bdrv_co_getlength = curl_co_getlength, 1095 1096 .bdrv_co_preadv = curl_co_preadv, 1097 1098 .bdrv_detach_aio_context = curl_detach_aio_context, 1099 .bdrv_attach_aio_context = curl_attach_aio_context, 1100 1101 .bdrv_refresh_filename = curl_refresh_filename, 1102 .strong_runtime_opts = curl_strong_runtime_opts, 1103 }; 1104 1105 static void curl_block_init(void) 1106 { 1107 bdrv_register(&bdrv_http); 1108 bdrv_register(&bdrv_https); 1109 bdrv_register(&bdrv_ftp); 1110 bdrv_register(&bdrv_ftps); 1111 } 1112 1113 block_init(curl_block_init); 1114