Переглянути джерело

Document mg_response_header_* functions

Document functions and add NO_REPSONSE_BUFFERING define to disable them
bel2125 4 роки тому
батько
коміт
9f6f72bfb1

+ 4 - 4
VisualStudio/civetweb_lua/civetweb_lua.vcxproj

@@ -102,7 +102,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>STOP_FLAG_NEEDS_LOCK;OPENSSL_API_1_0;USE_HTTP2;MG_EXPERIMENTAL_INTERFACES;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_LUA_LUAXML;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NO_HTTP2;STOP_FLAG_NEEDS_LOCK;OPENSSL_API_1_0;MG_EXPERIMENTAL_INTERFACES;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_LUA_LUAXML;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -119,7 +119,7 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>USE_HTTP2;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NO_HTTP2;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -149,7 +149,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>OPENSSL_API_1_0;MG_EXPERIMENTAL_INTERFACES;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_LUA_LUAXML;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NO_HTTP2;OPENSSL_API_1_0;MG_EXPERIMENTAL_INTERFACES;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_LUA_LUAXML;USE_WEBSOCKET;WIN32;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -170,7 +170,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>USE_HTTP2;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NO_HTTP2;USE_SERVER_STATS;USE_DUKTAPE;USE_IPV6;LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;USE_WEBSOCKET;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party;$(ProjectDir)..\..\src\third_party\lua-5.2.4\src;$(ProjectDir)..\..\src\third_party\duktape-1.5.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>

+ 33 - 24
docs/Building.md

