[vlc-devel] [PATCH 11/14] contrib: patch libupnp to expose HTTP headers

Alaric Senat dev.asenat at posteo.net
Fri Mar 19 11:40:06 UTC 2021


This patch exposes the extra unrecognized HTTP headers to the upnp API
ActionRequest interface, thus allowing the upnp server module to adapt
its behavior depending on what client he's responding to.

Upstreamed to libupnp by 508930f56cca885d82b94e6e7abf588d0e46faa4
---
 contrib/src/upnp/extra-http-headers.patch | 290 ++++++++++++++++++++++
 contrib/src/upnp/rules.mak                |   1 +
 2 files changed, 291 insertions(+)
 create mode 100644 contrib/src/upnp/extra-http-headers.patch

diff --git a/contrib/src/upnp/extra-http-headers.patch b/contrib/src/upnp/extra-http-headers.patch
new file mode 100644
index 0000000000..207c314ef9
--- /dev/null
+++ b/contrib/src/upnp/extra-http-headers.patch
@@ -0,0 +1,290 @@
+From efc92015f23caa2ad22831d3453d6be7c86ef407 Mon Sep 17 00:00:00 2001
+From: Alaric Senat <dev.asenat at posteo.net>
+Date: Thu, 4 Mar 2021 11:35:11 +0100
+Subject: action_request: Expose extra http headers
+
+Api users might want to process some http headers that are not
+recognized by the pupnp webserver. A similar behavior is already
+implemented for the upnp http io callbacks in the FileInfo interface.
+---
+ upnp/inc/ActionRequest.h              |  1 +
+ upnp/src/genlib/net/http/httpparser.c | 79 +++++++++++++++++++++++++++
+ upnp/src/genlib/net/http/webserver.c  | 69 +----------------------
+ upnp/src/inc/httpparser.h             | 30 ++++++++++
+ upnp/src/soap/soap_device.c           |  9 +++
+ 5 files changed, 121 insertions(+), 67 deletions(-)
+
+diff --git a/upnp/inc/ActionRequest.h b/upnp/inc/ActionRequest.h
+index f889fa1..4e1e376 100644
+--- a/upnp/inc/ActionRequest.h
++++ b/upnp/inc/ActionRequest.h
+@@ -29,6 +29,7 @@
+ 	EXPAND_CLASS_MEMBER_INT(CLASS, SoapHeader, IXML_Document *) \
+ 	EXPAND_CLASS_MEMBER_BUFFER(CLASS, CtrlPtIPAddr, struct sockaddr_storage) \
+ 	EXPAND_CLASS_MEMBER_STRING(CLASS, Os) \
++	EXPAND_CLASS_MEMBER_LIST(CLASS, ExtraHeadersList) \
+ 
+ #include "TemplateInclude.h"
+ 
+diff --git a/upnp/src/genlib/net/http/httpparser.c b/upnp/src/genlib/net/http/httpparser.c
+index 4f8da7a..f03e365 100644
+--- a/upnp/src/genlib/net/http/httpparser.c
++++ b/upnp/src/genlib/net/http/httpparser.c
+@@ -46,6 +46,8 @@
+ #include "httpparser.h"
+ #include "statcodes.h"
+ #include "unixutil.h"
++#include "ExtraHeaders.h"
++#include "list.h"
+ #include "upnpdebug.h"
+ 
+ #include <assert.h>
+@@ -2194,6 +2196,83 @@ const char *method_to_str(http_method_t method)
+     return index == -1 ? NULL : Http_Method_Table[index].name;
+ }
+ 
++/************************************************************************
++* Function: parser_get_unknown_headers
++*
++* Parameters:
++*	IN http_message_t req ;		HTTP request
++*	INOUT UpnpListHead list ;   Extra headers list
++*
++* Description: Append unknown HTTP headers to the list.
++*
++* Returns:
++*	HTTP_OK
++*	HTTP_INTERNAL_SERVER_ERROR
++************************************************************************/
++int parser_get_unknown_headers(http_message_t *req, UpnpListHead *list)
++{
++	http_header_t *header;
++	ListNode *node;
++	int index;
++	UpnpExtraHeaders *extraHeader;
++	UpnpListHead *extraHeaderNode;
++
++	node = ListHead(&req->headers);
++	while (node != NULL) {
++		header = (http_header_t *)node->item;
++		/* find header type. */
++		index = map_str_to_int((const char *)header->name.buf,
++			header->name.length,
++			Http_Header_Names,
++			NUM_HTTP_HEADER_NAMES,
++			0);
++		if (index < 0) {
++			extraHeader = UpnpExtraHeaders_new();
++			if (!extraHeader) {
++				free_http_headers_list(list);
++				return HTTP_INTERNAL_SERVER_ERROR;
++			}
++			extraHeaderNode =
++				(UpnpListHead *)UpnpExtraHeaders_get_node(
++					extraHeader);
++			UpnpListInsert(list, UpnpListEnd(list), extraHeaderNode);
++			UpnpExtraHeaders_strncpy_name(extraHeader,
++				header->name.buf,
++				header->name.length);
++			UpnpExtraHeaders_strncpy_value(extraHeader,
++				header->value.buf,
++				header->value.length);
++		}
++		node = ListNext(&req->headers, node);
++	}
++
++	return HTTP_OK;
++}
++
++/************************************************************************
++* Function: free_http_headers_list
++*
++* Parameters:
++*	IN UpnpListHead list ;   Extra headers list
++*
++* Description: Free all extra headers nodes in the given list.
++*
++* Returns:
++*	HTTP_OK
++*	HTTP_INTERNAL_SERVER_ERROR
++************************************************************************/
++void free_http_headers_list(UpnpListHead *list)
++{
++	UpnpListIter pos;
++	UpnpExtraHeaders *extra;
++
++	for (pos = UpnpListBegin(list);
++		pos != UpnpListEnd(list);) {
++		extra = (UpnpExtraHeaders *)pos;
++		pos = UpnpListErase(list, pos);
++		UpnpExtraHeaders_delete(extra);
++	}
++}
+ 
+ #ifdef DEBUG
+ void print_http_headers(http_message_t *hmsg)
+diff --git a/upnp/src/genlib/net/http/webserver.c b/upnp/src/genlib/net/http/webserver.c
+index 09bc97e..6fb7351 100644
+--- a/upnp/src/genlib/net/http/webserver.c
++++ b/upnp/src/genlib/net/http/webserver.c
+@@ -1054,71 +1054,6 @@ static int CheckOtherHTTPHeaders(
+ 	return RetCode;
+ }
+ 
+-static void FreeExtraHTTPHeaders(
+-	/*! [in] extra HTTP headers to free. */
+-	UpnpListHead *extraHeadersList)
+-{
+-	UpnpListIter pos;
+-	UpnpExtraHeaders *extra;
+-
+-	for (pos = UpnpListBegin(extraHeadersList);
+-		pos != UpnpListEnd(extraHeadersList);) {
+-		extra = (UpnpExtraHeaders *)pos;
+-		pos = UpnpListErase(extraHeadersList, pos);
+-		UpnpExtraHeaders_delete(extra);
+-	}
+-}
+-
+-/*!
+- * \brief Build an array of unrecognized headers.
+- *
+- * \return nothing
+- */
+-static int ExtraHTTPHeaders(
+-	/*! [in] HTTP Request message. */
+-	http_message_t *Req,
+-	UpnpListHead *extraHeadersList)
+-{
+-	http_header_t *header;
+-	ListNode *node;
+-	int index;
+-	UpnpExtraHeaders *extraHeader;
+-	UpnpListHead *extraHeaderNode;
+-
+-	node = ListHead(&Req->headers);
+-	while (node != NULL) {
+-		header = (http_header_t *)node->item;
+-		/* find header type. */
+-		index = map_str_to_int((const char *)header->name.buf,
+-			header->name.length,
+-			Http_Header_Names,
+-			NUM_HTTP_HEADER_NAMES,
+-			0);
+-		if (index < 0) {
+-			extraHeader = UpnpExtraHeaders_new();
+-			if (!extraHeader) {
+-				FreeExtraHTTPHeaders(extraHeadersList);
+-				return HTTP_INTERNAL_SERVER_ERROR;
+-			}
+-			extraHeaderNode =
+-				(UpnpListHead *)UpnpExtraHeaders_get_node(
+-					extraHeader);
+-			UpnpListInsert(extraHeadersList,
+-				UpnpListEnd(extraHeadersList),
+-				extraHeaderNode);
+-			UpnpExtraHeaders_strncpy_name(extraHeader,
+-				header->name.buf,
+-				header->name.length);
+-			UpnpExtraHeaders_strncpy_value(extraHeader,
+-				header->value.buf,
+-				header->value.length);
+-		}
+-		node = ListNext(&Req->headers, node);
+-	}
+-
+-	return HTTP_OK;
+-}
+-
+ /*!
+  * \brief Processes the request and returns the result in the output parameters.
+  *
+@@ -1227,7 +1162,7 @@ static int process_request(
+ 	}
+ 	if (using_virtual_dir) {
+ 		if (req->method != HTTPMETHOD_POST) {
+-			if ((code = ExtraHTTPHeaders(req,
++			if ((code = parser_get_unknown_headers(req,
+ 				     (UpnpListHead *)
+ 					     UpnpFileInfo_get_ExtraHeadersList(
+ 						     finfo))) != HTTP_OK) {
+@@ -1509,7 +1444,7 @@ static int process_request(
+ 
+ error_handler:
+ 	free(request_doc);
+-	FreeExtraHTTPHeaders(
++	free_http_headers_list(
+ 		(UpnpListHead *)UpnpFileInfo_get_ExtraHeadersList(finfo));
+ 	UpnpFileInfo_delete(finfo);
+ 	if (err_code != HTTP_OK && alias_grabbed) {
+diff --git a/upnp/src/inc/httpparser.h b/upnp/src/inc/httpparser.h
+index 99c3f2e..8cac3a7 100644
+--- a/upnp/src/inc/httpparser.h
++++ b/upnp/src/inc/httpparser.h
+@@ -419,6 +419,36 @@ parse_status_t parser_get_entity_read_method(http_parser_t *parser);
+ parse_status_t parser_append(
+ 	http_parser_t *parser, const char *buf, size_t buf_length);
+ 
++/************************************************************************
++* Function: parser_get_unknown_headers
++*
++* Parameters:
++*	IN http_message_t req ;		HTTP request
++*	INOUT UpnpListHead list ;   Extra headers list
++*
++* Description: Append unknown HTTP headers to the list.
++*
++* Returns:
++*	HTTP_OK
++*	HTTP_INTERNAL_SERVER_ERROR
++************************************************************************/
++
++int parser_get_unknown_headers(http_message_t *req, UpnpListHead *list);
++
++/************************************************************************
++* Function: free_http_headers_list
++*
++* Parameters:
++*	IN UpnpListHead list ;   Extra headers list
++*
++* Description: Free all extra headers nodes in the given list.
++*
++* Returns:
++*	HTTP_OK
++*	HTTP_INTERNAL_SERVER_ERROR
++************************************************************************/
++void free_http_headers_list(UpnpListHead *list);
++
+ /************************************************************************
+  * Function: matchstr
+  *
+diff --git a/upnp/src/soap/soap_device.c b/upnp/src/soap/soap_device.c
+index cd2ad38..e0fb1bd 100644
+--- a/upnp/src/soap/soap_device.c
++++ b/upnp/src/soap/soap_device.c
+@@ -429,6 +429,13 @@ static void handle_invoke_action(
+ 		UpnpActionRequest_strncpy_Os(action, hdr_value.buf, hdr_value.length);
+ 	}
+ 
++	if ((err_code = parser_get_unknown_headers(request,
++		     (UpnpListHead *)UpnpActionRequest_get_ExtraHeadersList(
++			     action))) != HTTP_OK) {
++		err_code = SOAP_ACTION_FAILED;
++		goto error_handler;
++	}
++
+ 	UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Calling Callback\n");
+ 	soap_info->callback(
+ 		UPNP_CONTROL_ACTION_REQUEST, action, soap_info->cookie);
+@@ -457,6 +464,8 @@ error_handler:
+ 	ixmlDocument_free(actionResultDoc);
+ 	ixmlDocument_free(actionRequestDoc);
+ 	ixmlFreeDOMString(act_node);
++	free_http_headers_list(
++		(UpnpListHead *)UpnpActionRequest_get_ExtraHeadersList(action));
+ 	/* restore */
+ 	action_name.buf[action_name.length] = save_char;
+ 	if (err_code != 0)
+-- 
+2.29.2
+
diff --git a/contrib/src/upnp/rules.mak b/contrib/src/upnp/rules.mak
index 9e5afb2fd9..1cc6bce33c 100644
--- a/contrib/src/upnp/rules.mak
+++ b/contrib/src/upnp/rules.mak
@@ -44,6 +44,7 @@ ifdef HAVE_WIN32
 endif
 	$(APPLY) $(SRC)/upnp/miniserver.patch
 	$(APPLY) $(SRC)/upnp/upnp-no-debugfile.patch
+	$(APPLY) $(SRC)/upnp/extra-http-headers.patch
 	$(UPDATE_AUTOCONFIG) && cd $(UNPACK_DIR) && mv config.guess config.sub build-aux/
 	$(MOVE)
 
-- 
2.29.2



More information about the vlc-devel mailing list