1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-http-client 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * This demonstrates the a minimal http client using lws. 10d4afb5ceSopenharmony_ci * 11d4afb5ceSopenharmony_ci * It visits https://warmcat.com/ and receives the html page there. You 12d4afb5ceSopenharmony_ci * can dump the page data by changing the #if 0 below. 13d4afb5ceSopenharmony_ci */ 14d4afb5ceSopenharmony_ci 15d4afb5ceSopenharmony_ci#include <libwebsockets.h> 16d4afb5ceSopenharmony_ci#include <string.h> 17d4afb5ceSopenharmony_ci#include <signal.h> 18d4afb5ceSopenharmony_ci 19d4afb5ceSopenharmony_cistatic int interrupted, bad = 1, status; 20d4afb5ceSopenharmony_cistatic struct lws *client_wsi; 21d4afb5ceSopenharmony_ci 22d4afb5ceSopenharmony_cistatic int 23d4afb5ceSopenharmony_cicallback_http(struct lws *wsi, enum lws_callback_reasons reason, 24d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 25d4afb5ceSopenharmony_ci{ 26d4afb5ceSopenharmony_ci uint8_t buf[1280]; 27d4afb5ceSopenharmony_ci union lws_tls_cert_info_results *ci = 28d4afb5ceSopenharmony_ci (union lws_tls_cert_info_results *)buf; 29d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_CTIME_R) 30d4afb5ceSopenharmony_ci char date[32]; 31d4afb5ceSopenharmony_ci#endif 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci switch (reason) { 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci /* because we are protocols[0] ... */ 36d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 37d4afb5ceSopenharmony_ci lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", 38d4afb5ceSopenharmony_ci in ? (char *)in : "(null)"); 39d4afb5ceSopenharmony_ci client_wsi = NULL; 40d4afb5ceSopenharmony_ci break; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: 43d4afb5ceSopenharmony_ci status = (int)lws_http_client_http_response(wsi); 44d4afb5ceSopenharmony_ci lwsl_notice("lws_http_client_http_response %d\n", status); 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, 47d4afb5ceSopenharmony_ci ci, sizeof(buf) - sizeof(*ci))) 48d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert CN : %s\n", ci->ns.name); 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_ISSUER_NAME, 51d4afb5ceSopenharmony_ci ci, sizeof(ci->ns.name))) 52d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert issuer : %s\n", ci->ns.name); 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_FROM, 55d4afb5ceSopenharmony_ci ci, 0)) 56d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_CTIME_R) 57d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert Valid from: %s", 58d4afb5ceSopenharmony_ci ctime_r(&ci->time, date)); 59d4afb5ceSopenharmony_ci#else 60d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert Valid from: %s", 61d4afb5ceSopenharmony_ci ctime(&ci->time)); 62d4afb5ceSopenharmony_ci#endif 63d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_TO, 64d4afb5ceSopenharmony_ci ci, 0)) 65d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_CTIME_R) 66d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert Valid to : %s", 67d4afb5ceSopenharmony_ci ctime_r(&ci->time, date)); 68d4afb5ceSopenharmony_ci#else 69d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert Valid to : %s", 70d4afb5ceSopenharmony_ci ctime(&ci->time)); 71d4afb5ceSopenharmony_ci#endif 72d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_USAGE, 73d4afb5ceSopenharmony_ci ci, 0)) 74d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert usage bits: 0x%x\n", ci->usage); 75d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, 76d4afb5ceSopenharmony_ci LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY, 77d4afb5ceSopenharmony_ci ci, sizeof(buf) - sizeof(*ci))) { 78d4afb5ceSopenharmony_ci lwsl_notice(" Peer Cert public key:\n"); 79d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ci->ns.name, (unsigned int)ci->ns.len); 80d4afb5ceSopenharmony_ci } 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID, 83d4afb5ceSopenharmony_ci ci, 0)) { 84d4afb5ceSopenharmony_ci lwsl_notice(" AUTHORITY_KEY_ID\n"); 85d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len); 86d4afb5ceSopenharmony_ci } 87d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER, 88d4afb5ceSopenharmony_ci ci, 0)) { 89d4afb5ceSopenharmony_ci lwsl_notice(" AUTHORITY_KEY_ID ISSUER\n"); 90d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len); 91d4afb5ceSopenharmony_ci } 92d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL, 93d4afb5ceSopenharmony_ci ci, 0)) { 94d4afb5ceSopenharmony_ci lwsl_notice(" AUTHORITY_KEY_ID SERIAL\n"); 95d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len); 96d4afb5ceSopenharmony_ci } 97d4afb5ceSopenharmony_ci if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID, 98d4afb5ceSopenharmony_ci ci, 0)) { 99d4afb5ceSopenharmony_ci lwsl_notice(" AUTHORITY_KEY_ID SUBJECT_KEY_ID\n"); 100d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len); 101d4afb5ceSopenharmony_ci } 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci break; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci /* chunks of chunked content, with header removed */ 106d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: 107d4afb5ceSopenharmony_ci lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len); 108d4afb5ceSopenharmony_ci#if 0 /* enable to dump the html */ 109d4afb5ceSopenharmony_ci { 110d4afb5ceSopenharmony_ci const char *p = in; 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci while (len--) 113d4afb5ceSopenharmony_ci if (*p < 0x7f) 114d4afb5ceSopenharmony_ci putchar(*p++); 115d4afb5ceSopenharmony_ci else 116d4afb5ceSopenharmony_ci putchar('.'); 117d4afb5ceSopenharmony_ci } 118d4afb5ceSopenharmony_ci#endif 119d4afb5ceSopenharmony_ci return 0; /* don't passthru */ 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci /* uninterpreted http content */ 122d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: 123d4afb5ceSopenharmony_ci { 124d4afb5ceSopenharmony_ci char buffer[1024 + LWS_PRE]; 125d4afb5ceSopenharmony_ci char *px = buffer + LWS_PRE; 126d4afb5ceSopenharmony_ci int lenx = sizeof(buffer) - LWS_PRE; 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci if (lws_http_client_read(wsi, &px, &lenx) < 0) 129d4afb5ceSopenharmony_ci return -1; 130d4afb5ceSopenharmony_ci } 131d4afb5ceSopenharmony_ci return 0; /* don't passthru */ 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_ci case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: 134d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); 135d4afb5ceSopenharmony_ci client_wsi = NULL; 136d4afb5ceSopenharmony_ci bad = status != 200; 137d4afb5ceSopenharmony_ci lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ 138d4afb5ceSopenharmony_ci break; 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_CLIENT_HTTP: 141d4afb5ceSopenharmony_ci client_wsi = NULL; 142d4afb5ceSopenharmony_ci bad = status != 200; 143d4afb5ceSopenharmony_ci lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ 144d4afb5ceSopenharmony_ci break; 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci default: 147d4afb5ceSopenharmony_ci break; 148d4afb5ceSopenharmony_ci } 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 151d4afb5ceSopenharmony_ci} 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_cistatic const struct lws_protocols protocols[] = { 154d4afb5ceSopenharmony_ci { 155d4afb5ceSopenharmony_ci "http", 156d4afb5ceSopenharmony_ci callback_http, 157d4afb5ceSopenharmony_ci 0, 0, 0, NULL, 0 158d4afb5ceSopenharmony_ci }, 159d4afb5ceSopenharmony_ci LWS_PROTOCOL_LIST_TERM 160d4afb5ceSopenharmony_ci}; 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_cistatic void 163d4afb5ceSopenharmony_cisigint_handler(int sig) 164d4afb5ceSopenharmony_ci{ 165d4afb5ceSopenharmony_ci interrupted = 1; 166d4afb5ceSopenharmony_ci} 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 169d4afb5ceSopenharmony_ci{ 170d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 171d4afb5ceSopenharmony_ci struct lws_client_connect_info i; 172d4afb5ceSopenharmony_ci struct lws_context *context; 173d4afb5ceSopenharmony_ci const char *p; 174d4afb5ceSopenharmony_ci int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE 175d4afb5ceSopenharmony_ci /* 176d4afb5ceSopenharmony_ci * For LLL_ verbosity above NOTICE to be built into lws, 177d4afb5ceSopenharmony_ci * lws must have been configured and built with 178d4afb5ceSopenharmony_ci * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE 179d4afb5ceSopenharmony_ci * 180d4afb5ceSopenharmony_ci * | LLL_INFO | LLL_PARSER | LLL_HEADER | LLL_EXT | 181d4afb5ceSopenharmony_ci * LLL_CLIENT | LLL_LATENCY | LLL_DEBUG 182d4afb5ceSopenharmony_ci */ ; 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 187d4afb5ceSopenharmony_ci logs = atoi(p); 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 190d4afb5ceSopenharmony_ci lwsl_user("LWS minimal http client [<-d <verbosity>] [-l] [--h1]\n"); 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 193d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 194d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ 195d4afb5ceSopenharmony_ci info.protocols = protocols; 196d4afb5ceSopenharmony_ci /* 197d4afb5ceSopenharmony_ci * since we know this lws context is only ever going to be used with 198d4afb5ceSopenharmony_ci * one client wsis / fds / sockets at a time, let lws know it doesn't 199d4afb5ceSopenharmony_ci * have to use the default allocations for fd tables up to ulimit -n. 200d4afb5ceSopenharmony_ci * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we 201d4afb5ceSopenharmony_ci * will use. 202d4afb5ceSopenharmony_ci */ 203d4afb5ceSopenharmony_ci info.fd_limit_per_thread = 1 + 1 + 1; 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 206d4afb5ceSopenharmony_ci /* 207d4afb5ceSopenharmony_ci * OpenSSL uses the system trust store. mbedTLS has to be told which 208d4afb5ceSopenharmony_ci * CA to trust explicitly. 209d4afb5ceSopenharmony_ci */ 210d4afb5ceSopenharmony_ci info.client_ssl_ca_filepath = "./warmcat.com.cer"; 211d4afb5ceSopenharmony_ci#endif 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci context = lws_create_context(&info); 214d4afb5ceSopenharmony_ci if (!context) { 215d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 216d4afb5ceSopenharmony_ci return 1; 217d4afb5ceSopenharmony_ci } 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_ci memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */ 220d4afb5ceSopenharmony_ci i.context = context; 221d4afb5ceSopenharmony_ci i.ssl_connection = LCCSCF_USE_SSL; 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-l")) { 224d4afb5ceSopenharmony_ci i.port = 7681; 225d4afb5ceSopenharmony_ci i.address = "localhost"; 226d4afb5ceSopenharmony_ci i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; 227d4afb5ceSopenharmony_ci } else { 228d4afb5ceSopenharmony_ci i.port = 443; 229d4afb5ceSopenharmony_ci i.address = "warmcat.com"; 230d4afb5ceSopenharmony_ci } 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-s"))) 233d4afb5ceSopenharmony_ci i.address = p; 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ci i.path = "/"; 236d4afb5ceSopenharmony_ci i.host = i.address; 237d4afb5ceSopenharmony_ci i.origin = i.address; 238d4afb5ceSopenharmony_ci 239d4afb5ceSopenharmony_ci /* force h1 even if h2 available */ 240d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "--h1")) 241d4afb5ceSopenharmony_ci i.alpn = "http/1.1"; 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci i.method = "GET"; 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci i.protocol = protocols[0].name; 246d4afb5ceSopenharmony_ci i.pwsi = &client_wsi; 247d4afb5ceSopenharmony_ci lws_client_connect_via_info(&i); 248d4afb5ceSopenharmony_ci 249d4afb5ceSopenharmony_ci while (n >= 0 && client_wsi && !interrupted) 250d4afb5ceSopenharmony_ci n = lws_service(context, 0); 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci lws_context_destroy(context); 253d4afb5ceSopenharmony_ci lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci return bad; 256d4afb5ceSopenharmony_ci} 257