1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-http-server-form-post 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 a minimal http server that performs POST with a couple 10d4afb5ceSopenharmony_ci * of parameters. It dumps the parameters to the console log and redirects 11d4afb5ceSopenharmony_ci * to another page. 12d4afb5ceSopenharmony_ci */ 13d4afb5ceSopenharmony_ci 14d4afb5ceSopenharmony_ci#include <libwebsockets.h> 15d4afb5ceSopenharmony_ci#include <string.h> 16d4afb5ceSopenharmony_ci#include <signal.h> 17d4afb5ceSopenharmony_ci 18d4afb5ceSopenharmony_ci/* 19d4afb5ceSopenharmony_ci * Unlike ws, http is a stateless protocol. This pss only exists for the 20d4afb5ceSopenharmony_ci * duration of a single http transaction. With http/1.1 keep-alive and http/2, 21d4afb5ceSopenharmony_ci * that is unrelated to (shorter than) the lifetime of the network connection. 22d4afb5ceSopenharmony_ci */ 23d4afb5ceSopenharmony_cistruct pss { 24d4afb5ceSopenharmony_ci struct lws_spa *spa; 25d4afb5ceSopenharmony_ci}; 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_cistatic int interrupted, use303; 28d4afb5ceSopenharmony_ci 29d4afb5ceSopenharmony_cistatic const char * const param_names[] = { 30d4afb5ceSopenharmony_ci "text1", 31d4afb5ceSopenharmony_ci "send", 32d4afb5ceSopenharmony_ci}; 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_cienum enum_param_names { 35d4afb5ceSopenharmony_ci EPN_TEXT1, 36d4afb5ceSopenharmony_ci EPN_SEND, 37d4afb5ceSopenharmony_ci}; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_cistatic int 40d4afb5ceSopenharmony_cicallback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, 41d4afb5ceSopenharmony_ci void *in, size_t len) 42d4afb5ceSopenharmony_ci{ 43d4afb5ceSopenharmony_ci struct pss *pss = (struct pss *)user; 44d4afb5ceSopenharmony_ci uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE], *start = &buf[LWS_PRE], 45d4afb5ceSopenharmony_ci *p = start, *end = &buf[sizeof(buf) - 1]; 46d4afb5ceSopenharmony_ci int n; 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ci switch (reason) { 49d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP: 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci /* 52d4afb5ceSopenharmony_ci * Manually report that our form target URL exists 53d4afb5ceSopenharmony_ci * 54d4afb5ceSopenharmony_ci * you can also do this by adding a mount for the form URL 55d4afb5ceSopenharmony_ci * to the protocol with type LWSMPRO_CALLBACK, then no need 56d4afb5ceSopenharmony_ci * to trap LWS_CALLBACK_HTTP. 57d4afb5ceSopenharmony_ci */ 58d4afb5ceSopenharmony_ci 59d4afb5ceSopenharmony_ci if (!strcmp((const char *)in, "/form1")) 60d4afb5ceSopenharmony_ci /* assertively allow it to exist in the URL space */ 61d4afb5ceSopenharmony_ci return 0; 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci /* default to 404-ing the URL if not mounted */ 64d4afb5ceSopenharmony_ci break; 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_BODY: 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci /* create the POST argument parser if not already existing */ 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci if (!pss->spa) { 71d4afb5ceSopenharmony_ci pss->spa = lws_spa_create(wsi, param_names, 72d4afb5ceSopenharmony_ci LWS_ARRAY_SIZE(param_names), 1024, 73d4afb5ceSopenharmony_ci NULL, NULL); /* no file upload */ 74d4afb5ceSopenharmony_ci if (!pss->spa) 75d4afb5ceSopenharmony_ci return -1; 76d4afb5ceSopenharmony_ci } 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci /* let it parse the POST data */ 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci if (lws_spa_process(pss->spa, in, (int)len)) 81d4afb5ceSopenharmony_ci return -1; 82d4afb5ceSopenharmony_ci break; 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_CLIENT_HTTP: 85d4afb5ceSopenharmony_ci if (pss->spa && lws_spa_destroy(pss->spa)) 86d4afb5ceSopenharmony_ci return -1; 87d4afb5ceSopenharmony_ci break; 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_BODY_COMPLETION: 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci /* inform the spa no more payload data coming */ 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); 94d4afb5ceSopenharmony_ci lws_spa_finalize(pss->spa); 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci /* we just dump the decoded things to the log */ 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci if (pss->spa) 99d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) { 100d4afb5ceSopenharmony_ci if (!lws_spa_get_string(pss->spa, n)) 101d4afb5ceSopenharmony_ci lwsl_user("%s: undefined\n", param_names[n]); 102d4afb5ceSopenharmony_ci else 103d4afb5ceSopenharmony_ci lwsl_user("%s: (len %d) '%s'\n", 104d4afb5ceSopenharmony_ci param_names[n], 105d4afb5ceSopenharmony_ci lws_spa_get_length(pss->spa, n), 106d4afb5ceSopenharmony_ci lws_spa_get_string(pss->spa, n)); 107d4afb5ceSopenharmony_ci } 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci /* 110d4afb5ceSopenharmony_ci * Our response is to redirect to a static page. We could 111d4afb5ceSopenharmony_ci * have generated a dynamic html page here instead. 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if (lws_http_redirect(wsi, use303 ? HTTP_STATUS_SEE_OTHER : 115d4afb5ceSopenharmony_ci HTTP_STATUS_MOVED_PERMANENTLY, 116d4afb5ceSopenharmony_ci (unsigned char *)"after-form1.html", 117d4afb5ceSopenharmony_ci 16, &p, end) < 0) 118d4afb5ceSopenharmony_ci return -1; 119d4afb5ceSopenharmony_ci break; 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_DROP_PROTOCOL: 122d4afb5ceSopenharmony_ci /* called when our wsi user_space is going to be destroyed */ 123d4afb5ceSopenharmony_ci if (pss->spa) { 124d4afb5ceSopenharmony_ci lws_spa_destroy(pss->spa); 125d4afb5ceSopenharmony_ci pss->spa = NULL; 126d4afb5ceSopenharmony_ci } 127d4afb5ceSopenharmony_ci break; 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci default: 130d4afb5ceSopenharmony_ci break; 131d4afb5ceSopenharmony_ci } 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 134d4afb5ceSopenharmony_ci} 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_cistatic struct lws_protocols protocols[] = { 137d4afb5ceSopenharmony_ci { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 }, 138d4afb5ceSopenharmony_ci LWS_PROTOCOL_LIST_TERM 139d4afb5ceSopenharmony_ci}; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci/* default mount serves the URL space from ./mount-origin */ 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_cistatic const struct lws_http_mount mount = { 144d4afb5ceSopenharmony_ci /* .mount_next */ NULL, /* linked-list "next" */ 145d4afb5ceSopenharmony_ci /* .mountpoint */ "/", /* mountpoint URL */ 146d4afb5ceSopenharmony_ci /* .origin */ "./mount-origin", /* serve from dir */ 147d4afb5ceSopenharmony_ci /* .def */ "index.html", /* default filename */ 148d4afb5ceSopenharmony_ci /* .protocol */ NULL, 149d4afb5ceSopenharmony_ci /* .cgienv */ NULL, 150d4afb5ceSopenharmony_ci /* .extra_mimetypes */ NULL, 151d4afb5ceSopenharmony_ci /* .interpret */ NULL, 152d4afb5ceSopenharmony_ci /* .cgi_timeout */ 0, 153d4afb5ceSopenharmony_ci /* .cache_max_age */ 0, 154d4afb5ceSopenharmony_ci /* .auth_mask */ 0, 155d4afb5ceSopenharmony_ci /* .cache_reusable */ 0, 156d4afb5ceSopenharmony_ci /* .cache_revalidate */ 0, 157d4afb5ceSopenharmony_ci /* .cache_intermediaries */ 0, 158d4afb5ceSopenharmony_ci /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ 159d4afb5ceSopenharmony_ci /* .mountpoint_len */ 1, /* char count */ 160d4afb5ceSopenharmony_ci /* .basic_auth_login_file */ NULL, 161d4afb5ceSopenharmony_ci}; 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_civoid sigint_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_context *context; 172d4afb5ceSopenharmony_ci const char *p; 173d4afb5ceSopenharmony_ci int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE 174d4afb5ceSopenharmony_ci /* for LLL_ verbosity above NOTICE to be built into lws, 175d4afb5ceSopenharmony_ci * lws must have been configured and built with 176d4afb5ceSopenharmony_ci * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ 177d4afb5ceSopenharmony_ci /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ 178d4afb5ceSopenharmony_ci /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ 179d4afb5ceSopenharmony_ci /* | LLL_DEBUG */; 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 184d4afb5ceSopenharmony_ci logs = atoi(p); 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 187d4afb5ceSopenharmony_ci lwsl_user("LWS minimal http server POST | visit http://localhost:7681\n"); 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 190d4afb5ceSopenharmony_ci info.port = 7681; 191d4afb5ceSopenharmony_ci info.protocols = protocols; 192d4afb5ceSopenharmony_ci info.mounts = &mount; 193d4afb5ceSopenharmony_ci info.options = 194d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; 195d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 196d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-s")) { 197d4afb5ceSopenharmony_ci info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 198d4afb5ceSopenharmony_ci info.ssl_cert_filepath = "localhost-100y.cert"; 199d4afb5ceSopenharmony_ci info.ssl_private_key_filepath = "localhost-100y.key"; 200d4afb5ceSopenharmony_ci } 201d4afb5ceSopenharmony_ci#endif 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "--port"))) 204d4afb5ceSopenharmony_ci info.port = atoi(p); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "--303")) { 207d4afb5ceSopenharmony_ci lwsl_user("%s: using 303 redirect\n", __func__); 208d4afb5ceSopenharmony_ci use303 = 1; 209d4afb5ceSopenharmony_ci } 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci context = lws_create_context(&info); 212d4afb5ceSopenharmony_ci if (!context) { 213d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 214d4afb5ceSopenharmony_ci return 1; 215d4afb5ceSopenharmony_ci } 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 218d4afb5ceSopenharmony_ci n = lws_service(context, 0); 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci lws_context_destroy(context); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci return 0; 223d4afb5ceSopenharmony_ci} 224