uclient-fetch: Support of --method, --body-data and --body-file
authorSergey Ponomarev <stokito@gmail.com>
Mon, 9 May 2022 21:09:09 +0000 (00:09 +0300)
committerFelix Fietkau <nbd@nbd.name>
Fri, 13 Feb 2026 07:38:05 +0000 (07:38 +0000)
The --method allows executing PUT, DELETE, OPTIONS, HEAD e.g.:

    wget -O - -q \
    --method=PUT \
    --body-data='{"id": 42}' \
    --header='Content-Type: application/json' \
    http://api.example.com/

To avoid clashes with the --post-data/file options,
the separate --body-data/file must be used.
They are stored to the same post_data and post_file vars.
Mutual usage of the options is not allowed, same as in GNU wget.

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
tests/cram/test-san_uclient-fetch.t
tests/cram/test_uclient-fetch.t
uclient-fetch.c

index dc5fcb419f38ef6a0f08712b509cd80a8430c726..f37149a93daea3e2caccdd8fd5ccbf1f9f3603ca 100644 (file)
@@ -18,6 +18,9 @@ check uclient-fetch usage:
   \t--user-agent | -U <str>\t\tSet HTTP user agent (esc)
   \t--post-data=STRING\t\tuse the POST method; send STRING as the data (esc)
   \t--post-file=FILE\t\tuse the POST method; send FILE as the data (esc)
+  \t--method=METHOD\t\tuse the HTTP method e.g. PUT (esc)
+  \t--body-data=STRING\t\twith --method send the STRING in body (esc)
+  \t--body-file=FILE\t\twith --method send the FILE content in body (esc)
   \t--spider | -s\t\t\tSpider mode - only check file existence (esc)
   \t--timeout=N | -T N\t\tSet connect/request timeout to N seconds (esc)
   \t--proxy=on | -Y on\t\tEnable interpretation of proxy env vars (default) (esc)
index 77fc7aef4de477802d8cf2ddd506af45d20cbdfa..c6cf1a316e300ab49b5628a80fe3254d4e000733 100644 (file)
@@ -18,6 +18,9 @@ check uclient-fetch usage:
   \t--user-agent | -U <str>\t\tSet HTTP user agent (esc)
   \t--post-data=STRING\t\tuse the POST method; send STRING as the data (esc)
   \t--post-file=FILE\t\tuse the POST method; send FILE as the data (esc)
+  \t--method=METHOD\t\tuse the HTTP method e.g. PUT (esc)
+  \t--body-data=STRING\t\twith --method send the STRING in body (esc)
+  \t--body-file=FILE\t\twith --method send the FILE content in body (esc)
   \t--spider | -s\t\t\tSpider mode - only check file existence (esc)
   \t--timeout=N | -T N\t\tSet connect/request timeout to N seconds (esc)
   \t--proxy=on | -Y on\t\tEnable interpretation of proxy env vars (default) (esc)
index 26269f52df076d9b9c75eb5d8d0c3a5ba33d9319..43f7d9d57e624cc01c313b6127ad3e079d211071 100644 (file)
@@ -50,7 +50,7 @@ static const char *user_agent = "uclient-fetch";
 static const char *method = NULL;
 static const char *post_data;
 static const char *post_file;
-static char opt_post = 0;  /* 1 when --post-data/file is used */
+static char opt_post = 0; /* 1 when --post-data/file is used, 2 when --body-data/file is used */
 static struct ustream_ssl_ctx *ssl_ctx;
 static const struct ustream_ssl_ops *ssl_ops;
 static int quiet = false;
@@ -529,6 +529,9 @@ static void usage(const char *progname)
                "       --user-agent | -U <str>         Set HTTP user agent\n"
                "       --post-data=STRING              use the POST method; send STRING as the data\n"
                "       --post-file=FILE                use the POST method; send FILE as the data\n"
+               "       --method=METHOD         use the HTTP method e.g. PUT\n"
+               "       --body-data=STRING              with --method send the STRING in body\n"
+               "       --body-file=FILE                with --method send the FILE content in body\n"
                "       --spider | -s                   Spider mode - only check file existence\n"
                "       --timeout=N | -T N              Set connect/request timeout to N seconds\n"
                "       --proxy=on | -Y on              Enable interpretation of proxy env vars (default)\n"
@@ -595,6 +598,9 @@ enum {
        L_USER_AGENT,
        L_POST_DATA,
        L_POST_FILE,
+       L_METHOD,
+       L_BODY_DATA,
+       L_BODY_FILE,
        L_SPIDER,
        L_TIMEOUT,
        L_CONTINUE,
@@ -614,6 +620,9 @@ static const struct option longopts[] = {
        [L_USER_AGENT] = { "user-agent", required_argument, NULL, 0 },
        [L_POST_DATA] = { "post-data", required_argument, NULL, 0 },
        [L_POST_FILE] = { "post-file", required_argument, NULL, 0 },
+       [L_METHOD] = { "method", required_argument, NULL, 0 },
+       [L_BODY_DATA] = { "body-data", required_argument, NULL, 0 },
+       [L_BODY_FILE] = { "body-file", required_argument, NULL, 0 },
        [L_SPIDER] = { "spider", no_argument, NULL, 0 },
        [L_TIMEOUT] = { "timeout", required_argument, NULL, 0 },
        [L_CONTINUE] = { "continue", no_argument, NULL, 0 },
@@ -700,6 +709,25 @@ int main(int argc, char **argv)
                                opt_post = 1;
                                post_file = optarg;
                                break;
+                       case L_METHOD:
+                               method = optarg;
+                               break;
+                       case L_BODY_DATA:
+                               if (opt_post) {
+                                       usage(progname);
+                                       goto out;
+                               }
+                               opt_post = 2;
+                               post_data = optarg;
+                               break;
+                       case L_BODY_FILE:
+                               if (opt_post) {
+                                       usage(progname);
+                                       goto out;
+                               }
+                               opt_post = 2;
+                               post_file = optarg;
+                               break;
                        case L_SPIDER:
                                no_output = true;
                                break;
@@ -796,13 +824,25 @@ int main(int argc, char **argv)
                }
        }
 
-       if (opt_post == 1) {
-               method = "POST";
-       } else if (no_output) {
-               /* Note: GNU wget --spider sends a HEAD and if it failed repeats with a GET */
-               method = "HEAD";
+       if (method) {
+               if (opt_post == 1 || no_output) {
+                       /* --post-data/file or --spider can't be used with --method */
+                       usage(progname);
+                       goto out;
+               }
        } else {
-               method = "GET";
+               if (opt_post == 1) {
+                       method = "POST";
+               } else if (opt_post == 2) {
+                       /* --body-data/file specified but no --method */
+                       usage(progname);
+                       goto out;
+               } else if (no_output) {
+                       /* Note: GNU wget --spider sends a HEAD and if it failed repeats with a GET */
+                       method = "HEAD";
+               } else {
+                       method = "GET";
+               }
        }
 
        argv += optind;