diff mbox series

[15/29] channel_curl: allow an external callback for headers

Message ID 20211011112156.44192-16-sbabic@denx.de
State Changes Requested
Headers show
Series DELTA Update | expand

Commit Message

Stefano Babic Oct. 11, 2021, 11:21 a.m. UTC
Headers are handled automatically by the channel. Add an optional
callback that the channel can call to handle the headers.

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

Patch

diff --git a/corelib/channel_curl.c b/corelib/channel_curl.c
index 20323b7..9af9c39 100644
--- a/corelib/channel_curl.c
+++ b/corelib/channel_curl.c
@@ -452,36 +452,43 @@  static size_t channel_callback_headers(char *buffer, size_t size, size_t nitems,
 {
 	channel_data_t *channel_data = (channel_data_t *)userdata;
 	struct dict *dict = channel_data->received_headers;
-	char *info = malloc(size * nitems + 1);
+	char *info;
 	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++;
-		/* Remove '\n', '\r', and '\r\n' from header's value. */
-		*strchrnul(val, '\r') = '\0';
-		*strchrnul(val, '\n') = '\0';
-		/* For multiple same-key headers, only the last is saved. */
-		dict_set_value(dict, key, val);
-		TRACE("Header processed: %s : %s", key, val);
-	} else {
-		TRACE("Header not processed: '%s'", info);
+	if (dict) {
+		info = malloc(size * nitems + 1);
+		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++;
+			/* Remove '\n', '\r', and '\r\n' from header's value. */
+			*strchrnul(val, '\r') = '\0';
+			*strchrnul(val, '\n') = '\0';
+			/* For multiple same-key headers, only the last is saved. */
+			dict_set_value(dict, key, val);
+			TRACE("Header processed: %s : %s", key, val);
+		} else {
+			TRACE("Header not processed: '%s'", info);
+		}
+
+		free(info);
 	}
 
-	free(info);
+	if (channel_data->headers)
+		return channel_data->headers(buffer, size, nitems, userdata);
+
 	return nitems * size;
 }
 
@@ -608,7 +615,7 @@  channel_op_res_t channel_set_options(channel_t *this, channel_data_t *channel_da
 		goto cleanup;
 	}
 
-	if (channel_data->received_headers) {
+	if (channel_data->received_headers || channel_data->headers) {
 		/*
 		 * Setup supply request and receive reply HTTP headers.
 		 * A LIST_INIT()'d dictionary is expected at channel_data->headers.
@@ -619,7 +626,7 @@  channel_op_res_t channel_set_options(channel_t *this, channel_data_t *channel_da
 			      CURLOPT_HEADERFUNCTION,
 			      channel_callback_headers) != CURLE_OK) ||
 		    (curl_easy_setopt(channel_curl->handle, CURLOPT_HEADERDATA,
-			      channel_data->received_headers) != CURLE_OK)) {
+			      channel_data) != CURLE_OK)) {
 			result = CHANNEL_EINIT;
 			goto cleanup;
 		}
diff --git a/include/channel_curl.h b/include/channel_curl.h
index fe68a99..456367d 100644
--- a/include/channel_curl.h
+++ b/include/channel_curl.h
@@ -71,6 +71,8 @@  typedef struct {
 	bool nofollow;
 	size_t (*dwlwrdata)(char *streamdata, size_t size, size_t nmemb,
 				   void *data);
+	size_t (*headers)(char *streamdata, size_t size, size_t nmemb,
+				   void *data);
 	struct swupdate_digest *dgst;
 	char sha1hash[SWUPDATE_SHA_DIGEST_LENGTH * 2 + 1];
 	sourcetype source;