@@ -143,30 +143,39 @@ Compile flags can be set using the *COPT* make option like so.
 make build COPT="-DNDEBUG -DNO_CGI"
 ```
 
-| Compile Flags                | Description                                               |
-| ---------------------------- | --------------------------------------------------------- |
-| `NDEBUG`                     | strip off all debug code                                  |
-| `DEBUG`                      | build debug version (very noisy)                          |
-|                              |                                                           |
-| `NO_FILES`                   | do not serve files from a directory                       |
-| `NO_FILESYSTEMS`             | completely disable filesystems usage (requires NO_FILES)  |
-| `NO_SSL`                     | disable SSL functionality                                 |
-| `NO_CGI`                     | disable CGI support                                       |
-| `NO_CACHING`                 | disable caching functionality                             |
-|                              |                                                           |
-| `USE_IPV6`                   | enable IPv6 support                                       |
-| `USE_WEBSOCKET`              | enable websocket support                                  |
-| `USE_LUA`                    | enable Lua support                                        |
-| `USE_DUKTAPE`                | enable server-side JavaScript (using Duktape library)     |
-| `USE_SERVER_STATS`           | enable server statistics support                          |
-| `USE_ZLIB`                   | enable on-the-fly compression of files (using zlib)       |
-| `MG_EXPERIMENTAL_INTERFACES` | include experimental interfaces                           |
-| `MG_LEGACY_INTERFACE`        | include obsolete interfaces (candidates for deletion)     |
-|                              |                                                           |
-| `NO_SSL_DL`                  | link against system libssl library                        |
-| `SQLITE_DISABLE_LFS`         | disables large files (Lua only)                           |
-| `SSL_ALREADY_INITIALIZED`    | do not initialize libcrypto                               |
-| `OPENSSL_API_1_1`            | Use OpenSSL V1.1.x interface                              |
+| Compile Flags                | Description                                                         |
+| ---------------------------- | ------------------------------------------------------------------- |
+| `NDEBUG`                     | strip off all debug code                                            |
+| `DEBUG`                      | build debug version (very noisy)                                    |
+|                              |                                                                     |
+| `NO_ATOMICS`                 | do not use atomic functions, use locks instead                      |
+| `NO_CACHING`                 | disable caching functionality                                       |
+| `NO_CGI`                     | disable CGI support                                                 |
+| `NO_FILES`                   | do not serve files from a directory                                 |
+| `NO_FILESYSTEMS`             | completely disable filesystems usage (requires NO_FILES)            |
+| `NO_NONCE_CHECK`             | disable nonce check for HTTP digest authentication                  |
+| `NO_RESPONSE_BUFFERING`      | send all mg_response_header_* immediately instead of buffering until the mg_response_header_send call |
+| `NO_SSL`                     | disable SSL functionality                                           |
+| `NO_SSL_DL`                  | link against system libssl library                                  |
+| `NO_THREAD_NAME`             | do not set a name for pthread                                       |
+|                              |                                                                     |
+| `USE_ALPN`                   | enable Application-Level-Protocol-Negotiation, required for HTTP2   |
+| `USE_DUKTAPE`                | enable server-side JavaScript (using Duktape library)               |
+| `USE_HTTP2`                  | enable HTTP2 support (experimental, not reccomended for production) |
+| `USE_IPV6`                   | enable IPv6 support                                                 |
+| `USE_LUA`                    | enable Lua support                                                  |
+| `USE_SERVER_STATS`           | enable server statistics support                                    |
+| `USE_STACK_SIZE`             | define stack size instead of using system default                   |
+| `USE_WEBSOCKET`              | enable websocket support                                            |
+| `USE_ZLIB`                   | enable on-the-fly compression of files (using zlib)                 |
+|                              |                                                                     |
+| `MG_EXPERIMENTAL_INTERFACES` | include experimental interfaces                                     |
+| `MG_LEGACY_INTERFACE`        | include obsolete interfaces (candidates for deletion)               |
+|                              |                                                                     |
+| `SQLITE_DISABLE_LFS`         | disables large files (Lua only)                                     |
+| `SSL_ALREADY_INITIALIZED`    | do not initialize libcrypto                                         |
+| `OPENSSL_API_1_0`            | Use OpenSSL V1.0.x interface                                        |
+| `OPENSSL_API_1_1`            | Use OpenSSL V1.1.x interface                                        |
 
 
 Note: If `make` is used (with this [Makefile](https://github.com/civetweb/civetweb/blob/master/Makefile)), you should not pass the `USE_<feature>` flags using `COPT`, but use the `WITH_<feature>` syntax above, since additional features may also use additional source code files.

+ 53 - 0
docs/api/mg_response_header_X.md

@@ -0,0 +1,53 @@
+# Civetweb API Reference
+
+### `mg_response_header_start( conn, status );`
+### `mg_response_header_add( conn, header, value, value_len );`
+### `mg_response_header_add_lines( conn, http1_headers );`
+### `mg_response_header_send( conn );`
+
+### Parameters
+
+| Parameter | Type | Description |
+| :--- | :--- | :--- |
+|**`conn`**|`struct mg_connection *`|The server is sending a response to this connection|
+|**`status`**|`int`|HTTP status code to send (100-599)|
+|**`header`**|`const char *`|HTTP header name|
+|**`value`**|`const char *`|HTTP header value|
+|**`value_len`**|`int`|Length of HTTP header value. -1 will use the entire value string.|
+|**`http1_headers`**|`const char *`|String in format "Key: Value\r\nKey2: Value2"|
+
+### Return Value
+
+| Type | Description |
+|`int`| An integer indicating success (>=0) or failure (<0). |
+|`-1`| Error: Invalid parameter (e.g., NULL pointer or value out of range) |
+|`-2`| Error: Invalid connection type. These functions must only be used in web server request handlers. |
+|`-3`| Error: Invalid connection status. These functions must be used before `mg_send()` or `mg_printf()` functions. |
+|`-4`| Error: Too many headers. The total number of header lines is limited to MG_MAX_HEADERS (default: 64). |
+|`-5`| Error: Out of memory. |
+
+
+### Description
+
+The `mg_response_header_*` family of functions can be used to send HTTP response headers from a web server handler function.
+Do not use it for HTTP clients or websockets. When using `mg_response_header_*` functions, they must be used to send all HTTP headers - combining `mg_response_header_*` functions and `mg_send_*`/`mg_write`/`mg_printf` to send HTTP headers is not possible.
+After sending HTTP headers, HTTP body data is still sent using `mg_write`/`mg_printf`.
+
+All `mg_response_header_*` functions must be used prior to any call to `mg_write`/`mg_printf`, in the following order:
+
+1) `mg_response_header_start` (once)
+2) `mg_response_header_add` (0 - 64 times), alternatively `mg_response_header_add_lines`. The preferred function is `mg_response_header_add`. The function `mg_response_header_add_lines` can process HTTP/1.x formatted header lines and is used for compatibility.
+3) `mg_response_header_send` (once)
+4) `mg_write` or `mg_printf` (multiple) to send the HTTP body
+
+Using `mg_response_header_*` functions will allow a request handler to process HTTP/1.x and HTTP/2 requests, in contrast to sending HTTP headers directly using `mg_printf`/`mg_write`.
+
+
+### See Also
+
+* [`mg_send_http_ok();`](mg_send_http_ok.md)
+* [`mg_send_http_error();`](mg_send_http_error.md)
+* [`mg_send_http_redirect();`](mg_send_http_redirect.md)
+* [`mg_write();`](mg_write.md)
+* [`mg_send_chunk();`](mg_send_chunk.md)
+

+ 4 - 0
resources/check_defines.lua

@@ -65,11 +65,15 @@ noifdef(path .. "src/civetweb_private_lua.h")
 noifdef(path .. "src/main.c")
 noifdef(path .. "src/md5.inl")
 noifdef(path .. "src/mod_duktape.inl")
+noifdef(path .. "src/mod_http2.inl")
 noifdef(path .. "src/mod_lua.inl")
+noifdef(path .. "src/mod_lua_shared.inl")
 noifdef(path .. "src/mod_zlib.inl")
 noifdef(path .. "src/sha1.inl")
 noifdef(path .. "src/timer.inl")
 noifdef(path .. "src/wolfssl_extras.inl")
+noifdef(path .. "src/response.inl")
+noifdef(path .. "src/handle_form.inl")
 
 --PrintTab(usedlines)
 

+ 8 - 7
src/civetweb.c

@@ -234,7 +234,7 @@ static void DEBUG_TRACE_FUNC(const char *func,
 	DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
 
 #define NEED_DEBUG_TRACE_FUNC
-#ifndef DEBUG_TRACE_STREAM
+#if !defined(DEBUG_TRACE_STREAM)
 #define DEBUG_TRACE_STREAM stdout
 #endif
 
@@ -2868,7 +2868,7 @@ struct mg_domain_context {
 /* Stop flag can be "volatile" or require a lock.
  * MSDN uses volatile for "Interlocked" operations, but also explicitly
  * states a read operation for int is always atomic. */
-#ifdef STOP_FLAG_NEEDS_LOCK
+#if defined(STOP_FLAG_NEEDS_LOCK)
 
 typedef ptrdiff_t volatile stop_flag_t;
 
@@ -3045,7 +3045,7 @@ struct mg_connection {
 	int protocol_type;   /* see PROTOCOL_TYPE_*: 0=http/1.x, 1=ws, 2=http/2 */
 	int request_state;   /* 0: nothing sent, 1: header partially sent, 2: header
 	                        fully sent */
-#ifdef USE_HTTP2
+#if defined(USE_HTTP2)
 	struct mg_http2_connection http2;
 #endif
 
@@ -6996,7 +6996,7 @@ mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
 static void handle_request(struct mg_connection *);
 
 
-#ifdef USE_HTTP2
+#if defined(USE_HTTP2)
 #if defined(NO_SSL)
 #error "HTTP2 requires ALPN, APLN requires SSL/TLS"
 #endif
@@ -7138,7 +7138,7 @@ mg_write(struct mg_connection *conn, const void *buf, size_t len)
 
 	/* Mark connection as "data sent" */
 	conn->request_state = 10;
-#ifdef USE_HTTP2
+#if defined(USE_HTTP2)
 	if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
 		http2_data_frame_head(conn, len, 0);
 	}
@@ -16390,7 +16390,7 @@ ssl_servername_callback(SSL *ssl, int *ad, void *arg)
 }
 
 
-#ifdef USE_ALPN
+#if defined(USE_ALPN)
 static const char alpn_proto_list[] = "\x02h2\x08http/1.1\x08http/1.0";
 static const char *alpn_proto_order_http1[] = {alpn_proto_list + 3,
                                                alpn_proto_list + 3 + 8,
@@ -16715,7 +16715,7 @@ init_ssl_ctx_impl(struct mg_context *phys_ctx,
 		SSL_CTX_set_timeout(dom_ctx->ssl_ctx, (long)ssl_cache_timeout);
 	}
 
-#ifdef USE_ALPN
+#if defined(USE_ALPN)
 	/* Initialize ALPN only of TLS library (OpenSSL version) supports ALPN */
 #if !defined(NO_SSL_DL)
 	if (!tls_feature_missing[TLS_ALPN])
@@ -16938,6 +16938,7 @@ reset_per_request_attributes(struct mg_connection *conn)
 	conn->is_chunked = 0;
 	conn->must_close = 0;
 	conn->request_len = 0;
+	conn->request_state = 0;
 	conn->throttle = 0;
 	conn->accept_gzip = 0;
 

+ 51 - 6
src/response.inl

@@ -7,11 +7,18 @@
  * This file is part of the CivetWeb project.
  */
 
+#define NO_RESPONSE_BUFFERING
+
+#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
@@ -25,6 +32,23 @@ free_buffered_response_header_list(struct mg_connection *conn)
 		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);
 }
 
 
@@ -56,7 +80,15 @@ mg_response_header_start(struct mg_connection *conn, int status)
 	}
 	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;
 }
@@ -83,7 +115,9 @@ mg_response_header_add(struct mg_connection *conn,
                        const char *value,
                        int value_len)
 {
+#if !defined(NO_RESPONSE_BUFFERING)
 	int hidx;
+#endif
 
 	if ((conn == NULL) || (header == NULL) || (value == NULL)) {
 		/* Parameter error */
@@ -99,6 +133,7 @@ mg_response_header_add(struct mg_connection *conn,
 		return -3;
 	}
 
+#if !defined(NO_RESPONSE_BUFFERING)
 	hidx = conn->response_info.num_headers;
 	if (hidx >= MG_MAX_HEADERS) {
 		/* Too many headers */
@@ -132,6 +167,16 @@ mg_response_header_add(struct mg_connection *conn,
 
 	/* 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;
 }
 
@@ -205,10 +250,12 @@ static int http2_send_response_headers(struct mg_connection *conn);
 int
 mg_response_header_send(struct mg_connection *conn)
 {
+#if !defined(NO_RESPONSE_BUFFERING)
 	const char *txt;
 	int i;
 	int has_date = 0;
 	int has_connection = 0;
+#endif
 
 	if (conn == NULL) {
 		/* Parameter error */
@@ -226,6 +273,8 @@ mg_response_header_send(struct mg_connection *conn)
 
 	/* 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);
@@ -236,12 +285,7 @@ mg_response_header_send(struct mg_connection *conn)
 	}
 
 	/* Send */
-	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);
+	send_http1_response_status_line(conn);
 	for (i = 0; i < conn->response_info.num_headers; i++) {
 		mg_printf(conn,
 		          "%s: %s\r\n",
@@ -267,6 +311,7 @@ mg_response_header_send(struct mg_connection *conn)
 	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;