[OpenWrt-Devel] uclient-fetch add ability to pass custom http headers
diff mbox series

Message ID CADR0UcUXJS4DkSSR_0-ZKhdEOaOwUn09WpJDpG9NMRYNsjQ8Sw@mail.gmail.com
State New
Headers show
Series
  • [OpenWrt-Devel] uclient-fetch add ability to pass custom http headers
Related show

Commit Message

Sergey Ponomarev Jan. 27, 2020, 1:46 a.m. UTC
Hi,

I making a package that internally will perform a HTTP call to OAuth
service and I need to pass `Authorization: Barer token` as a header. The
wget clone uclient-fetch doesn't have such functionality to pass an
additional header while original wget have it. I can use curl but it uses
too much space: uclient-fetch~ 28Kb while curl  ~280kb.
I'm pretty sure that there is thousands of other reasons to pass a custom
header like `Accept: application/json` etc.
So here I made a small patch that adds such functionality to uclient-fetch.
You can specify multiple headers so they all will be stored to raw_headers
list.
uclient-fetch --header="H1: VAL1" --header="H2: VAL2" -O -
http://192.168.1.1/
I tested with Wireshark and all works fine.

 int uclient_http_redirect(struct uclient *cl);

Comments

Sergey Ponomarev Jan. 29, 2020, 12:10 a.m. UTC | #1
Hi again,

I need to discuss some changes before working on it so please take a
look on https://forum.openwrt.org/t/uclient-fetch-add-more-options-from-wget-and-create-uclient-curl-clone-of-curl/54060

I created the patch from CLion and it doesn't contains signoff so just
to be sure that it will be processed correctly I regenerated it with
git format-patch:


From 8a9562d89891ec886192d7693e60065d0985fedd Mon Sep 17 00:00:00 2001
From: Sergey Ponomarev <stokito@gmail.com>
Date: Mon, 27 Jan 2020 03:27:50 +0200
Subject: [PATCH] Add --header option to pass additional raw HTTP headers

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
---
 uclient-fetch.c | 16 ++++++++++++++++
 uclient-http.c  | 28 ++++++++++++++++++++++++++++
 uclient.h       |  1 +
 3 files changed, 45 insertions(+)

diff --git a/uclient-fetch.c b/uclient-fetch.c
index 38c9c53..34cbfd5 100644
--- a/uclient-fetch.c
+++ b/uclient-fetch.c
@@ -43,6 +43,7 @@

 static const char *user_agent = "uclient-fetch";
 static const char *post_data;
+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;
@@ -340,6 +341,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);

@@ -458,6 +460,7 @@ static int usage(const char *progname)
      "  -P <dir>         Set directory for output files\n"
      "  --user=<user>        HTTP authentication username\n"
      "  --password=<password>     HTTP authentication password\n"
+     "  --header=<header>     Add HTTP header\n"
      "  --user-agent|-U <str>     Set HTTP user agent\n"
      "  --post-data=STRING    use the POST method; send STRING as the data\n"
      "  --spider|-s          Spider mode - only check file existence\n"
@@ -512,6 +515,7 @@ enum {
   L_CA_CERTIFICATE,
   L_USER,
   L_PASSWORD,
+  L_HEADER,
   L_USER_AGENT,
   L_POST_DATA,
   L_SPIDER,
@@ -527,6 +531,7 @@ static const struct option longopts[] = {
   [L_CA_CERTIFICATE] = { "ca-certificate", required_argument },
   [L_USER] = { "user", required_argument },
   [L_PASSWORD] = { "password", required_argument },
+  [L_HEADER] = { "header", required_argument },
   [L_USER_AGENT] = { "user-agent", required_argument },
   [L_POST_DATA] = { "post-data", required_argument },
   [L_SPIDER] = { "spider", no_argument },
@@ -546,6 +551,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;
@@ -580,6 +586,16 @@ int main(int argc, char **argv)
            password = strdup(optarg);
            memset(optarg, '*', strlen(optarg));
            break;
+        case L_HEADER:
+           if (!raw_headers) {
+              // Max possible count of headers is the count of args (argc) - 2
+              // because the first arg is program and last is a URL.
+              // But user may forget the URL and raw_headers is null
terminated so max raw_headers can be argc
+              raw_headers = calloc(argc, sizeof(char *));
+           }
+           raw_headers[raw_headers_count] = optarg;
+           raw_headers_count++;
+           break;
         case L_USER_AGENT:
            user_agent = optarg;
            break;
diff --git a/uclient-http.c b/uclient-http.c
index c1f7228..a70d445 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;
 };
@@ -589,6 +590,17 @@ uclient_http_add_auth_header(struct uclient_http *uh)
   return 0;
 }

