summaryrefslogtreecommitdiffstats
path: root/aclk/legacy/aclk_lws_https_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'aclk/legacy/aclk_lws_https_client.c')
-rw-r--r--aclk/legacy/aclk_lws_https_client.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/aclk/legacy/aclk_lws_https_client.c b/aclk/legacy/aclk_lws_https_client.c
new file mode 100644
index 000000000..c1856ed2c
--- /dev/null
+++ b/aclk/legacy/aclk_lws_https_client.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#define ACLK_LWS_HTTPS_CLIENT_INTERNAL
+#include "aclk_lws_https_client.h"
+
+#include "aclk_common.h"
+
+#include "aclk_lws_wss_client.h"
+
+#define SMALL_BUFFER 16
+
+struct simple_hcc_data {
+ char *data;
+ size_t data_size;
+ size_t written;
+ char lws_work_buffer[1024 + LWS_PRE];
+ char *payload;
+ int response_code;
+ int done;
+};
+
+static int simple_https_client_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
+{
+ UNUSED(user);
+ int n;
+ char *ptr;
+ char buffer[SMALL_BUFFER];
+ struct simple_hcc_data *perconn_data = lws_get_opaque_user_data(wsi);
+
+ switch (reason) {
+ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+ debug(D_ACLK, "LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ");
+ if (perconn_data->data_size - 1 - perconn_data->written < len)
+ return 1;
+ memcpy(&perconn_data->data[perconn_data->written], in, len);
+ perconn_data->written += len;
+ return 0;
+ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+ debug(D_ACLK, "LWS_CALLBACK_RECEIVE_CLIENT_HTTP");
+ if(!perconn_data) {
+ error("Missing Per Connect Data");
+ return -1;
+ }
+ n = sizeof(perconn_data->lws_work_buffer) - LWS_PRE;
+ ptr = perconn_data->lws_work_buffer + LWS_PRE;
+ if (lws_http_client_read(wsi, &ptr, &n) < 0)
+ return -1;
+ perconn_data->data[perconn_data->written] = '\0';
+ return 0;
+ case LWS_CALLBACK_WSI_DESTROY:
+ debug(D_ACLK, "LWS_CALLBACK_WSI_DESTROY");
+ if(perconn_data)
+ perconn_data->done = 1;
+ return 0;
+ case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+ debug(D_ACLK, "LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP");
+ if(perconn_data)
+ perconn_data->response_code = lws_http_client_http_response(wsi);
+ return 0;
+ case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+ debug(D_ACLK, "LWS_CALLBACK_CLOSED_CLIENT_HTTP");
+ return 0;
+ case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
+ debug(D_ACLK, "LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS");
+ return 0;
+ case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+ debug(D_ACLK, "LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER");
+ if(perconn_data && perconn_data->payload) {
+ unsigned char **p = (unsigned char **)in, *end = (*p) + len;
+ snprintfz(buffer, SMALL_BUFFER, "%zu", strlen(perconn_data->payload));
+ if (lws_add_http_header_by_token(wsi,
+ WSI_TOKEN_HTTP_CONTENT_LENGTH,
+ (unsigned char *)buffer, strlen(buffer), p, end))
+ return -1;
+ if (lws_add_http_header_by_token(wsi,
+ WSI_TOKEN_HTTP_CONTENT_TYPE,
+ (unsigned char *)ACLK_CONTENT_TYPE_JSON,
+ strlen(ACLK_CONTENT_TYPE_JSON), p, end))
+ return -1;
+ lws_client_http_body_pending(wsi, 1);
+ lws_callback_on_writable(wsi);
+ }
+ return 0;
+ case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
+ debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_WRITEABLE");
+ if(perconn_data && perconn_data->payload) {
+ n = strlen(perconn_data->payload);
+ if(perconn_data->data_size < (size_t)LWS_PRE + n + 1) {
+ error("Buffer given is not big enough");
+ return 1;
+ }
+
+ memcpy(&perconn_data->data[LWS_PRE], perconn_data->payload, n);
+ if(n != lws_write(wsi, (unsigned char*)&perconn_data->data[LWS_PRE], n, LWS_WRITE_HTTP)) {
+ error("lws_write error");
+ perconn_data->data[0] = 0;
+ return 1;
+ }
+ lws_client_http_body_pending(wsi, 0);
+ // clean for subsequent reply read
+ perconn_data->data[0] = 0;
+ }
+ return 0;
+ case LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL:
+ debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL");
+ return 0;
+ case LWS_CALLBACK_WSI_CREATE:
+ debug(D_ACLK, "LWS_CALLBACK_WSI_CREATE");
+ return 0;
+ case LWS_CALLBACK_PROTOCOL_INIT:
+ debug(D_ACLK, "LWS_CALLBACK_PROTOCOL_INIT");
+ return 0;
+ case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL:
+ debug(D_ACLK, "LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL");
+ return 0;
+ case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
+ debug(D_ACLK, "LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED");
+ return 0;
+ case LWS_CALLBACK_GET_THREAD_ID:
+ debug(D_ACLK, "LWS_CALLBACK_GET_THREAD_ID");
+ return 0;
+ case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
+ debug(D_ACLK, "LWS_CALLBACK_EVENT_WAIT_CANCELLED");
+ return 0;
+ case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION:
+ debug(D_ACLK, "LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION");
+ return 0;
+ case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
+ debug(D_ACLK, "LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH");
+ return 0;
+ default:
+ debug(D_ACLK, "Unknown callback %d", (int)reason);
+ return 0;
+ }
+}
+
+static const struct lws_protocols protocols[] = {
+ {
+ "http",
+ simple_https_client_callback,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ { NULL, NULL, 0, 0, 0, 0, 0 }
+};
+
+static void simple_hcc_log_divert(int level, const char *line)
+{
+ UNUSED(level);
+ error("Libwebsockets: %s", line);
+}
+
+int aclk_send_https_request(char *method, char *host, int port, char *url, char *b, size_t b_size, char *payload)
+{
+ info("%s %s", __func__, method);
+
+ struct lws_context_creation_info info;
+ struct lws_client_connect_info i;
+ struct lws_context *context;
+
+ struct simple_hcc_data *data = callocz(1, sizeof(struct simple_hcc_data));
+ data->data = b;
+ data->data[0] = 0;
+ data->data_size = b_size;
+ data->payload = payload;
+
+ int n = 0;
+ time_t timestamp;
+
+ struct lws_vhost *vhost;
+
+ memset(&info, 0, sizeof info);
+
+ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+ info.port = CONTEXT_PORT_NO_LISTEN;
+ info.protocols = protocols;
+
+
+ context = lws_create_context(&info);
+ if (!context) {
+ error("Error creating LWS context");
+ freez(data);
+ return 1;
+ }
+
+ lws_set_log_level(LLL_ERR | LLL_WARN, simple_hcc_log_divert);
+
+ lws_service(context, 0);
+
+ memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+ i.context = context;
+
+#ifdef ACLK_SSL_ALLOW_SELF_SIGNED
+ i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE;
+ info("Disabling SSL certificate checks");
+#else
+ i.ssl_connection = LCCSCF_USE_SSL;
+#endif
+#if defined(HAVE_X509_VERIFY_PARAM_set1_host) && HAVE_X509_VERIFY_PARAM_set1_host == 0
+#warning DISABLING SSL HOSTNAME VALIDATION BECAUSE IT IS NOT AVAILABLE ON THIS SYSTEM.
+ i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+#endif
+
+ i.port = port;
+ i.address = host;
+ i.path = url;
+
+ i.host = i.address;
+ i.origin = i.address;
+ i.method = method;
+ i.opaque_user_data = data;
+ i.alpn = "http/1.1";
+
+ i.protocol = protocols[0].name;
+
+ vhost = lws_get_vhost_by_name(context, "default");
+ if(!vhost)
+ fatal("Could not find the default LWS vhost.");
+
+ //set up proxy
+ aclk_wss_set_proxy(vhost);
+
+ lws_client_connect_via_info(&i);
+
+ // libwebsockets handle connection timeouts already
+ // this adds additional safety in case of bug in LWS
+ timestamp = now_monotonic_sec();
+ while( n >= 0 && !data->done && !netdata_exit) {
+ n = lws_service(context, 0);
+ if( now_monotonic_sec() - timestamp > SEND_HTTPS_REQUEST_TIMEOUT ) {
+ data->data[0] = 0;
+ data->done = 1;
+ error("Servicing LWS took too long.");
+ }
+ }
+
+ lws_context_destroy(context);
+
+ n = data->response_code;
+
+ freez(data);
+ return (n < 200 || n >= 300);
+}