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