diff mbox series

--header option to pass additional raw HTTP headers

Message ID 20210508192343.66941-1-stokito@gmail.com
State Changes Requested
Delegated to: Petr Štetiar
Headers show
Series --header option to pass additional raw HTTP headers | expand

Commit Message

Sergey Ponomarev May 8, 2021, 7:23 p.m. UTC
Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
---
 tests/cram/test-san_uclient-fetch.t |  1 +
 tests/cram/test_uclient-fetch.t     |  1 +
 uclient-fetch.c                     | 16 +++++++++++++++
 uclient-http.c                      | 31 +++++++++++++++++++++++++++++
 uclient.h                           |  1 +
 5 files changed, 50 insertions(+)

Comments

Petr Štetiar May 9, 2021, 7:24 a.m. UTC | #1
Sergey Ponomarev <stokito@gmail.com> [2021-05-08 22:23:43]:

As stated in https://openwrt.org/submitting-patches your v2 should look like:

 Subject: [PATCH uclient] uclient-fetch: add support for --header option

 put missing commit description here

> Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
Sergey Ponomarev May 9, 2021, 9:51 a.m. UTC | #2
Hi Petr and thank you for the review. I'm not sure what to add to the
option described in man but here is a comment that I made:

You can add a custom HTTP header(s) to request:

    wget --header='Authorization: Bearer TOKEN' \
        --header='If-Modified-Since: Wed, 9 May 2021 12:16:00 GMT' \
        https://example.com/

Some headers like Authorization or User-Agent may be already set by
--password or --user-agent.
We may override them but it's a protection from user itself.
To keep code concise the logic omitted.


I don't know how to update the patch because when I sent it created a
new PR or patchwork.
So please change the commit description yourself.


On Sun, 9 May 2021 at 10:24, Petr Štetiar <ynezz@true.cz> wrote:
>
> Sergey Ponomarev <stokito@gmail.com> [2021-05-08 22:23:43]:
>
> As stated in https://openwrt.org/submitting-patches your v2 should look like:
>
>  Subject: [PATCH uclient] uclient-fetch: add support for --header option
>
>  put missing commit description here
>
> > Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
diff mbox series

Patch

diff --git a/tests/cram/test-san_uclient-fetch.t b/tests/cram/test-san_uclient-fetch.t
index 3158bde..3ed3be5 100644
--- a/tests/cram/test-san_uclient-fetch.t
+++ b/tests/cram/test-san_uclient-fetch.t
@@ -15,6 +15,7 @@  check uclient-fetch usage:
   \t--user=<user>\t\t\tHTTP authentication username (esc)
   \t--password=<password>\t\tHTTP authentication password (esc)
   \t--user-agent | -U <str>\t\tSet HTTP user agent (esc)
