diff mbox series

[07/12] channel_curl: allow to collect HTTP headers

Message ID 20181002143357.9329-7-sbabic@denx.de
State Accepted
Headers show
Series [01/12] channel_curl: allow answers not in JSON format | expand

Commit Message

Stefano Babic Oct. 2, 2018, 2:33 p.m. UTC
Some backends require to parse the headers sent by the servers.
Add callback to the connection and parse headers in the
format <name>:<value> into a dictionary. This is done
if the caller pass a valid dictionary list, or skipped
in other cases.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 corelib/channel_curl.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 include/channel_curl.h |  1 +
 2 files changed, 52 insertions(+)
diff mbox series

Patch

diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
index 992cff3..8fec0d9 100644
--- a/corelib/channel_curl.c
+++ b/corelib/channel_curl.c
@@ -8,6 +8,7 @@ 
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <errno.h>
 #include <assert.h>
 #include <stdarg.h>
@@ -390,6 +391,38 @@  static int channel_callback_xferinfo_legacy(void *p, double dltotal, double dlno
 					 (curl_off_t)ultotal, (curl_off_t)ulnow);
 }
 
+static size_t channel_callback_headers(char *buffer, size_t size, size_t nitems, void *userdata)
+{
+	struct dict *dict = (struct dict *)userdata;
+	char *info = malloc(size * nitems + 1);
+	char *p, *key, *val;
+
+	if (!info) {
+		ERROR("No memory allocated for headers, headers not collected !!");
+		return nitems * size;
+	}
+	/*
+	 * Work on a local copy because the buffer is not
+	 * '\0' terminated
+	 */
+	memcpy(info, buffer, size * nitems);
+	info[size * nitems] = '\0';
+	p = memchr(info, ':', size * nitems);
+	if (p) {
+		*p = '\0';
+		key = info;
+		val = p + 1; /* Next char after ':' */
+		while(isspace((unsigned char)*val)) val++;
+		dict_insert_value(dict, key, val);
+		TRACE("%s : %s", key, val);
+	} else {
+		TRACE("Header not processed: %s", info);
+	}
+
+	free(info);
+	return nitems * size;
+}
+
 channel_op_res_t channel_set_options(channel_t *this,
 					channel_data_t *channel_data,
 					channel_method_t method)
@@ -458,6 +491,24 @@  channel_op_res_t channel_set_options(channel_t *this,
 		goto cleanup;
 	}
 
+	/*
+	 * if the caller wants to parse the headers,
+	 * collect them in a dictionary.
+	 * The caller must provide a valid dictionary
+	 * for it
+	 */
+
+	if (channel_data->headers) {
+		if ((curl_easy_setopt(channel_curl->handle,
+			      CURLOPT_HEADERFUNCTION,
+			      channel_callback_headers) != CURLE_OK) ||
+		    (curl_easy_setopt(channel_curl->handle, CURLOPT_HEADERDATA,
+			      channel_data->headers) != CURLE_OK)) {
+			result = CHANNEL_EINIT;
+			goto cleanup;
+		}
+	}
+
 	if (channel_data->strictssl == true) {
 		if ((curl_easy_setopt(channel_curl->handle,
 				      CURLOPT_SSL_VERIFYHOST,
diff --git a/include/channel_curl.h b/include/channel_curl.h
index 36e92ad..32b0f17 100644
--- a/include/channel_curl.h
+++ b/include/channel_curl.h
@@ -64,4 +64,5 @@  typedef struct {
 	struct swupdate_digest *dgst;
 	char sha1hash[SHA_DIGEST_LENGTH * 2 + 1];
 	sourcetype source;
+	struct dict *headers;
 } channel_data_t;