HTTP_Adapter: allow API users to specifiy custom header

At the moment HTTP_Adapter can only make requests with a fixed
pre-defined HTTP header. However, some application may require
additional custom header lines or different values than the ones
specified in the pre-defined HTTP header.

Related: SYS#6824
Change-Id: I115fd14254e0957c0955649aeb47059dc180bf57
diff --git a/library/HTTP_Adapter.ttcn b/library/HTTP_Adapter.ttcn
index 0885f05..b302a80 100644
--- a/library/HTTP_Adapter.ttcn
+++ b/library/HTTP_Adapter.ttcn
@@ -15,6 +15,7 @@
 
 import from HTTPmsg_Types all;
 import from HTTPmsg_PortType all;
+import from Native_Functions all;
 
 type component http_CT {
 	port HTTPmsg_PT HTTP;
@@ -37,24 +38,65 @@
 }
 template (value) Close ts_HTTP_Close := { client_id := omit };
 
-template (value) HeaderLines ts_HTTP_Header(charstring body, charstring host) := {
-	{ header_name := "Host", header_value := host },
-	{ header_name := "Content-Type", header_value := "application/json" },
-	{ header_name := "Content-Length", header_value := int2str(lengthof(body)) }
+/* function to add HeaderLines to a an existing set of HeaderLines. HeaderLines that are already present, are updated. */
+function f_overlay_HTTP_Header(HeaderLines hdr, HeaderLines additional_hdr) return template (value) HeaderLines
+{
+	var integer i;
+	var integer k;
+	var boolean updated;
+
+	for (i := 0; i < lengthof(additional_hdr); i := i+1) {
+		updated := false;
+		for (k := 0; k < lengthof(hdr); k := k+1) {
+			if (f_str_tolower(hdr[k].header_name) == f_str_tolower(additional_hdr[i].header_name)) {
+				hdr[k] := additional_hdr[i];
+				updated := true;
+			}
+		}
+		if (updated == false) {
+			hdr := hdr & { additional_hdr[i] };
+		}
+	}
+
+	return hdr;
+}
+
+template (value) HeaderLine ts_HeaderLine(charstring header_name, charstring header_value) := {
+	header_name := header_name,
+	header_value := header_value
+}
+
+function f_ts_HTTP_Header(template (omit) charstring body := omit,
+			  template (omit) charstring host := omit,
+			  HeaderLines custom_hdr := { })
+return template (value) HeaderLines {
+	var HeaderLines hdr := { };
+
+	/* Build default header */
+	if (not istemplatekind(host, "omit")) {
+		hdr := hdr & {valueof(ts_HeaderLine("Host", valueof(host)))};
+	}
+	hdr := hdr & {{ header_name := "Content-Type", header_value := "application/json" }};
+	if (not istemplatekind(body, "omit")) {
+		hdr := hdr & {valueof(ts_HeaderLine("Content-Length", int2str(lengthof(body))))};
+	}
+
+	return f_overlay_HTTP_Header(hdr, custom_hdr);
 }
 
 template (value) HTTPMessage ts_HTTP_Req(charstring url,
 					 charstring method := "GET",
 					 charstring body := "",
 					 integer v_maj := 1, integer v_min := 1,
-					 charstring host) := {
+					 charstring host,
+					 HeaderLines custom_hdr := { }) := {
 	request := {
 		client_id := omit,
 		method := method,
 		uri := url,
 		version_major := v_maj,
 		version_minor := v_min,
-		header := valueof(ts_HTTP_Header(body, host)),
+		header := valueof(f_ts_HTTP_Header(body, host, custom_hdr)),
 		body := body
 	}
 }
@@ -73,11 +115,12 @@
 
 template HTTPMessage tr_HTTP_Resp2xx := tr_HTTP_Resp((200..299));
 
-function f_http_tx_request(charstring url, charstring method := "GET", charstring body := "")
+function f_http_tx_request(charstring url, charstring method := "GET", charstring body := "",
+			   HeaderLines custom_hdr := { })
 runs on http_CT {
 	HTTP.send(ts_HTTP_Connect(g_http_host, g_http_port));
 	HTTP.receive(Connect_result:?);
-	HTTP.send(ts_HTTP_Req(url, method, body, host := g_http_host & ":" & int2str(g_http_port)));
+	HTTP.send(ts_HTTP_Req(url, method, body, host := g_http_host & ":" & int2str(g_http_port), custom_hdr := custom_hdr));
 }
 
 function f_http_rx_response(template HTTPMessage exp := tr_HTTP_Resp2xx, float tout := 2.0)
@@ -104,9 +147,9 @@
 /* run a HTTP request and return the response */
 function f_http_transact(charstring url, charstring method := "GET",
 			 charstring body := "", template HTTPMessage exp := tr_HTTP_Resp2xx,
-			 float tout := 2.0)
+			 float tout := 2.0, HeaderLines custom_hdr := { })
 runs on http_CT return HTTPMessage {
-	f_http_tx_request(url, method, body);
+	f_http_tx_request(url, method, body, custom_hdr);
 	return f_http_rx_response(exp, tout);
 }