diff --git a/src/http.c b/src/http.c index eea62afd1..9d764e68b 100644 --- a/src/http.c +++ b/src/http.c @@ -97,7 +97,38 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, bool done = false; switch (reason) { + case LWS_CALLBACK_HTTP_BODY: + // Accumulate POST body data + if (pss->post_body == NULL) { + pss->post_body = malloc(len + 1); + if (pss->post_body) { + memcpy(pss->post_body, in, len); + pss->post_body[len] = '\0'; + pss->post_body_len = len; + } + } else { + char *new_body = realloc(pss->post_body, pss->post_body_len + len + 1); + if (new_body) { + pss->post_body = new_body; + memcpy(pss->post_body + pss->post_body_len, in, len); + pss->post_body_len += len; + pss->post_body[pss->post_body_len] = '\0'; + } + } + break; + + case LWS_CALLBACK_HTTP_BODY_COMPLETION: + // Store POST body for WebSocket upgrade + if (pss->post_body && pss->post_body_len > 0) { + store_post_body(wsi, pss->post_body, pss->post_body_len); + } + break; + case LWS_CALLBACK_HTTP: + // Initialize POST body fields + pss->post_body = NULL; + pss->post_body_len = 0; + access_log(wsi, (const char *)in); snprintf(pss->path, sizeof(pss->path), "%s", (const char *)in); switch (check_auth(wsi, pss)) { @@ -215,6 +246,13 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; + case LWS_CALLBACK_CLOSED_HTTP: + if (pss->post_body) { + free(pss->post_body); + pss->post_body = NULL; + pss->post_body_len = 0; + } + break; #if (defined(LWS_OPENSSL_SUPPORT) || defined(LWS_WITH_TLS)) && !defined(LWS_WITH_MBEDTLS) case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if (!len || (SSL_get_verify_result((SSL *)in) != X509_V_OK)) { diff --git a/src/protocol.c b/src/protocol.c index 53e65d4dd..cfc7e8e81 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -13,6 +13,73 @@ // initial message list static char initial_cmds[] = {SET_WINDOW_TITLE, SET_PREFERENCES}; +// Storage for POST body data during WebSocket upgrade +struct post_body_storage { + struct lws *wsi; + char *body; + size_t len; + struct post_body_storage *next; +}; + +static struct post_body_storage *post_body_list = NULL; + +void store_post_body(struct lws *wsi, const char *body, size_t len) { + struct post_body_storage *storage = malloc(sizeof(struct post_body_storage)); + if (storage) { + storage->wsi = wsi; + storage->body = malloc(len + 1); + if (storage->body) { + memcpy(storage->body, body, len); + storage->body[len] = '\0'; + storage->len = len; + storage->next = post_body_list; + post_body_list = storage; + } else { + free(storage); + } + } +} + +char *retrieve_post_body(struct lws *wsi) { + struct post_body_storage **prev = &post_body_list; + struct post_body_storage *curr = post_body_list; + + while (curr) { + if (curr->wsi == wsi) { + char *body = curr->body; + *prev = curr->next; + free(curr); + return body; + } + prev = &curr->next; + curr = curr->next; + } + return NULL; +} + +static int hex_to_int(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return 0; +} + +static void url_decode(char *dst, const char *src) { + char a, b; + while (*src) { + if (*src == '%' && (a = src[1]) && a != '\0' && (b = src[2]) && b != '\0') { + *dst++ = hex_to_int(a) * 16 + hex_to_int(b); + src += 3; + } else if (*src == '+') { + *dst++ = ' '; + src++; + } else { + *dst++ = *src++; + } + } + *dst = '\0'; +} + static int send_initial_message(struct lws *wsi, int index) { unsigned char message[LWS_PRE + 1 + 4096]; unsigned char *p = &message[LWS_PRE]; @@ -196,7 +263,7 @@ static bool check_auth(struct lws *wsi, struct pss_tty *pss) { int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct pss_tty *pss = (struct pss_tty *)user; - char buf[256]; + char buf[8192]; size_t n = 0; switch (reason) { @@ -233,15 +300,46 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user, pss->authenticated = false; pss->wsi = wsi; pss->lws_close_status = LWS_CLOSE_STATUS_NOSTATUS; + pss->args = NULL; + pss->argc = 0; if (server->url_arg) { + // Parse URL query parameters while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n++) > 0) { if (strncmp(buf, "arg=", 4) == 0) { + char decoded[sizeof(buf)]; + url_decode(decoded, &buf[4]); pss->args = xrealloc(pss->args, (pss->argc + 1) * sizeof(char *)); - pss->args[pss->argc] = strdup(&buf[4]); + pss->args[pss->argc] = strdup(decoded); pss->argc++; } } + + // Parse POST body parameters + char *post_body = retrieve_post_body(wsi); + if (post_body && strlen(post_body) > 0) { + char *body_copy = strdup(post_body); + if (body_copy) { + char *ptr = body_copy; + char *token; + + // Parse URL-encoded POST body (arg=value1&arg=value2) + while ((token = strsep(&ptr, "&")) != NULL) { + if (strlen(token) > 4 && strncmp(token, "arg=", 4) == 0) { + char *decoded = malloc(strlen(token + 4) + 1); + if (decoded) { + url_decode(decoded, token + 4); + pss->args = xrealloc(pss->args, (pss->argc + 1) * sizeof(char *)); + pss->args[pss->argc] = decoded; + pss->argc++; + } + } + } + + free(body_copy); + } + free(post_body); + } } server->client_count++; diff --git a/src/server.h b/src/server.h index e13d63271..293056c0b 100644 --- a/src/server.h +++ b/src/server.h @@ -29,11 +29,17 @@ extern struct lws_context *context; extern struct server *server; extern struct endpoints endpoints; +// POST body storage functions +void store_post_body(struct lws *wsi, const char *body, size_t len); +char *retrieve_post_body(struct lws *wsi); + struct pss_http { char path[128]; char *buffer; char *ptr; size_t len; + char *post_body; + size_t post_body_len; }; struct pss_tty {