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