+  \t--header='Header: value'\t\tAdd HTTP header. Multiple allowed (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--spider | -s\t\t\tSpider mode - only check file existence (esc)
diff --git a/tests/cram/test_uclient-fetch.t b/tests/cram/test_uclient-fetch.t
index 4ffe719..5a7ff43 100644
--- a/tests/cram/test_uclient-fetch.t
+++ b/tests/cram/test_uclient-fetch.t
@@ -15,6 +15,7 @@  check uclient-fetch usage:
   \t--user=<user>\t\t\tHTTP authentication username (esc)
   \t--password=<password>\t\tHTTP authentication password (esc)
   \t--user-agent | -U <str>\t\tSet HTTP user agent (esc)
+  \t--header='Header: value'\t\tAdd HTTP header. Multiple allowed (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--spider | -s\t\t\tSpider mode - only check file existence (esc)
diff --git a/uclient-fetch.c b/uclient-fetch.c
index 282092e..4efc917 100644
--- a/uclient-fetch.c
+++ b/uclient-fetch.c
@@ -44,6 +44,7 @@ 
 static const char *user_agent = "uclient-fetch";
 static const char *post_data;
 static const char *post_file;
+static const char **raw_headers = NULL;
 static struct ustream_ssl_ctx *ssl_ctx;
 static const struct ustream_ssl_ops *ssl_ops;
 static int quiet = false;
@@ -342,6 +343,7 @@  static int init_request(struct uclient *cl)
 
 	uclient_http_reset_headers(cl);
 	uclient_http_set_header(cl, "User-Agent", user_agent);
+	uclient_http_set_raw_headers(cl, raw_headers);
 	if (cur_resume)
 		check_resume_offset(cl);
 
@@ -481,6 +483,7 @@  static int usage(const char *progname)
 		"	--continue | -c			Continue a partially-downloaded file\n"
 		"	--user=<user>			HTTP authentication username\n"
 		"	--password=<password>		HTTP authentication password\n"
+		"	--header='Header: value'		Add HTTP header. Multiple allowed\n"
 		"	--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"
@@ -542,6 +545,7 @@  enum {
 	L_USER,
 	L_PASSWORD,
 	L_USER_AGENT,
+	L_HEADER,
 	L_POST_DATA,
 	L_POST_FILE,
 	L_SPIDER,
@@ -559,6 +563,7 @@  static const struct option longopts[] = {
 	[L_USER] = { "user", required_argument, NULL, 0 },
 	[L_PASSWORD] = { "password", required_argument, NULL, 0 },
 	[L_USER_AGENT] = { "user-agent", required_argument, NULL, 0 },
+	[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_SPIDER] = { "spider", no_argument, NULL, 0 },
@@ -578,6 +583,7 @@  int main(int argc, char **argv)
 	const char *proxy_url;
 	char *username = NULL;
 	char *password = NULL;
+	int raw_headers_count = 0;
 	struct uclient *cl;
 	int longopt_idx = 0;
 	bool has_cert = false;
@@ -626,6 +632,16 @@  int main(int argc, char **argv)
 			case L_USER_AGENT:
 				user_agent = optarg;
 				break;
+			case L_HEADER:
+				if (!raw_headers) {
+					/* Max possible count of headers is the count of args (argc) - 2
+					 Since the first arg is program and last is a URL.
+					 But user may forget the URL and raw_headers is null terminated so allocate argc */
+					raw_headers = calloc(argc, sizeof(char *));
+				}
+				raw_headers[raw_headers_count] = optarg;
+				raw_headers_count++;
+				break;
 			case L_POST_DATA:
 				post_data = optarg;
 				break;
diff --git a/uclient-http.c b/uclient-http.c
index 349e69c..4ea40c7 100644
--- a/uclient-http.c
+++ b/uclient-http.c
@@ -96,6 +96,7 @@  struct uclient_http {
 
 	uint32_t nc;
 
+	const char **raw_headers;
 	struct blob_buf headers;
 	struct blob_buf meta;
 };
@@ -587,6 +588,20 @@  uclient_http_add_auth_header(struct uclient_http *uh)
 	return 0;
 }
 
+static void
+uclient_http_send_raw_headers(const struct uclient_http *uh) {
+	if (!uh->raw_headers) {
+		return;
+	}
+	const char **raw_headers = uh->raw_headers;
+	const char *raw_header = *raw_headers;
+	while (raw_header != NULL) {
+		ustream_printf(uh->us, "%s\r\n", raw_header);
+		raw_headers++;
+		raw_header = *raw_headers;
+	}
+}
+
 static int
 uclient_http_send_headers(struct uclient_http *uh)
 {
@@ -625,6 +640,7 @@  uclient_http_send_headers(struct uclient_http *uh)
 	if (err)
 		return err;
 
+	uclient_http_send_raw_headers(uh);
 	ustream_printf(uh->us, "\r\n");
 
 	uh->state = HTTP_STATE_HEADERS_SENT;
@@ -1025,6 +1041,21 @@  uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
 	return 0;
 }
 
+int
+uclient_http_set_raw_headers(struct uclient *cl, const char **raw_headers)
+{
+	struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
+
+	if (cl->backend != &uclient_backend_http)
+		return -1;
+
+	if (uh->state > HTTP_STATE_INIT)
+		return -1;
+
+	uh->raw_headers = raw_headers;
+	return 0;
+}
+
 static int
 uclient_http_send_data(struct uclient *cl, const char *buf, unsigned int len)
 {
diff --git a/uclient.h b/uclient.h
index 4f37364..f1977bc 100644
--- a/uclient.h
+++ b/uclient.h
@@ -121,6 +121,7 @@  extern const struct uclient_backend uclient_backend_http;
 
 int uclient_http_reset_headers(struct uclient *cl);
 int uclient_http_set_header(struct uclient *cl, const char *name, const char *value);
+int uclient_http_set_raw_headers(struct uclient *cl, const char **raw_headers);
 int uclient_http_set_request_type(struct uclient *cl, const char *type);
 int uclient_http_redirect(struct uclient *cl);