+static void
+uclient_http_send_raw_headers(const struct uclient_http *uh) {
+  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)
 {
@@ -626,6 +638,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;
@@ -1026,6 +1039,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);

Patch
diff mbox series

Index: uclient-fetch.c
<+>UTF-8
===================================================================
--- uclient-fetch.c (revision fef6d3d311ac45c662c01e0ebd9cb0f6c8d7145c)
+++ uclient-fetch.c (revision 8a9562d89891ec886192d7693e60065d0985fedd)
@@ -43,6 +43,7 @@ 

 static const char *user_agent = "uclient-fetch";
 static const char *post_data;
+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;
@@ -340,6 +341,7 @@ 

  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);

@@ -458,6 +460,7 @@ 
  " -P <dir> Set directory for output files\n"
  " --user=<user> HTTP authentication username\n"
  " --password=<password> HTTP authentication password\n"
+ " --header=<header> Add HTTP header\n"
  " --user-agent|-U <str> Set HTTP user agent\n"
  " --post-data=STRING use the POST method; send STRING as the data\n"
  " --spider|-s Spider mode - only check file existence\n"
@@ -512,6 +515,7 @@ 
  L_CA_CERTIFICATE,
  L_USER,
  L_PASSWORD,
+ L_HEADER,
  L_USER_AGENT,
  L_POST_DATA,
  L_SPIDER,
@@ -527,6 +531,7 @@ 
  [L_CA_CERTIFICATE] = { "ca-certificate", required_argument },
  [L_USER] = { "user", required_argument },
  [L_PASSWORD] = { "password", required_argument },
+ [L_HEADER] = { "header", required_argument },
  [L_USER_AGENT] = { "user-agent", required_argument },
  [L_POST_DATA] = { "post-data", required_argument },
  [L_SPIDER] = { "spider", no_argument },
@@ -546,6 +551,7 @@ 
  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;
@@ -579,6 +585,16 @@ 
  break;
  password = strdup(optarg);
  memset(optarg, '*', strlen(optarg));
+ break;
+ case L_HEADER:
+ if (!raw_headers) {
+ // Max possible count of headers is the count of args (argc) - 2
+ // because the first arg is program and last is a URL.
+ // But user may forget the URL and raw_headers is null terminated so max
raw_headers can be argc
+ raw_headers = calloc(argc, sizeof(char *));
+ }
+ raw_headers[raw_headers_count] = optarg;
+ raw_headers_count++;
  break;
  case L_USER_AGENT:
  user_agent = optarg;
Index: uclient-http.c
<+>UTF-8
===================================================================
--- uclient-http.c (revision fef6d3d311ac45c662c01e0ebd9cb0f6c8d7145c)
+++ uclient-http.c (revision 8a9562d89891ec886192d7693e60065d0985fedd)
@@ -96,6 +96,7 @@ 

  uint32_t nc;

+ const char **raw_headers;
  struct blob_buf headers;
  struct blob_buf meta;
 };
@@ -589,6 +590,17 @@ 
  return 0;
 }

+static void
+uclient_http_send_raw_headers(const struct uclient_http *uh) {
+ 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)
 {
@@ -626,6 +638,7 @@ 
  if (err)
  return err;

+ uclient_http_send_raw_headers(uh);
  ustream_printf(uh->us, "\r\n");

  uh->state = HTTP_STATE_HEADERS_SENT;
@@ -1025,6 +1038,21 @@ 
  blobmsg_add_string(&uh->headers, name, 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)
Index: uclient.h
<+>UTF-8
===================================================================
--- uclient.h (revision fef6d3d311ac45c662c01e0ebd9cb0f6c8d7145c)
+++ uclient.h (revision 8a9562d89891ec886192d7693e60065d0985fedd)
@@ -121,6 +121,7 @@ 

 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);