mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-15 07:57:07 +03:00
move to new cspot
This commit is contained in:
339
components/spotify/cspot/bell/external/civetweb/response.inl
vendored
Normal file
339
components/spotify/cspot/bell/external/civetweb/response.inl
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
/* response.inl
|
||||
*
|
||||
* Bufferring for HTTP headers for HTTP response.
|
||||
* This function are only intended to be used at the server side.
|
||||
* Optional for HTTP/1.0 and HTTP/1.1, mandatory for HTTP/2.
|
||||
*
|
||||
* This file is part of the CivetWeb project.
|
||||
*/
|
||||
|
||||
#if defined(NO_RESPONSE_BUFFERING) && defined(USE_HTTP2)
|
||||
#error "HTTP2 works only if NO_RESPONSE_BUFFERING is not set"
|
||||
#endif
|
||||
|
||||
|
||||
/* Internal function to free header list */
|
||||
static void
|
||||
free_buffered_response_header_list(struct mg_connection *conn)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
while (conn->response_info.num_headers > 0) {
|
||||
conn->response_info.num_headers--;
|
||||
mg_free((void *)conn->response_info
|
||||
.http_headers[conn->response_info.num_headers]
|
||||
.name);
|
||||
conn->response_info.http_headers[conn->response_info.num_headers].name =
|
||||
0;
|
||||
mg_free((void *)conn->response_info
|
||||
.http_headers[conn->response_info.num_headers]
|
||||
.value);
|
||||
conn->response_info.http_headers[conn->response_info.num_headers]
|
||||
.value = 0;
|
||||
}
|
||||
#else
|
||||
(void)conn; /* Nothing to do */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Send first line of HTTP/1.x response */
|
||||
static int
|
||||
send_http1_response_status_line(struct mg_connection *conn)
|
||||
{
|
||||
const char *status_txt;
|
||||
const char *http_version = conn->request_info.http_version;
|
||||
int status_code = conn->status_code;
|
||||
|
||||
if ((status_code < 100) || (status_code > 999)) {
|
||||
/* Set invalid status code to "500 Internal Server Error" */
|
||||
status_code = 500;
|
||||
}
|
||||
if (!http_version) {
|
||||
http_version = "1.0";
|
||||
}
|
||||
|
||||
/* mg_get_response_code_text will never return NULL */
|
||||
status_txt = mg_get_response_code_text(conn, conn->status_code);
|
||||
|
||||
if (mg_printf(
|
||||
conn, "HTTP/%s %i %s\r\n", http_version, status_code, status_txt)
|
||||
< 10) {
|
||||
/* Network sending failed */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a new HTTP response
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* status: HTTP status code (e.g., 200 for "OK").
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: network error (only if built with NO_RESPONSE_BUFFERING)
|
||||
*/
|
||||
int
|
||||
mg_response_header_start(struct mg_connection *conn, int status)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((conn == NULL) || (status < 100) || (status > 999)) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 0) {
|
||||
/* only allowed if nothing was sent up to now */
|
||||
return -3;
|
||||
}
|
||||
conn->status_code = status;
|
||||
conn->request_state = 1;
|
||||
|
||||
/* Buffered response is stored, unbuffered response will be sent directly,
|
||||
* but we can only send HTTP/1.x response here */
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
free_buffered_response_header_list(conn);
|
||||
#else
|
||||
if (!send_http1_response_status_line(conn)) {
|
||||
ret = -4;
|
||||
};
|
||||
conn->request_state = 1; /* Reset from 10 to 1 */
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Add a new HTTP response header line
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* header: Header name.
|
||||
* value: Header value.
|
||||
* value_len: Length of header value, excluding the terminating zero.
|
||||
* Use -1 for "strlen(value)".
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: too many headers
|
||||
* -5: out of memory
|
||||
*/
|
||||
int
|
||||
mg_response_header_add(struct mg_connection *conn,
|
||||
const char *header,
|
||||
const char *value,
|
||||
int value_len)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
int hidx;
|
||||
#endif
|
||||
|
||||
if ((conn == NULL) || (header == NULL) || (value == NULL)) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 1) {
|
||||
/* only allowed if mg_response_header_start has been called before */
|
||||
return -3;
|
||||
}
|
||||
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
hidx = conn->response_info.num_headers;
|
||||
if (hidx >= MG_MAX_HEADERS) {
|
||||
/* Too many headers */
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Alloc new element */
|
||||
conn->response_info.http_headers[hidx].name =
|
||||
mg_strdup_ctx(header, conn->phys_ctx);
|
||||
if (value_len >= 0) {
|
||||
char *hbuf =
|
||||
(char *)mg_malloc_ctx((unsigned)value_len + 1, conn->phys_ctx);
|
||||
if (hbuf) {
|
||||
memcpy(hbuf, value, (unsigned)value_len);
|
||||
hbuf[value_len] = 0;
|
||||
}
|
||||
conn->response_info.http_headers[hidx].value = hbuf;
|
||||
} else {
|
||||
conn->response_info.http_headers[hidx].value =
|
||||
mg_strdup_ctx(value, conn->phys_ctx);
|
||||
}
|
||||
|
||||
if ((conn->response_info.http_headers[hidx].name == 0)
|
||||
|| (conn->response_info.http_headers[hidx].value == 0)) {
|
||||
/* Out of memory */
|
||||
mg_free((void *)conn->response_info.http_headers[hidx].name);
|
||||
conn->response_info.http_headers[hidx].name = 0;
|
||||
mg_free((void *)conn->response_info.http_headers[hidx].value);
|
||||
conn->response_info.http_headers[hidx].value = 0;
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* OK, header stored */
|
||||
conn->response_info.num_headers++;
|
||||
|
||||
#else
|
||||
if (value_len >= 0) {
|
||||
mg_printf(conn, "%s: %.*s\r\n", header, (int)value_len, value);
|
||||
} else {
|
||||
mg_printf(conn, "%s: %s\r\n", header, value);
|
||||
}
|
||||
conn->request_state = 1; /* Reset from 10 to 1 */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* forward */
|
||||
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]);
|
||||
|
||||
|
||||
/* Add a complete header string (key + value).
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* http1_headers: Header line(s) in the form "name: value".
|
||||
* Return:
|
||||
* >=0: no error, number of header lines added
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: too many headers
|
||||
* -5: out of memory
|
||||
*/
|
||||
int
|
||||
mg_response_header_add_lines(struct mg_connection *conn,
|
||||
const char *http1_headers)
|
||||
{
|
||||
struct mg_header add_hdr[MG_MAX_HEADERS];
|
||||
int num_hdr, i, ret;
|
||||
char *workbuffer, *parse;
|
||||
|
||||
/* We need to work on a copy of the work buffer, sice parse_http_headers
|
||||
* will modify */
|
||||
workbuffer = mg_strdup_ctx(http1_headers, conn->phys_ctx);
|
||||
if (!workbuffer) {
|
||||
/* Out of memory */
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Call existing method to split header buffer */
|
||||
parse = workbuffer;
|
||||
num_hdr = parse_http_headers(&parse, add_hdr);
|
||||
ret = num_hdr;
|
||||
|
||||
for (i = 0; i < num_hdr; i++) {
|
||||
int lret =
|
||||
mg_response_header_add(conn, add_hdr[i].name, add_hdr[i].value, -1);
|
||||
if ((ret > 0) && (lret < 0)) {
|
||||
/* Store error return value */
|
||||
ret = lret;
|
||||
}
|
||||
}
|
||||
|
||||
/* mg_response_header_add created a copy, so we can free the original */
|
||||
mg_free(workbuffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if defined(USE_HTTP2)
|
||||
static int http2_send_response_headers(struct mg_connection *conn);
|
||||
#endif
|
||||
|
||||
|
||||
/* Send http response
|
||||
* Parameters:
|
||||
* conn: Current connection handle.
|
||||
* Return:
|
||||
* 0: ok
|
||||
* -1: parameter error
|
||||
* -2: invalid connection type
|
||||
* -3: invalid connection status
|
||||
* -4: network send failed
|
||||
*/
|
||||
int
|
||||
mg_response_header_send(struct mg_connection *conn)
|
||||
{
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
int i;
|
||||
int has_date = 0;
|
||||
int has_connection = 0;
|
||||
#endif
|
||||
|
||||
if (conn == NULL) {
|
||||
/* Parameter error */
|
||||
return -1;
|
||||
}
|
||||
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|
||||
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
|
||||
/* Only allowed in server context */
|
||||
return -2;
|
||||
}
|
||||
if (conn->request_state != 1) {
|
||||
/* only allowed if mg_response_header_start has been called before */
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* State: 2 */
|
||||
conn->request_state = 2;
|
||||
|
||||
#if !defined(NO_RESPONSE_BUFFERING)
|
||||
#if defined(USE_HTTP2)
|
||||
if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
|
||||
int ret = http2_send_response_headers(conn);
|
||||
return (ret ? 0 : -4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Send */
|
||||
if (!send_http1_response_status_line(conn)) {
|
||||
return -4;
|
||||
};
|
||||
for (i = 0; i < conn->response_info.num_headers; i++) {
|
||||
mg_printf(conn,
|
||||
"%s: %s\r\n",
|
||||
conn->response_info.http_headers[i].name,
|
||||
conn->response_info.http_headers[i].value);
|
||||
|
||||
/* Check for some special headers */
|
||||
if (!mg_strcasecmp("Date", conn->response_info.http_headers[i].name)) {
|
||||
has_date = 1;
|
||||
}
|
||||
if (!mg_strcasecmp("Connection",
|
||||
conn->response_info.http_headers[i].name)) {
|
||||
has_connection = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_date) {
|
||||
time_t curtime = time(NULL);
|
||||
char date[64];
|
||||
gmt_time_string(date, sizeof(date), &curtime);
|
||||
mg_printf(conn, "Date: %s\r\n", date);
|
||||
}
|
||||
if (!has_connection) {
|
||||
mg_printf(conn, "Connection: %s\r\n", suggest_connection_header(conn));
|
||||
}
|
||||
#endif
|
||||
|
||||
mg_write(conn, "\r\n", 2);
|
||||
conn->request_state = 3;
|
||||
|
||||
/* ok */
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user