Discard unwanted libraries from discord integration attempt.

This commit is contained in:
Sandu Liviu Catalin
2021-01-28 13:17:06 +02:00
parent da39892bb0
commit 9efcfe2fa9
831 changed files with 3916 additions and 215608 deletions
+20 -2
View File
@@ -6,8 +6,25 @@ add_library(CivetWeb STATIC
# Configure include folders
target_include_directories(CivetWeb PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(CivetWeb PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
# Configure macro options
target_compile_definitions(CivetWeb PRIVATE _WIN32_WINNT=0x0601)
# Feature selection
target_compile_definitions(CivetWeb PUBLIC USE_WEBSOCKET=1 USE_HTTP2=1 USE_TIMERS=1)
# Enable SSL
find_package(OpenSSL REQUIRED)
if (OPENSSL_FOUND)
string(REPLACE "." ";" VERSION_LIST ${OPENSSL_VERSION})
list(GET VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
list(GET VERSION_LIST 1 OPENSSL_VERSION_MINOR)
list(GET VERSION_LIST 2 OPENSSL_VERSION_PATCH)
if(OPENSSL_VERSION_MAJOR EQUAL 1 AND OPENSSL_VERSION_MINOR EQUAL 0)
target_compile_definitions(CivetWeb PUBLIC OPENSSL_API_1_0=1)
elseif(OPENSSL_VERSION_MAJOR EQUAL 1 AND OPENSSL_VERSION_MINOR EQUAL 1)
target_compile_definitions(CivetWeb PUBLIC OPENSSL_API_1_1=1)
endif()
target_include_directories(CivetWeb PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(CivetWeb PRIVATE OpenSSL::SSL OpenSSL::Crypto)
else()
target_compile_definitions(CivetWeb PUBLIC NO_SSL=1)
endif()
# Enable LTO
if (LTO_ENABLED)
target_link_libraries(CivetWeb PRIVATE -flto)
@@ -19,6 +36,7 @@ find_package(Threads)
target_link_libraries(CivetWeb PUBLIC ${CMAKE_THREAD_LIBS_INIT})
# OS and compiler checks.
if(WIN32)
target_compile_definitions(CivetWeb PRIVATE _WIN32_WINNT=0x0601)
target_link_libraries(CivetWeb PUBLIC Ws2_32)
endif()
# Need the realtime library if we're using timers
+6
View File
@@ -43,6 +43,7 @@
* Drew Wells
* duong2179
* ehlertjd
* Elan P. Kugelmass
* eugene
* Eric Tsau
* Erick Vieyra
@@ -54,6 +55,8 @@
* feneuilflo
* Fernando G. Aranda
* Frank Hilliger
* Gábor Csárdi
* goodmenzy
* Grahack
* Gregor Jasny
* grenclave
@@ -139,6 +142,8 @@
* Philipp Hasper
* Piotr Zierhoffer
* pkvamme
* Ponnuvel Palaniyappan
* qinch
* Radoslaw Zarzynski
* Red54
* Retallack Mark mark.retallack
@@ -159,6 +164,7 @@
* Simon Hailes
* slidertom
* SpaceLord
* Stefan Codrescu
* sunfch
* suzukibitman
* Símal Rasmussen
+20 -18
View File
@@ -118,27 +118,29 @@ Lua File System License
### Included only if built with Lua support.
http://keplerproject.github.io/luafilesystem/license.html
https://github.com/keplerproject/luafilesystem/blob/master/LICENSE
> Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
> Copyright © 2003-2014 Kepler Project.
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> Permission is hereby granted, free of charge, to any person
> obtaining a copy of this software and associated documentation
> files (the "Software"), to deal in the Software without
> restriction, including without limitation the rights to use, copy,
> modify, merge, publish, distribute, sublicense, and/or sell copies
> of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.
LuaXML License
@@ -188,9 +190,9 @@ https://github.com/svaarala/duktape/blob/master/LICENSE.txt
> ===============
> Duktape license
> ===============
>
>
> (http://opensource.org/licenses/MIT)
>
>
> Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
+1246 -722
View File
File diff suppressed because it is too large Load Diff
+129 -58
View File
@@ -23,9 +23,9 @@
#ifndef CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_VERSION "1.13"
#define CIVETWEB_VERSION "1.14"
#define CIVETWEB_VERSION_MAJOR (1)
#define CIVETWEB_VERSION_MINOR (13)
#define CIVETWEB_VERSION_MINOR (14)
#define CIVETWEB_VERSION_PATCH (0)
#ifndef CIVETWEB_API
@@ -98,8 +98,13 @@ enum {
/* Will only work, if USE_ZLIB is set. */
MG_FEATURES_COMPRESSION = 0x200u,
/* Collect server status information. */
/* Will only work, if USE_SERVER_STATS is set. */
/* HTTP/2 support enabled. */
MG_FEATURES_HTTP2 = 0x400u,
/* Support unix domain sockets. */
MG_FEATURES_X_DOMAIN_SOCKET = 0x800u,
/* Bit mask for all feature defines. */
MG_FEATURES_ALL = 0xFFFFu
};
@@ -161,8 +166,11 @@ struct mg_request_info {
long long content_length; /* Length (in bytes) of the request body,
can be -1 if no length was given. */
int remote_port; /* Client's port */
int is_ssl; /* 1 if SSL-ed, 0 if not */
int remote_port; /* Port at client side */
int server_port; /* Port at server side (one of the listening
ports) */
int is_ssl; /* 1 if HTTPS or WS is used (SSL/TLS used),
0 if not */
void *user_data; /* User data pointer passed to mg_start() */
void *conn_data; /* Connection-specific user data */
@@ -293,21 +301,8 @@ struct mg_callbacks {
void **ssl_ctx,
void *user_data);
#if defined(MG_LEGACY_INTERFACE) /* 2015-08-19 */ \
|| defined(MG_EXPERIMENTAL_INTERFACES) /* 2019-11-03 */
/* Called when websocket request is received, before websocket handshake.
Return value:
0: civetweb proceeds with websocket handshake.
1: connection is closed immediately.
This callback is deprecated: Use mg_set_websocket_handler instead. */
int (*websocket_connect)(const struct mg_connection *);
/* Called when websocket handshake is successfully completed, and
connection is ready for data exchange.
This callback is deprecated: Use mg_set_websocket_handler instead. */
void (*websocket_ready)(struct mg_connection *);
/* Called when data frame has been received from the client.
#if defined(MG_EXPERIMENTAL_INTERFACES) /* 2019-11-03 */
/* Called when data frame has been received from the peer.
Parameters:
bits: first byte of the websocket frame, see websocket RFC at
http://tools.ietf.org/html/rfc6455, section 5.2
@@ -355,14 +350,6 @@ struct mg_callbacks {
void *lua_context,
unsigned context_flags);
#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
/* Called when civetweb has uploaded a file to a temporary directory as a
result of mg_upload() call.
Note that mg_upload is deprecated. Use mg_handle_form_request instead.
Parameters:
file_name: full path name to the uploaded file. */
void (*upload)(struct mg_connection *, const char *file_name);
#endif
/* Called when civetweb is about to send HTTP error to the client.
Implementing this callback allows to create custom error pages.
@@ -580,7 +567,7 @@ typedef void (*mg_websocket_close_handler)(const struct mg_connection *,
*/
struct mg_websocket_subprotocols {
int nb_subprotocols;
char **subprotocols;
const char **subprotocols;
};
/* mg_set_websocket_handler
@@ -664,7 +651,14 @@ CIVETWEB_API void *mg_get_thread_pointer(const struct mg_connection *conn);
/* Set user data for the current connection. */
/* Note: This function is deprecated. Use the init_connection callback
/* Note: CivetWeb callbacks use "struct mg_connection *conn" as input
when mg_read/mg_write callbacks are allowed in the callback,
while "const struct mg_connection *conn" is used as input in case
calling mg_read/mg_write is not allowed.
Setting the user connection data will modify the connection
object represented by mg_connection *, but it will not read from
or write to the connection. */
/* Note: An alternative is to use the init_connection callback
instead to initialize the user connection data pointer. It is
reccomended to supply a pointer to some user defined data structure
as conn_data initializer in init_connection. In case it is required
@@ -672,7 +666,7 @@ CIVETWEB_API void *mg_get_thread_pointer(const struct mg_connection *conn);
data pointer in the user defined data structure and modify that
pointer. In either case, after the init_connection callback, only
calls to mg_get_user_connection_data should be required. */
CIVETWEB_API void mg_set_user_connection_data(struct mg_connection *conn,
CIVETWEB_API void mg_set_user_connection_data(const struct mg_connection *conn,
void *data);
@@ -694,16 +688,6 @@ CIVETWEB_API int
mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen);
#if defined(MG_LEGACY_INTERFACE) /* 2014-02-21 */
/* Return array of strings that represent valid configuration options.
For each option, option name and default value is returned, i.e. the
number of entries in the array equals to number_of_options x 2.
Array is NULL terminated. */
/* Deprecated: Use mg_get_valid_options instead. */
CIVETWEB_API const char **mg_get_valid_option_names(void);
#endif
struct mg_option {
const char *name;
int type;
@@ -876,12 +860,6 @@ CIVETWEB_API void mg_lock_connection(struct mg_connection *conn);
CIVETWEB_API void mg_unlock_connection(struct mg_connection *conn);
#if defined(MG_LEGACY_INTERFACE) /* 2014-06-21 */
#define mg_lock mg_lock_connection
#define mg_unlock mg_unlock_connection
#endif
/* Lock server context. This lock may be used to protect resources
that are shared between different connection/worker threads.
If the given context is not server, these functions do nothing. */
@@ -1243,16 +1221,6 @@ mg_download(const char *host,
CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
/* File upload functionality. Each uploaded file gets saved into a temporary
file and MG_UPLOAD event is sent.
Return number of uploaded files.
Deprecated: Use mg_handle_form_request instead. */
CIVETWEB_API int mg_upload(struct mg_connection *conn,
const char *destination_dir);
#endif
/* This structure contains callback functions for handling form fields.
It is used as an argument to mg_handle_form_request. */
struct mg_form_data_handler {
@@ -1468,6 +1436,19 @@ mg_connect_websocket_client(const char *host,
mg_websocket_close_handler close_func,
void *user_data);
CIVETWEB_API struct mg_connection *
mg_connect_websocket_client_extensions(const char *host,
int port,
int use_ssl,
char *error_buffer,
size_t error_buffer_size,
const char *path,
const char *origin,
const char *extensions,
mg_websocket_data_handler data_func,
mg_websocket_close_handler close_func,
void *user_data);
/* Connect to a TCP server as a client (can be used to connect to a HTTP server)
Parameters:
@@ -1514,12 +1495,24 @@ CIVETWEB_API struct mg_connection *mg_connect_websocket_client_secure(
mg_websocket_close_handler close_func,
void *user_data);
CIVETWEB_API struct mg_connection *
mg_connect_websocket_client_secure_extensions(
const struct mg_client_options *client_options,
char *error_buffer,
size_t error_buffer_size,
const char *path,
const char *origin,
const char *extensions,
mg_websocket_data_handler data_func,
mg_websocket_close_handler close_func,
void *user_data);
#if defined(MG_LEGACY_INTERFACE) /* 2019-11-02 */
enum { TIMEOUT_INFINITE = -1 };
#endif
enum { MG_TIMEOUT_INFINITE = -1 };
/* Wait for a response from the server
Parameters:
conn: connection
@@ -1537,6 +1530,76 @@ CIVETWEB_API int mg_get_response(struct mg_connection *conn,
int timeout);
/* mg_response_header_* functions can be used from server callbacks
* to prepare HTTP server response headers. Using this function will
* allow a callback to work with HTTP/1.x and HTTP/2.
*/
/* 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
*/
CIVETWEB_API int mg_response_header_start(struct mg_connection *conn,
int status);
/* 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
*/
CIVETWEB_API int mg_response_header_add(struct mg_connection *conn,
const char *header,
const char *value,
int value_len);
/* Add a complete header string (key + value).
* This function is less efficient as compared to mg_response_header_add,
* and should only be used to convert complete HTTP/1.x header lines.
* Parameters:
* conn: Current connection handle.
* http1_headers: Header line(s) in the form "name: value\r\n".
* 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
*/
CIVETWEB_API int mg_response_header_add_lines(struct mg_connection *conn,
const char *http1_headers);
/* Send http response
* Parameters:
* conn: Current connection handle.
* Return:
* 0: ok
* -1: parameter error
* -2: invalid connection type
* -3: invalid connection status
*/
CIVETWEB_API int mg_response_header_send(struct mg_connection *conn);
/* Check which features where set when the civetweb library has been compiled.
The function explicitly addresses compile time defines used when building
the library - it does not mean, the feature has been initialized using a
@@ -1606,6 +1669,14 @@ CIVETWEB_API int
mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen);
/* Disable HTTP keep-alive on a per-connection basis.
Reference: https://github.com/civetweb/civetweb/issues/727
Parameters:
conn: Current connection handle.
*/
CIVETWEB_API void mg_disable_connection_keep_alive(struct mg_connection *conn);
#if defined(MG_EXPERIMENTAL_INTERFACES)
/* Get connection information. Useful for server diagnosis.
Parameters:
File diff suppressed because it is too large Load Diff
+277
View File
@@ -0,0 +1,277 @@
/* Experimental implementation for on-the-fly compression */
#if !defined(USE_ZLIB)
#error "This file must only be included, if USE_ZLIB is set"
#endif
#if !defined(MEM_LEVEL)
#define MEM_LEVEL (8)
#endif
static void *
zalloc(void *opaque, uInt items, uInt size)
{
struct mg_connection *conn = (struct mg_connection *)opaque;
void *ret = mg_calloc_ctx(items, size, conn->phys_ctx);
return ret;
}
static void
zfree(void *opaque, void *address)
{
struct mg_connection *conn = (struct mg_connection *)opaque;
(void)conn; /* not required */
mg_free(address);
}
static void
send_compressed_data(struct mg_connection *conn, struct mg_file *filep)
{
int zret;
z_stream zstream;
int do_flush;
unsigned bytes_avail;
unsigned char in_buf[MG_BUF_LEN];
unsigned char out_buf[MG_BUF_LEN];
FILE *in_file = filep->access.fp;
/* Prepare state buffer. User server context memory allocation. */
memset(&zstream, 0, sizeof(zstream));
zstream.zalloc = zalloc;
zstream.zfree = zfree;
zstream.opaque = (void *)conn;
/* Initialize for GZIP compression (MAX_WBITS | 16) */
zret = deflateInit2(&zstream,
Z_BEST_COMPRESSION,
Z_DEFLATED,
MAX_WBITS | 16,
MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (zret != Z_OK) {
mg_cry_internal(conn,
"GZIP init failed (%i): %s",
zret,
(zstream.msg ? zstream.msg : "<no error message>"));
deflateEnd(&zstream);
return;
}
/* Read until end of file */
do {
zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file);
if (ferror(in_file)) {
mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO));
(void)deflateEnd(&zstream);
return;
}
do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH);
zstream.next_in = in_buf;
/* run deflate() on input until output buffer not full, finish
* compression if all of source has been read in */
do {
zstream.avail_out = MG_BUF_LEN;
zstream.next_out = out_buf;
zret = deflate(&zstream, do_flush);
if (zret == Z_STREAM_ERROR) {
/* deflate error */
zret = -97;
break;
}
bytes_avail = MG_BUF_LEN - zstream.avail_out;
if (bytes_avail) {
if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) {
zret = -98;
break;
}
}
} while (zstream.avail_out == 0);
if (zret < -90) {
/* Forward write error */
break;
}
if (zstream.avail_in != 0) {
/* all input will be used, otherwise GZIP is incomplete */
zret = -99;
break;
}
/* done when last data in file processed */
} while (do_flush != Z_FINISH);
if (zret != Z_STREAM_END) {
/* Error: We did not compress everything. */
mg_cry_internal(conn,
"GZIP incomplete (%i): %s",
zret,
(zstream.msg ? zstream.msg : "<no error message>"));
}
deflateEnd(&zstream);
/* Send "end of chunked data" marker */
mg_write(conn, "0\r\n\r\n", 5);
}
#if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
int
websocket_deflate_initialize(struct mg_connection *conn, int server)
{
int zret =
deflateInit2(&conn->websocket_deflate_state,
Z_BEST_COMPRESSION,
Z_DEFLATED,
server
? -1 * conn->websocket_deflate_server_max_windows_bits
: -1 * conn->websocket_deflate_client_max_windows_bits,
MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (zret != Z_OK) {
mg_cry_internal(conn,
"Websocket deflate init failed (%i): %s",
zret,
(conn->websocket_deflate_state.msg
? conn->websocket_deflate_state.msg
: "<no error message>"));
deflateEnd(&conn->websocket_deflate_state);
return zret;
}
zret = inflateInit2(
&conn->websocket_inflate_state,
server ? -1 * conn->websocket_deflate_client_max_windows_bits
: -1 * conn->websocket_deflate_server_max_windows_bits);
if (zret != Z_OK) {
mg_cry_internal(conn,
"Websocket inflate init failed (%i): %s",
zret,
(conn->websocket_inflate_state.msg
? conn->websocket_inflate_state.msg
: "<no error message>"));
inflateEnd(&conn->websocket_inflate_state);
return zret;
}
if ((conn->websocket_deflate_server_no_context_takeover && server)
|| (conn->websocket_deflate_client_no_context_takeover && !server))
conn->websocket_deflate_flush = Z_FULL_FLUSH;
else
conn->websocket_deflate_flush = Z_SYNC_FLUSH;
conn->websocket_deflate_initialized = 1;
return Z_OK;
}
void
websocket_deflate_negotiate(struct mg_connection *conn)
{
const char *extensions = mg_get_header(conn, "Sec-WebSocket-Extensions");
int val;
if (extensions && !strncmp(extensions, "permessage-deflate", 18)) {
conn->accept_gzip = 1;
conn->websocket_deflate_client_max_windows_bits = 15;
conn->websocket_deflate_server_max_windows_bits = 15;
conn->websocket_deflate_server_no_context_takeover = 0;
conn->websocket_deflate_client_no_context_takeover = 0;
extensions += 18;
while (*extensions != '\0') {
if (*extensions == ';' || *extensions == ' ')
++extensions;
else if (!strncmp(extensions, "server_no_context_takeover", 26)) {
extensions += 26;
conn->websocket_deflate_server_no_context_takeover = 1;
} else if (!strncmp(extensions, "client_no_context_takeover", 26)) {
extensions += 26;
conn->websocket_deflate_client_no_context_takeover = 1;
} else if (!strncmp(extensions, "server_max_window_bits", 22)) {
extensions += 22;
if (*extensions == '=') {
++extensions;
if (*extensions == '"')
++extensions;
val = 0;
while (*extensions >= '0' && *extensions <= '9') {
val = val * 10 + (*extensions - '0');
++extensions;
}
if (val < 9 || val > 15) {
// The permessage-deflate spec specifies that a
// value of 8 is also allowed, but zlib doesn't accept
// that.
mg_cry_internal(conn,
"server-max-window-bits must be "
"between 9 and 15. Got %i",
val);
} else
conn->websocket_deflate_server_max_windows_bits = val;
if (*extensions == '"')
++extensions;
}
} else if (!strncmp(extensions, "client_max_window_bits", 22)) {
extensions += 22;
if (*extensions == '=') {
++extensions;
if (*extensions == '"')
++extensions;
val = 0;
while (*extensions >= '0' && *extensions <= '9') {
val = val * 10 + (*extensions - '0');
++extensions;
}
if (val < 9 || val > 15)
// The permessage-deflate spec specifies that a
// value of 8 is also allowed, but zlib doesn't
// accept that.
mg_cry_internal(conn,
"client-max-window-bits must be "
"between 9 and 15. Got %i",
val);
else
conn->websocket_deflate_client_max_windows_bits = val;
if (*extensions == '"')
++extensions;
}
} else {
mg_cry_internal(conn,
"Unknown parameter %s for permessage-deflate",
extensions);
break;
}
}
} else {
conn->accept_gzip = 0;
}
conn->websocket_deflate_initialized = 0;
}
void
websocket_deflate_response(struct mg_connection *conn)
{
if (conn->accept_gzip) {
mg_printf(conn,
"Sec-WebSocket-Extensions: permessage-deflate; "
"server_max_window_bits=%i; "
"client_max_window_bits=%i"
"%s%s\r\n",
conn->websocket_deflate_server_max_windows_bits,
conn->websocket_deflate_client_max_windows_bits,
conn->websocket_deflate_client_no_context_takeover
? "; client_no_context_takeover"
: "",
conn->websocket_deflate_server_no_context_takeover
? "; server_no_context_takeover"
: "");
};
}
#endif
+318
View File
@@ -0,0 +1,318 @@
/* 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 currently 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 void
send_http1_response_status_line(struct mg_connection *conn)
{
/* mg_get_response_code_text will never return NULL */
const char *txt = mg_get_response_code_text(conn, conn->status_code);
mg_printf(conn,
"HTTP/%s %i %s\r\n",
conn->request_info.http_version,
conn->status_code,
txt);
}
/* 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
*/
int
mg_response_header_start(struct mg_connection *conn, int status)
{
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
send_http1_response_status_line(conn);
conn->request_state = 1; /* Reset from 10 to 1 */
#endif
return 0;
}
/* 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 = 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
*/
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 (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
#if defined USE_HTTP2
int ret = http2_send_response_headers(conn);
return ret ? 0 : 0; /* todo */
#else
return -2;
#endif
}
/* Send */
send_http1_response_status_line(conn);
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;
}