From c51017cf595c6e58c9051348f4eae2cbb5344aa3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 May 2024 14:49:42 +0200 Subject: [PATCH] trurl: add "strict:" as prefix to a get component The strict prefix makes trurl immediately exit with an error code if such a get can't be done due to URL decoding problems. By default, such a problem will only make trurl skip that part and silently continue. Use it like this: --get "{strict:query}" I also made "url:" a valid prefix, and now we consider the single colon prefix to be a shortcut for url:. The concept of prefixes scale better when we use real words instead of single characters. Fixes #305 Closes #310 --- tests.json | 28 ++++++++++++++++++++++++++++ trurl.1 | 13 ++++++++++--- trurl.c | 25 +++++++++++++++++-------- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/tests.json b/tests.json index 844f9085..2e440752 100644 --- a/tests.json +++ b/tests.json @@ -2544,5 +2544,33 @@ "stderr": "", "returncode": 0 } + }, + { + "input": { + "arguments": [ + "https://curl.se?name=mr%00smith", + "--get", + "{query}" + ] + }, + "expected": { + "stderr": "trurl note: URL decode error, most likely because of rubbish in the input (query)\n", + "returncode": 0, + "stdout": "\n" + } + }, + { + "input": { + "arguments": [ + "https://curl.se?name=mr%00smith", + "--get", + "{strict:query}" + ] + }, + "expected": { + "stderr": "trurl error: problems URL decoding query\ntrurl error: Try trurl -h for help\n", + "returncode": 10, + "stdout": "" + } } ] diff --git a/trurl.1 b/trurl.1 index 2faad488..d3309ccb 100644 --- a/trurl.1 +++ b/trurl.1 @@ -109,10 +109,17 @@ user, password, options, host, port, path, query, fragment and zoneid. not have a value. Components are shown URL decoded by default. If you instead write the -component prefixed with a colon like "{:path}", it gets output URL encoded. +component prefixed with "url:" like "{url:path}", it gets output URL encoded. +As a shortcut, "url:" also works written as a single colon: "{:path}". -You may also prefix components with \fBdefault:\fP and/or \fBpuny:\fP or \fBidn:\fP, -in any order. +URL decoding a component may cause problems to display it. Such problems make +a warning get displayed unless \fB--quiet\fP is used. URL decode problems can +optionally be turned into errors by prefixing the comopnent name with +"strict:", as in "{strict:path}". In this stricter mode, a URL decode problem +makes trurl stop what it is doing and return with exit code 10. + +You may also prefix components with \fBdefault:\fP and/or \fBpuny:\fP or +\fBidn:\fP, in any order. If \fBdefault:\fP is specified, like "{default:url}" or "{default:port}", and the port is not explicitly specified in the URL, diff --git a/trurl.c b/trurl.c index 38a49ed0..1ccb3bbf 100644 --- a/trurl.c +++ b/trurl.c @@ -757,6 +757,7 @@ static void get(struct option *o, CURLU *uh) size_t vlen; bool isquery = false; bool queryall = false; + bool strict = false; /* strict mode, fail on URL decode problems */ int mods = 0; end = strchr(ptr, endbyte); ptr++; /* pass the { */ @@ -766,39 +767,44 @@ static void get(struct option *o, CURLU *uh) continue; } - /* {path} {:path} */ + /* {path} {:path} {/path} */ if(*ptr == ':') { mods |= VARMODIFIER_URLENCODED; ptr++; } vlen = end - ptr; do { + size_t wordlen; cl = memchr(ptr, ':', vlen); if(!cl) break; + wordlen = cl - ptr + 1; /* modifiers! */ - if(!strncmp(ptr, "default:", cl - ptr + 1)) + if(!strncmp(ptr, "default:", wordlen)) mods |= VARMODIFIER_DEFAULT; - else if(!strncmp(ptr, "puny:", cl - ptr + 1)) { + else if(!strncmp(ptr, "puny:", wordlen)) { if(mods & VARMODIFIER_PUNY2IDN) errorf(o, ERROR_GET, "puny modifier is mutually exclusive with idn"); mods |= VARMODIFIER_PUNY; } - else if(!strncmp(ptr, "idn:", cl - ptr + 1)) { + else if(!strncmp(ptr, "idn:", wordlen)) { if(mods & VARMODIFIER_PUNY) errorf(o, ERROR_GET, "idn modifier is mutually exclusive with puny"); mods |= VARMODIFIER_PUNY2IDN; } + else if(!strncmp(ptr, "strict:", wordlen)) + strict = true; + else if(!strncmp(ptr, "url:", wordlen)) + mods |= VARMODIFIER_URLENCODED; else { - /* {query: or {query-all: */ - if(!strncmp(ptr, "query-all:", cl - ptr + 1)) { + if(!strncmp(ptr, "query-all:", wordlen)) { isquery = true; queryall = true; } - else if(!strncmp(ptr, "query:", cl - ptr + 1)) + else if(!strncmp(ptr, "query:", wordlen)) isquery = true; else { /* syntax error */ @@ -844,7 +850,10 @@ static void get(struct option *o, CURLU *uh) /* silently ignore */ break; default: - trurl_warnf(o, "%s (%s)", curl_url_strerror(rc), v->name); + if((rc == CURLUE_URLDECODE) && strict) + errorf(o, ERROR_GET, "problems URL decoding %s", v->name); + else + trurl_warnf(o, "%s (%s)", curl_url_strerror(rc), v->name); break; } }