/* SPDX-License-Identifier: BSD-3-Clause */ #include "websocket/private-libwebsockets.h" #include "websocket/lextable-strings.h" const unsigned char *lws_token_to_string(enum lws_token_indexes token) { if ((unsigned int)token >= ARRAY_SIZE(set)) return NULL; return (unsigned char *)set[token]; } int lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_by_name(wsi, name, value, length, p, end); #else (void)wsi; #endif if (name) { while (*p < end && *name) *((*p)++) = *name++; if (*p == end) return 1; *((*p)++) = ' '; } if (*p + length + 3 >= end) return 1; memcpy(*p, value, length); *p += length; *((*p)++) = '\x0d'; *((*p)++) = '\x0a'; return 0; } int lws_finalize_http_header(struct lws *wsi, unsigned char **p, unsigned char *end) { #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return 0; #else (void)wsi; #endif if ((long)(end - *p) < 3) return 1; *((*p)++) = '\x0d'; *((*p)++) = '\x0a'; return 0; } int lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { const unsigned char *name; #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_by_token(wsi, token, value, length, p, end); #endif name = lws_token_to_string(token); if (!name) return 1; return lws_add_http_header_by_name(wsi, name, value, length, p, end); } int lws_add_http_header_content_length(struct lws *wsi, unsigned long content_length, unsigned char **p, unsigned char *end) { char b[24]; int n; n = sprintf(b, "%lu", content_length); if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end)) return 1; wsi->u.http.content_length = content_length; wsi->u.http.content_remain = content_length; return 0; } STORE_IN_ROM static const char * const err400[] = { "Bad Request", "Unauthorized", "Payment Required", "Forbidden", "Not Found", "Method Not Allowed", "Not Acceptable", "Proxy Auth Required", "Request Timeout", "Conflict", "Gone", "Length Required", "Precondition Failed", "Request Entity Too Large", "Request URI too Long", "Unsupported Media Type", "Requested Range Not Satisfiable", "Expectation Failed" }; STORE_IN_ROM static const char * const err500[] = { "Internal Server Error", "Not Implemented", "Bad Gateway", "Service Unavailable", "Gateway Timeout", "HTTP Version Not Supported" }; int lws_add_http_header_status(struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end) { const struct lws_protocol_vhost_options *headers; unsigned char code_and_desc[60]; const char *description = "", *p1; int n; STORE_IN_ROM static const char * const hver[] = { "HTTP/1.0", "HTTP/1.1", "HTTP/2" }; #ifdef LWS_WITH_ACCESS_LOG wsi->access_log.response = code; #endif #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_status(wsi, code, p, end); #endif if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) description = err400[code - 400]; if (code >= 500 && code < (500 + ARRAY_SIZE(err500))) description = err500[code - 500]; if (code == 200) description = "OK"; if (code == 304) description = "Not Modified"; else if (code >= 300 && code < 400) description = "Redirect"; if (wsi->u.http.request_version < ARRAY_SIZE(hver)) p1 = hver[wsi->u.http.request_version]; else p1 = hver[0]; n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description); if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end)) return 1; headers = wsi->vhost->headers; while (headers) { if (lws_add_http_header_by_name(wsi, (const unsigned char *)headers->name, (unsigned char *)headers->value, strlen(headers->value), p, end)) return 1; headers = headers->next; } if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *) wsi->context->server_string, wsi->context->server_string_len, p, end)) return 1; if (wsi->vhost->options & LWS_SERVER_OPTION_STS) if (lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *)"max-age=15768000 ; " "includeSubDomains", 36, p, end)) return 1; return 0; } LWS_VISIBLE int lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; unsigned char *p = pt->serv_buf + LWS_PRE; unsigned char *start = p, *body = p + 512; unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE; int n, m, len; char slen[20]; if (!html_body) html_body = ""; len = sprintf((char *)body, "