@@ -490,6 +490,9 @@ static int 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"
@@ -551,6 +554,9 @@ enum {
L_HEADER,
L_POST_DATA,
L_POST_FILE,
+ L_METHOD,
+ L_BODY_DATA,
+ L_BODY_FILE,
L_SPIDER,
L_TIMEOUT,
L_CONTINUE,
@@ -569,6 +575,9 @@ static const struct option longopts[] = {
[L_HEADER] = { "header", 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 },
@@ -653,6 +662,15 @@ int main(int argc, char **argv)
opt_post = true;
post_file = optarg;
break;
+ case L_METHOD:
+ method = optarg;
+ break;
+ case L_BODY_DATA:
+ post_data = optarg;
+ break;
+ case L_BODY_FILE:
+ post_file = optarg;
+ break;
case L_SPIDER:
no_output = true;
break;
@@ -716,7 +734,9 @@ int main(int argc, char **argv)
}
}
- if (opt_post) {
+ if (method) {
+ // the method already was populated from getopt()
+ } else if (opt_post) {
method = "POST";
} else if (no_output) {
/* Note: GNU wget --spider sends a HEAD and if it failed repeats with a GET */
The --method allows to execute PUT,DELETE,OPTIONS. Usage sample: $ uclient-fetch -O - -q --method=PUT \ --body-data="trololo" \ --header="Content-Type: text/plain" \ http://localhost:8080/cgi-bin/echo.sh HTTP/1.1 200 OK Content-Length: 7 Content-Type: text/html REQUEST_METHOD: PUT CONTENT_TYPE: text/plain CONTENT_LENGTH: trololo To avoid clashes with the --post-data/file options the --body-data/file must be used. But internally they stored to the same post_data and post_data fields. The GNU wget does similar. GNU wget shows an error on mutual usage of the options and we can do this too: if (method) { // the method already was populated from getopt() if (opt_post) { fprintf(stderr, "--method expects data through --body-data/file\n"); exit(1); } But this is an additional code and space for a very exceptional case. We may change this behaviour later. Another incompatibility is about Content-Type header. When --post-data is used then added a header Content-Type: application/x-www-form-urlencoded. But users may call some API with POST and want to send some other e.g. Content-Type: application/json. The GNU wget and BusyBox wget allows to override the CT with --header option i.e. $ wget -O - -q \ --post-data="trololo" \ --header="Content-Type: text/plain" \ http://localhost:8080/cgi-bin/echo.sh HTTP/1.1 200 OK Content-Length: 7 Content-Type: text/html REQUEST_METHOD: POST CONTENT_TYPE: text/plain CONTENT_LENGTH: trololo In GNU wget even when --method=POST and --body-data are used but the --header Content-Type wasn't set then the default CT x-www-form-urlencoded is used. The header overriding is currently not implemented and it may require more of changes. Also users may want to also override other headers like Authorization and Host. For me this seems like a dangerous practice. If someone wants to send a POST request with a custom CT then instead of --post-data and --header they should use --method=POST --body-data and --header. This will make the request explicit. Signed-off-by: Sergey Ponomarev <stokito@gmail.com> --- uclient-fetch.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)