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"
36
#include "qemu/cutils.h"
44
#if LIBCURL_VERSION_NUM >= 0x075500
45
#define PROTOCOLS "HTTP,HTTPS,FTP,FTPS"
47
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
48
CURLPROTO_FTP | CURLPROTO_FTPS)
51
#define CURL_NUM_STATES 8
53
#define CURL_TIMEOUT_MAX 10000
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"
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
73
static bool libcurl_initialized;
75
typedef struct CURLAIOCB {
87
typedef struct CURLSocket {
89
struct BDRVCURLState *s;
92
typedef struct CURLState
94
struct BDRVCURLState *s;
95
CURLAIOCB *acb[CURL_NUM_ACB];
102
char errmsg[CURL_ERROR_SIZE];
106
typedef struct BDRVCURLState {
110
CURLState states[CURL_NUM_STATES];
113
size_t readahead_size;
118
AioContext *aio_context;
120
CoQueue free_state_waitq;
127
static void curl_clean_state(CURLState *s);
128
static void curl_multi_do(void *arg);
130
static gboolean curl_drop_socket(void *key, void *value, void *opaque)
132
CURLSocket *socket = value;
133
BDRVCURLState *s = socket->s;
135
aio_set_fd_handler(s->aio_context, socket->fd,
136
NULL, NULL, NULL, NULL, NULL);
140
static void curl_drop_all_sockets(GHashTable *sockets)
142
g_hash_table_foreach_remove(sockets, curl_drop_socket, NULL);
146
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
148
BDRVCURLState *s = opaque;
150
trace_curl_timer_cb(timeout_ms);
151
if (timeout_ms == -1) {
152
timer_del(&s->timer);
154
int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
156
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
162
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
163
void *userp, void *sp)
166
CURLState *state = NULL;
169
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
172
socket = g_hash_table_lookup(s->sockets, GINT_TO_POINTER(fd));
174
socket = g_new0(CURLSocket, 1);
177
g_hash_table_insert(s->sockets, GINT_TO_POINTER(fd), socket);
180
trace_curl_sock_cb(action, (int)fd);
183
aio_set_fd_handler(s->aio_context, fd,
184
curl_multi_do, NULL, NULL, NULL, socket);
187
aio_set_fd_handler(s->aio_context, fd,
188
NULL, curl_multi_do, NULL, NULL, socket);
190
case CURL_POLL_INOUT:
191
aio_set_fd_handler(s->aio_context, fd,
192
curl_multi_do, curl_multi_do,
195
case CURL_POLL_REMOVE:
196
aio_set_fd_handler(s->aio_context, fd,
197
NULL, NULL, NULL, NULL, NULL);
201
if (action == CURL_POLL_REMOVE) {
202
g_hash_table_remove(s->sockets, GINT_TO_POINTER(fd));
209
static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
211
BDRVCURLState *s = opaque;
212
size_t realsize = size * nmemb;
214
const char *end = p + realsize;
215
const char *t = "accept-ranges : bytes ";
220
if (p < end && g_ascii_isspace(*p)) {
225
} else if (*t && p < end && *t == g_ascii_tolower(*p)) {
232
if (!*t && p == end) {
233
s->accept_range = true;
240
static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
242
CURLState *s = ((CURLState*)opaque);
243
size_t realsize = size * nmemb;
245
trace_curl_read_cb(realsize);
247
if (!s || !s->orig_buf) {
251
if (s->buf_off >= s->buf_len) {
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;
265
static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len,
269
uint64_t end = start + len;
270
uint64_t clamped_end = MIN(end, s->len);
271
uint64_t clamped_len = clamped_end - start;
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);
278
if (!state->orig_buf)
284
if ((start >= state->buf_start) &&
285
(start <= buf_end) &&
286
(clamped_end >= state->buf_start) &&
287
(clamped_end <= buf_end))
289
char *buf = state->orig_buf + (start - state->buf_start);
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);
301
(start >= state->buf_start) &&
302
(start <= buf_fend) &&
303
(clamped_end >= state->buf_start) &&
304
(clamped_end <= buf_fend))
308
acb->start = start - state->buf_start;
309
acb->end = acb->start + clamped_len;
311
for (j=0; j<CURL_NUM_ACB; j++) {
312
if (!state->acb[j]) {
324
static void curl_multi_check_completion(BDRVCURLState *s)
332
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
338
if (msg->msg == CURLMSG_DONE) {
340
CURLState *state = NULL;
341
bool error = msg->data.result != CURLE_OK;
343
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
347
static int errcount = 100;
353
error_report("curl: %s", state->errmsg);
354
if (--errcount == 0) {
355
error_report("curl: further errors suppressed");
360
for (i = 0; i < CURL_NUM_ACB; i++) {
361
CURLAIOCB *acb = state->acb[i];
369
assert(state->buf_off >= acb->end);
371
qemu_iovec_from_buf(acb->qiov, 0,
372
state->orig_buf + acb->start,
373
acb->end - acb->start);
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);
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);
389
curl_clean_state(state);
396
static void curl_multi_do_locked(CURLSocket *socket)
398
BDRVCURLState *s = socket->s;
407
r = curl_multi_socket_action(s->multi, socket->fd, 0, &running);
408
} while (r == CURLM_CALL_MULTI_PERFORM);
411
static void curl_multi_do(void *arg)
413
CURLSocket *socket = arg;
414
BDRVCURLState *s = socket->s;
416
qemu_mutex_lock(&s->mutex);
417
curl_multi_do_locked(socket);
418
curl_multi_check_completion(s);
419
qemu_mutex_unlock(&s->mutex);
422
static void curl_multi_timeout_do(void *arg)
424
BDRVCURLState *s = (BDRVCURLState *)arg;
431
qemu_mutex_lock(&s->mutex);
432
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
434
curl_multi_check_completion(s);
435
qemu_mutex_unlock(&s->mutex);
439
static CURLState *curl_find_state(BDRVCURLState *s)
441
CURLState *state = NULL;
444
for (i = 0; i < CURL_NUM_STATES; i++) {
445
if (!s->states[i].in_use) {
446
state = &s->states[i];
454
static int curl_init_state(BDRVCURLState *s, CURLState *state)
457
state->curl = curl_easy_init();
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)) {
469
if (curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie)) {
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)) {
486
if (curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username)) {
491
if (curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password)) {
495
if (s->proxyusername) {
496
if (curl_easy_setopt(state->curl,
497
CURLOPT_PROXYUSERNAME, s->proxyusername)) {
501
if (s->proxypassword) {
502
if (curl_easy_setopt(state->curl,
503
CURLOPT_PROXYPASSWORD, s->proxypassword)) {
516
#if LIBCURL_VERSION_NUM >= 0x075500
517
if (curl_easy_setopt(state->curl,
518
CURLOPT_PROTOCOLS_STR, PROTOCOLS) ||
519
curl_easy_setopt(state->curl,
520
CURLOPT_REDIR_PROTOCOLS_STR, PROTOCOLS)) {
523
#elif LIBCURL_VERSION_NUM >= 0x071304
524
if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) ||
525
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) {
531
if (curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1)) {
542
curl_easy_cleanup(state->curl);
548
static void curl_clean_state(CURLState *s)
551
for (j = 0; j < CURL_NUM_ACB; j++) {
556
curl_multi_remove_handle(s->s->multi, s->curl);
560
qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex);
563
static void curl_parse_filename(const char *filename, QDict *options,
566
qdict_put_str(options, CURL_BLOCK_OPT_URL, filename);
569
static void curl_detach_aio_context(BlockDriverState *bs)
571
BDRVCURLState *s = bs->opaque;
574
WITH_QEMU_LOCK_GUARD(&s->mutex) {
575
curl_drop_all_sockets(s->sockets);
576
for (i = 0; i < CURL_NUM_STATES; i++) {
577
if (s->states[i].in_use) {
578
curl_clean_state(&s->states[i]);
580
if (s->states[i].curl) {
581
curl_easy_cleanup(s->states[i].curl);
582
s->states[i].curl = NULL;
584
g_free(s->states[i].orig_buf);
585
s->states[i].orig_buf = NULL;
588
curl_multi_cleanup(s->multi);
593
timer_del(&s->timer);
596
static void curl_attach_aio_context(BlockDriverState *bs,
597
AioContext *new_context)
599
BDRVCURLState *s = bs->opaque;
601
aio_timer_init(new_context, &s->timer,
602
QEMU_CLOCK_REALTIME, SCALE_NS,
603
curl_multi_timeout_do, s);
606
s->multi = curl_multi_init();
607
s->aio_context = new_context;
608
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
609
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
610
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
613
static QemuOptsList runtime_opts = {
615
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
618
.name = CURL_BLOCK_OPT_URL,
619
.type = QEMU_OPT_STRING,
620
.help = "URL to open",
623
.name = CURL_BLOCK_OPT_READAHEAD,
624
.type = QEMU_OPT_SIZE,
625
.help = "Readahead size",
628
.name = CURL_BLOCK_OPT_SSLVERIFY,
629
.type = QEMU_OPT_BOOL,
630
.help = "Verify SSL certificate"
633
.name = CURL_BLOCK_OPT_TIMEOUT,
634
.type = QEMU_OPT_NUMBER,
635
.help = "Curl timeout"
638
.name = CURL_BLOCK_OPT_COOKIE,
639
.type = QEMU_OPT_STRING,
640
.help = "Pass the cookie or list of cookies with each request"
643
.name = CURL_BLOCK_OPT_COOKIE_SECRET,
644
.type = QEMU_OPT_STRING,
645
.help = "ID of secret used as cookie passed with each request"
648
.name = CURL_BLOCK_OPT_USERNAME,
649
.type = QEMU_OPT_STRING,
650
.help = "Username for HTTP auth"
653
.name = CURL_BLOCK_OPT_PASSWORD_SECRET,
654
.type = QEMU_OPT_STRING,
655
.help = "ID of secret used as password for HTTP auth",
658
.name = CURL_BLOCK_OPT_PROXY_USERNAME,
659
.type = QEMU_OPT_STRING,
660
.help = "Username for HTTP proxy auth"
663
.name = CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
664
.type = QEMU_OPT_STRING,
665
.help = "ID of secret used as password for HTTP proxy auth",
672
static int curl_open(BlockDriverState *bs, QDict *options, int flags,
675
BDRVCURLState *s = bs->opaque;
676
CURLState *state = NULL;
680
const char *cookie_secret;
682
#if LIBCURL_VERSION_NUM >= 0x073700
687
const char *secretid;
688
const char *protocol_delimiter;
691
bdrv_graph_rdlock_main_loop();
692
ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
694
bdrv_graph_rdunlock_main_loop();
699
if (!libcurl_initialized) {
700
ret = curl_global_init(CURL_GLOBAL_ALL);
702
error_setg(errp, "libcurl initialization failed with %d", ret);
705
libcurl_initialized = true;
708
qemu_mutex_init(&s->mutex);
709
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
710
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
714
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
715
CURL_BLOCK_OPT_READAHEAD_DEFAULT);
716
if ((s->readahead_size & 0x1ff) != 0) {
717
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
722
s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
723
CURL_BLOCK_OPT_TIMEOUT_DEFAULT);
724
if (s->timeout > CURL_TIMEOUT_MAX) {
725
error_setg(errp, "timeout parameter is too large or negative");
729
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY,
730
CURL_BLOCK_OPT_SSLVERIFY_DEFAULT);
732
cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
733
cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET);
735
if (cookie && cookie_secret) {
737
"curl driver cannot handle both cookie and cookie secret");
742
s->cookie = qcrypto_secret_lookup_as_utf8(cookie_secret, errp);
747
s->cookie = g_strdup(cookie);
750
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
752
error_setg(errp, "curl block driver requires an 'url' option");
756
if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) ||
757
!strstart(protocol_delimiter, "://", NULL))
759
error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not "
760
"start with '%s://')", bs->drv->protocol_name, file,
761
bs->drv->protocol_name);
765
s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
766
secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);
769
s->password = qcrypto_secret_lookup_as_utf8(secretid, errp);
775
s->proxyusername = g_strdup(
776
qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_USERNAME));
777
secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET);
779
s->proxypassword = qcrypto_secret_lookup_as_utf8(secretid, errp);
780
if (!s->proxypassword) {
785
trace_curl_open(file);
786
qemu_co_queue_init(&s->free_state_waitq);
787
s->aio_context = bdrv_get_aio_context(bs);
788
s->url = g_strdup(file);
789
s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free);
790
qemu_mutex_lock(&s->mutex);
791
state = curl_find_state(s);
792
qemu_mutex_unlock(&s->mutex);
799
if (curl_init_state(s, state) < 0) {
800
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
801
"curl library initialization failed.");
805
s->accept_range = false;
806
if (curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1) ||
807
curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb) ||
808
curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s)) {
809
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
810
"curl library initialization failed.");
813
if (curl_easy_perform(state->curl))
818
#if LIBCURL_VERSION_NUM >= 0x073700
819
if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl)) {
823
if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl)) {
830
#if LIBCURL_VERSION_NUM >= 0x071304
832
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
833
"Server didn't report file size.");
838
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
839
"Unknown file size or zero-length file.");
846
if ((!strncasecmp(s->url, "http://", strlen("http://"))
847
|| !strncasecmp(s->url, "https://", strlen("https://")))
848
&& !s->accept_range) {
849
pstrcpy(state->errmsg, CURL_ERROR_SIZE,
850
"Server does not support 'range' (byte ranges).");
853
trace_curl_open_size(s->len);
855
qemu_mutex_lock(&s->mutex);
856
curl_clean_state(state);
857
qemu_mutex_unlock(&s->mutex);
858
curl_easy_cleanup(state->curl);
861
curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
867
error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
868
curl_easy_cleanup(state->curl);
871
qemu_mutex_destroy(&s->mutex);
875
g_free(s->proxyusername);
876
g_free(s->proxypassword);
878
curl_drop_all_sockets(s->sockets);
879
g_hash_table_destroy(s->sockets);
885
static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
890
BDRVCURLState *s = bs->opaque;
892
uint64_t start = acb->offset;
895
qemu_mutex_lock(&s->mutex);
899
if (curl_find_buf(s, start, acb->bytes, acb)) {
905
state = curl_find_state(s);
909
qemu_co_queue_wait(&s->free_state_waitq, &s->mutex);
912
if (curl_init_state(s, state) < 0) {
913
curl_clean_state(state);
919
acb->end = MIN(acb->bytes, s->len - start);
922
g_free(state->orig_buf);
923
state->buf_start = start;
924
state->buf_len = MIN(acb->end + s->readahead_size, s->len - start);
925
end = start + state->buf_len - 1;
926
state->orig_buf = g_try_malloc(state->buf_len);
927
if (state->buf_len && state->orig_buf == NULL) {
928
curl_clean_state(state);
934
snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end);
935
trace_curl_setup_preadv(acb->bytes, start, state->range);
936
if (curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range) ||
937
curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) {
938
state->acb[0] = NULL;
941
curl_clean_state(state);
946
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
949
qemu_mutex_unlock(&s->mutex);
952
static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
953
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
954
BdrvRequestFlags flags)
957
.co = qemu_coroutine_self(),
964
curl_setup_preadv(bs, &acb);
965
while (acb.ret == -EINPROGRESS) {
966
qemu_coroutine_yield();
971
static void curl_close(BlockDriverState *bs)
973
BDRVCURLState *s = bs->opaque;
976
curl_detach_aio_context(bs);
977
qemu_mutex_destroy(&s->mutex);
979
g_hash_table_destroy(s->sockets);
983
g_free(s->proxyusername);
984
g_free(s->proxypassword);
987
static int64_t coroutine_fn curl_co_getlength(BlockDriverState *bs)
989
BDRVCURLState *s = bs->opaque;
993
static void curl_refresh_filename(BlockDriverState *bs)
995
BDRVCURLState *s = bs->opaque;
999
if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT ||
1000
s->cookie || s->username || s->password || s->proxyusername ||
1006
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url);
1010
static const char *const curl_strong_runtime_opts[] = {
1012
CURL_BLOCK_OPT_SSLVERIFY,
1013
CURL_BLOCK_OPT_COOKIE,
1014
CURL_BLOCK_OPT_COOKIE_SECRET,
1015
CURL_BLOCK_OPT_USERNAME,
1016
CURL_BLOCK_OPT_PASSWORD_SECRET,
1017
CURL_BLOCK_OPT_PROXY_USERNAME,
1018
CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
1023
static BlockDriver bdrv_http = {
1024
.format_name = "http",
1025
.protocol_name = "http",
1027
.instance_size = sizeof(BDRVCURLState),
1028
.bdrv_parse_filename = curl_parse_filename,
1029
.bdrv_open = curl_open,
1030
.bdrv_close = curl_close,
1031
.bdrv_co_getlength = curl_co_getlength,
1033
.bdrv_co_preadv = curl_co_preadv,
1035
.bdrv_detach_aio_context = curl_detach_aio_context,
1036
.bdrv_attach_aio_context = curl_attach_aio_context,
1038
.bdrv_refresh_filename = curl_refresh_filename,
1039
.strong_runtime_opts = curl_strong_runtime_opts,
1042
static BlockDriver bdrv_https = {
1043
.format_name = "https",
1044
.protocol_name = "https",
1046
.instance_size = sizeof(BDRVCURLState),
1047
.bdrv_parse_filename = curl_parse_filename,
1048
.bdrv_open = curl_open,
1049
.bdrv_close = curl_close,
1050
.bdrv_co_getlength = curl_co_getlength,
1052
.bdrv_co_preadv = curl_co_preadv,
1054
.bdrv_detach_aio_context = curl_detach_aio_context,
1055
.bdrv_attach_aio_context = curl_attach_aio_context,
1057
.bdrv_refresh_filename = curl_refresh_filename,
1058
.strong_runtime_opts = curl_strong_runtime_opts,
1061
static BlockDriver bdrv_ftp = {
1062
.format_name = "ftp",
1063
.protocol_name = "ftp",
1065
.instance_size = sizeof(BDRVCURLState),
1066
.bdrv_parse_filename = curl_parse_filename,
1067
.bdrv_open = curl_open,
1068
.bdrv_close = curl_close,
1069
.bdrv_co_getlength = curl_co_getlength,
1071
.bdrv_co_preadv = curl_co_preadv,
1073
.bdrv_detach_aio_context = curl_detach_aio_context,
1074
.bdrv_attach_aio_context = curl_attach_aio_context,
1076
.bdrv_refresh_filename = curl_refresh_filename,
1077
.strong_runtime_opts = curl_strong_runtime_opts,
1080
static BlockDriver bdrv_ftps = {
1081
.format_name = "ftps",
1082
.protocol_name = "ftps",
1084
.instance_size = sizeof(BDRVCURLState),
1085
.bdrv_parse_filename = curl_parse_filename,
1086
.bdrv_open = curl_open,
1087
.bdrv_close = curl_close,
1088
.bdrv_co_getlength = curl_co_getlength,
1090
.bdrv_co_preadv = curl_co_preadv,
1092
.bdrv_detach_aio_context = curl_detach_aio_context,
1093
.bdrv_attach_aio_context = curl_attach_aio_context,
1095
.bdrv_refresh_filename = curl_refresh_filename,
1096
.strong_runtime_opts = curl_strong_runtime_opts,
1099
static void curl_block_init(void)
1101
bdrv_register(&bdrv_http);
1102
bdrv_register(&bdrv_https);
1103
bdrv_register(&bdrv_ftp);
1104
bdrv_register(&bdrv_ftps);
1107
block_init(curl_block_init);