From: Matthew Booth <mbooth@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org
Subject: [Qemu-devel] [PATCH 1/4] curl: Fix parsing of readahead option from filename
Date: Thu, 8 May 2014 09:42:17 +0100 [thread overview]
Message-ID: <1399538540-5076-2-git-send-email-mbooth@redhat.com> (raw)
In-Reply-To: <1399538540-5076-1-git-send-email-mbooth@redhat.com>
curl_parse_filename wasn't removing the option string from the url,
resulting in a 404.
This change is a rewrite of the previous parsing behaviour, and
also changes the option syntax. The new syntax is:
http://example.com/path?query[sslverify=off:readahead=64k]
The new syntax is well defined as long as square brackets in the URI
are escaped.
This change is also preparation for the addition of more options.
Signed-off-by: Matthew Booth <mbooth@redhat.com>
---
block/curl.c | 101 +++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 67 insertions(+), 34 deletions(-)
diff --git a/block/curl.c b/block/curl.c
index d2f1084..e31b6f3 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -46,12 +46,15 @@
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8
#define SECTOR_SIZE 512
-#define READ_AHEAD_SIZE (256 * 1024)
+#define READ_AHEAD_DEFAULT (256 * 1024)
#define FIND_RET_NONE 0
#define FIND_RET_OK 1
#define FIND_RET_WAIT 2
+#define CURL_BLOCK_OPT_URL "url"
+#define CURL_BLOCK_OPT_READAHEAD "readahead"
+
struct BDRVCURLState;
typedef struct CURLAIOCB {
@@ -393,45 +396,74 @@ static void curl_clean_state(CURLState *s)
s->in_use = 0;
}
+/* Parse options out of @filename, which should be a URI.
+ *
+ * Options are given as a sequence of key=value pairs separated by colons and
+ * enclosed in square brackets at the end of the URI. e.g.:
+ *
+ * http://example.com/path?query[sslverify=off:readahead=64k]
+ *
+ * Consequently, if a valid URI ends with a block enclosed by square brackets,
+ * those brackets MUST be URI encoded.
+ */
static void curl_parse_filename(const char *filename, QDict *options,
Error **errp)
{
+ char *file = g_strdup(filename);
+ char *end = file + strlen(file) - 1;
+
+ /* Don't fail if we've been passed an empty string.
+ * Only examine strings with a trailing ']'
+ */
+ if (end >= file && ']' == *end) {
+ /* Look for the opening bracket */
+ char *open = memrchr(file, '[', end - file);
+
+ if (NULL != open) {
+ /* NULL terminate the preceding URI by overwriting the opening
+ * bracket */
+ *open = '\0';
+ char *opt_block = open + 1;
+
+ /* NULL terminate the option string by overwriting the closing
+ * bracket */
+ *end = '\0';
+
+ /* Parse each colon-separated option */
+ char *saveptr;
+ char *opt = strtok_r(opt_block, ":", &saveptr);
+ while (NULL != opt) {
+ size_t opt_len = strlen(opt);
+
+ /* Look for an equals sign */
+ char *equals = memchr(opt, '=', opt_len);
+ if (NULL == equals) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt,
+ "a value");
+ goto out;
+ }
- #define RA_OPTSTR ":readahead="
- char *file;
- char *ra;
- const char *ra_val;
- int parse_state = 0;
-
- file = g_strdup(filename);
-
- /* Parse a trailing ":readahead=#:" param, if present. */
- ra = file + strlen(file) - 1;
- while (ra >= file) {
- if (parse_state == 0) {
- if (*ra == ':') {
- parse_state++;
- } else {
- break;
- }
- } else if (parse_state == 1) {
- if (*ra > '9' || *ra < '0') {
- char *opt_start = ra - strlen(RA_OPTSTR) + 1;
- if (opt_start > file &&
- strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
- ra_val = ra + 1;
- ra -= strlen(RA_OPTSTR) - 1;
- *ra = '\0';
- qdict_put(options, "readahead", qstring_from_str(ra_val));
+ size_t key_len = equals - opt;
+ char *value = equals + 1;
+
+ if (key_len == strlen(CURL_BLOCK_OPT_READAHEAD) &&
+ memcmp(opt, CURL_BLOCK_OPT_READAHEAD, key_len) == 0) {
+ qdict_put(options, CURL_BLOCK_OPT_READAHEAD,
+ qstring_from_str(value));
+ } else {
+ *equals = '\0';
+ error_set(errp, QERR_INVALID_PARAMETER, opt);
+ goto out;
}
- break;
+
+ opt = strtok_r(NULL, ":", &saveptr);
}
}
- ra--;
}
- qdict_put(options, "url", qstring_from_str(file));
+ qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(file));
+out:
g_free(file);
}
@@ -440,12 +472,12 @@ static QemuOptsList runtime_opts = {
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
- .name = "url",
+ .name = CURL_BLOCK_OPT_URL,
.type = QEMU_OPT_STRING,
.help = "URL to open",
},
{
- .name = "readahead",
+ .name = CURL_BLOCK_OPT_READAHEAD,
.type = QEMU_OPT_SIZE,
.help = "Readahead size",
},
@@ -477,14 +509,15 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
goto out_noclean;
}
- s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
+ s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
+ READ_AHEAD_DEFAULT);
if ((s->readahead_size & 0x1ff) != 0) {
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
s->readahead_size);
goto out_noclean;
}
- file = qemu_opt_get(opts, "url");
+ file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
if (file == NULL) {
error_setg(errp, "curl block driver requires an 'url' option");
goto out_noclean;
--
1.9.0
next prev parent reply other threads:[~2014-05-08 8:42 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-08 8:42 [Qemu-devel] Curl updates Matthew Booth
2014-05-08 8:42 ` Matthew Booth [this message]
2014-05-13 17:29 ` [Qemu-devel] [PATCH 1/4] curl: Fix parsing of readahead option from filename Eric Blake
2014-05-14 16:00 ` Matthew Booth
2014-05-14 16:55 ` Eric Blake
2014-05-08 8:42 ` [Qemu-devel] [PATCH 2/4] curl: Add sslverify option Matthew Booth
2014-05-08 8:42 ` [Qemu-devel] [PATCH 3/4] curl: Add usage documentation Matthew Booth
2014-05-08 8:42 ` [Qemu-devel] [PATCH 4/4] curl: Fix build when curl_multi_socket_action isn't available Matthew Booth
2014-05-13 19:47 ` [Qemu-devel] Curl updates Eric Blake
2014-05-14 7:48 ` Kevin Wolf
2014-05-14 12:59 ` Eric Blake
2014-05-14 16:08 ` Matthew Booth
2014-05-14 16:43 ` Kevin Wolf
2014-05-14 21:20 ` Matthew Booth
2014-05-14 21:36 ` Eric Blake
2014-05-14 16:59 ` Eric Blake
2014-05-14 16:06 ` Matthew Booth
2014-05-14 17:02 ` Eric Blake
2014-05-14 20:45 ` Matthew Booth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1399538540-5076-2-git-send-email-mbooth@redhat.com \
--to=mbooth@redhat.com \
--cc=kwolf@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.