aboutsummaryrefslogtreecommitdiffstats
path: root/library/HTTP_Adapter.ttcn
diff options
context:
space:
mode:
Diffstat (limited to 'library/HTTP_Adapter.ttcn')
-rw-r--r--library/HTTP_Adapter.ttcn281
1 files changed, 281 insertions, 0 deletions
diff --git a/library/HTTP_Adapter.ttcn b/library/HTTP_Adapter.ttcn
new file mode 100644
index 00000000..d970416e
--- /dev/null
+++ b/library/HTTP_Adapter.ttcn
@@ -0,0 +1,281 @@
+module HTTP_Adapter {
+
+/* HTTP Adapter component, originally part of Integration Tests for osmo-remsim-server
+ * (C) 2019 by Harald Welte <laforge@gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This test suite tests osmo-remsim-server by attaching to the external interfaces
+ * such as RSPRO for simulated clients + bankds and RSRES (REST backend interface).
+ */
+
+import from HTTPmsg_Types all;
+import from HTTPmsg_PortType all;
+import from Native_Functions all;
+
+type component http_CT {
+ port HTTPmsg_PT HTTP;
+ /* double underscore to have "g_pars" available on components extending this one: */
+ var HTTP_Adapter_Params g_http_pars;
+};
+
+type record HTTP_Adapter_Params {
+ charstring http_host,
+ integer http_port,
+ boolean use_ssl
+};
+
+function f_http_init(HTTP_Adapter_Params pars) runs on http_CT {
+ map(self:HTTP, system:HTTP);
+ g_http_pars := pars;
+}
+
+template (value) Connect ts_HTTP_Connect(template (value) charstring hostname,
+ template (value) integer http_port := 80,
+ template (value) boolean use_ssl := false) := {
+ hostname := hostname,
+ portnumber := http_port,
+ use_ssl := use_ssl
+}
+template (value) Close ts_HTTP_Close(template (omit) integer client_id := omit) := { client_id := client_id };
+
+/* 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) octetstring binary_body := omit,
+ template (omit) charstring host := omit,
+ HeaderLines custom_hdr := { })
+return template (value) HeaderLines {
+ var HeaderLines hdr := { };
+
+ /* Make sure we never use body or binary_body at the same time */
+ if (not istemplatekind(body, "omit") and not istemplatekind(binary_body, "omit")) {
+ setverdict(fail, "use wither (ascii) body or binary_body");
+ }
+
+ /* 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))))};
+ }
+ else if (not istemplatekind(binary_body, "omit")) {
+ hdr := hdr & {valueof(ts_HeaderLine("Content-Length", int2str(lengthof(binary_body))))};
+ }
+
+ return f_overlay_HTTP_Header(hdr, custom_hdr);
+}
+
+function f_ts_body_or_empty(template (omit) charstring body) return template (value) charstring {
+ if (istemplatekind(body, "omit")) {
+ return "";
+ }
+ return body;
+}
+
+template (value) HTTPMessage ts_HTTP_Req(charstring url,
+ charstring method := "GET",
+ template (omit) charstring body := omit,
+ integer v_maj := 1, integer v_min := 1,
+ charstring host,
+ HeaderLines custom_hdr := { },
+ template (omit) integer client_id := omit) := {
+ request := {
+ client_id := client_id,
+ method := method,
+ uri := url,
+ version_major := v_maj,
+ version_minor := v_min,
+ header := f_ts_HTTP_Header(body, omit, host, custom_hdr),
+ body := f_ts_body_or_empty(body)
+ }
+}
+
+function f_ts_body_or_empty_bin(template (omit) octetstring body) return template (value) octetstring {
+ if (istemplatekind(body, "omit")) {
+ return ''O;
+ }
+ return body;
+}
+
+template (value) HTTPMessage ts_HTTP_Req_Bin(charstring url,
+ charstring method := "GET",
+ template (omit) octetstring body := omit,
+ integer v_maj := 1, integer v_min := 1,
+ charstring host,
+ HeaderLines custom_hdr := { },
+ template (omit) integer client_id := omit) := {
+ request_binary := {
+ client_id := client_id,
+ method := method,
+ uri := url,
+ version_major := v_maj,
+ version_minor := v_min,
+ header := f_ts_HTTP_Header(omit, body, host, custom_hdr),
+ body := f_ts_body_or_empty_bin(body)
+ }
+}
+
+
+template HTTPMessage tr_HTTP_Resp(template integer sts := ?) := {
+ response := {
+ client_id := ?,
+ version_major := ?,
+ version_minor := ?,
+ statuscode := sts,
+ statustext := ?,
+ header := ?,
+ body := ?
+ }
+};
+
+template HTTPMessage tr_HTTP_Resp_Bin(template integer sts := ?) := {
+ response_binary := {
+ client_id := ?,
+ version_major := ?,
+ version_minor := ?,
+ statuscode := sts,
+ statustext := ?,
+ header := ?,
+ body := ?
+ }
+};
+
+template HTTPMessage tr_HTTP_Resp2xx := tr_HTTP_Resp((200..299));
+
+function f_http_tx_request(charstring url, charstring method := "GET",
+ template charstring body := omit,
+ template octetstring binary_body := omit,
+ HeaderLines custom_hdr := { },
+ float tout := 2.0,
+ template integer client_id := omit)
+runs on http_CT {
+ var Connect_result rc;
+ timer T := tout;
+ var template integer use_client_id := omit;
+
+ /* In case the caller didn't specify a client_id, we will create a new connection. */
+ if (istemplatekind(client_id, "omit")) {
+ HTTP.send(ts_HTTP_Connect(g_http_pars.http_host, g_http_pars.http_port, g_http_pars.use_ssl));
+ T.start;
+ alt {
+ [] HTTP.receive(Connect_result:?) -> value rc;
+ [] HTTP.receive {
+ setverdict(fail, "HTTP connection to client failed");
+ self.stop;
+ }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for completion of HTTP connection");
+ self.stop;
+ }
+ }
+ use_client_id := rc.client_id;
+ } else {
+ use_client_id := client_id;
+ }
+
+ if (not istemplatekind(body, "omit") and istemplatekind(binary_body, "omit")) {
+ /* HTTP message with ASCII content */
+ HTTP.send(ts_HTTP_Req(url, method, body, host := g_http_pars.http_host & ":" & int2str(g_http_pars.http_port),
+ custom_hdr := custom_hdr, client_id := use_client_id));
+ } else if (not istemplatekind(binary_body, "omit") and istemplatekind(body, "omit")) {
+ /* HTTP message with binary content */
+ HTTP.send(ts_HTTP_Req_Bin(url, method, binary_body,
+ host := g_http_pars.http_host & ":" & int2str(g_http_pars.http_port),
+ custom_hdr := custom_hdr, client_id := use_client_id));
+ } else if (istemplatekind(binary_body, "omit") and istemplatekind(body, "omit")) {
+ /* HTTP message without content (e.g. a GET request) */
+ HTTP.send(ts_HTTP_Req(url, method, host := g_http_pars.http_host & ":" & int2str(g_http_pars.http_port),
+ custom_hdr := custom_hdr, client_id := use_client_id));
+ } else {
+ setverdict(fail, "either binary_body or body must be used (a request can contain either ASCII data or binary data, not both!");
+ }
+}
+
+function f_http_rx_response(template HTTPMessage exp := tr_HTTP_Resp2xx,
+ float tout := 2.0,
+ template integer client_id := omit,
+ boolean keep_connection := false)
+runs on http_CT return HTTPMessage {
+ var HTTPMessage resp;
+ timer T := tout;
+ T.start;
+ alt {
+ [] HTTP.receive(exp) -> value resp {
+ setverdict(pass);
+ }
+ [] HTTP.receive(tr_HTTP_Resp) -> value resp {
+ setverdict(fail, "Unexpected HTTP response ", resp);
+ }
+ [] HTTP.receive(tr_HTTP_Resp_Bin) -> value resp {
+ setverdict(fail, "Unexpected (binary) HTTP response ", resp);
+ }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for HTTP response");
+ self.stop;
+ }
+ }
+
+ if (not keep_connection) {
+ HTTP.send(ts_HTTP_Close(client_id));
+ }
+
+ return resp;
+}
+
+/* run a HTTP request and return the response */
+function f_http_transact(charstring url, charstring method := "GET",
+ template (omit) charstring body := omit,
+ template (omit) octetstring binary_body := omit,
+ template HTTPMessage exp := tr_HTTP_Resp2xx,
+ float tout := 2.0, HeaderLines custom_hdr := { },
+ template integer client_id := omit,
+ boolean keep_connection := false)
+runs on http_CT return HTTPMessage {
+ f_http_tx_request(url, method, body, binary_body, custom_hdr, tout, client_id);
+ return f_http_rx_response(exp, tout, client_id, keep_connection);
+}
+
+function f_http_client_id_from_http_response(template HTTPMessage response_http) return template integer {
+ if (ispresent(response_http.response_binary)) {
+ return response_http.response_binary.client_id;
+ } else if (ispresent(response_http.response)) {
+ return response_http.response.client_id;
+ }
+
+ return omit;
+}
+
+}