Browse Source

Add example POST handler

bel 8 năm trước cách đây
mục cha
commit
47929c3f75
4 tập tin đã thay đổi với 225 bổ sung1 xóa
  1. 29 0
      docs/api/mg_get_request_link.md
  2. 101 0
      examples/embedded_c/embedded_c.c
  3. 14 1
      include/civetweb.h
  4. 81 0
      src/civetweb.c

+ 29 - 0
docs/api/mg_get_request_link.md

@@ -0,0 +1,29 @@
+# Civetweb API Reference
+
+### `mg_get_request_link( conn, buf, buflen );`
+
+### Parameters
+
+| Parameter | Type | Description |
+| :--- | :--- | :--- |
+|**`conn`**|`struct mg_connection *`| A pointer referencing the connection |
+|**`buf`**|`char *`| A buffer to store the link |
+|**`buflen`**|`size_t`| Size of the buffer |
+
+### Return Value
+
+| Type | Description |
+| :--- | :--- |
+|`int`| Return code: <0 for error, >=0 for success |
+
+### Description
+
+Store a formatted link corresponding to the current request.
+
+E.g., returns
+`http://mydomain.com:8080/path/to/callback.ext`
+or 
+`http://127.0.0.1:8080/path/to/callback.ext`
+depending on the auth check settings.
+
+### See Also

+ 101 - 0
examples/embedded_c/embedded_c.c

@@ -77,6 +77,9 @@ ExampleHandler(struct mg_connection *conn, void *cbdata)
 	          "<p>To see a page from the CookieHandler handler <a "
 	          "href=\"cookie\">click cookie</a></p>");
 	mg_printf(conn,
+	          "<p>To see a page from the PostResponser handler <a "
+	          "href=\"postresponse\">click post response</a></p>");
+	mg_printf(conn,
 	          "<p>To see an example for parsing files on the fly <a "
 	          "href=\"on_the_fly_form\">click form</a> (form for "
 	          "uploading files)</p>");
@@ -459,6 +462,99 @@ CookieHandler(struct mg_connection *conn, void *cbdata)
 }
 
 
+static int
+send_chunk(struct mg_connection *conn,
+           const char *chunk,
+           unsigned int chunk_len)
+{
+	char lenbuf[16];
+	size_t lenbuf_len;
+	int ret;
+	int t;
+
+	/* First store the length information in a text buffer. */
+	sprintf(lenbuf, "%x\r\n", chunk_len);
+	lenbuf_len = strlen(lenbuf);
+
+	/* Then send length information, chunk and terminating \r\n. */
+	ret = mg_write(conn, lenbuf, lenbuf_len);
+	if (ret != (int)lenbuf_len) {
+		return -1;
+	}
+	t = ret;
+
+	ret = mg_write(conn, chunk, chunk_len);
+	if (ret != (int)chunk_len) {
+		return -1;
+	}
+	t += ret;
+
+	ret = mg_write(conn, "\r\n", 2);
+	if (ret != 2) {
+		return -1;
+	}
+	t += ret;
+
+	return t;
+}
+
+
+int
+PostResponser(struct mg_connection *conn, void *cbdata)
+{
+	long long r_total = 0;
+	int r, s;
+
+	char buf[2048];
+
+	const struct mg_request_info *ri = mg_get_request_info(conn);
+
+	if (strcmp(ri->request_method, "POST")) {
+		char buf[1024];
+		int ret = mg_get_request_link(conn, buf, sizeof(buf));
+
+		mg_printf(conn,
+		          "HTTP/1.1 405 Method Not Allowed\r\nConnection: close\r\n");
+		mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+		mg_printf(conn,
+		          "%s method not allowed in the POST handler\n",
+		          ri->request_method);
+		if (ret >= 0) {
+			mg_printf(conn,
+			          "use a web tool to send a POST request to %s\n",
+			          buf);
+		}
+		return 1;
+	}
+
+	if (ri->content_length >= 0) {
+		/* We know the content length in advance */
+	} else {
+		/* We must read until we find the end (chunked encoding
+		 * or connection close), indicated my mg_read returning 0 */
+	}
+
+	mg_printf(conn,
+	          "HTTP/1.1 200 OK\r\nConnection: "
+	          "close\r\nTransfer-Encoding: chunked\r\n");
+	mg_printf(conn, "Content-Type: text/plain\r\n\r\n");
+
+	r = mg_read(conn, buf, sizeof(buf));
+	while (r > 0) {
+		r_total += r;
+		s = send_chunk(conn, buf, r);
+		if (r != s) {
+			/* Send error */
+			break;
+		}
+		r = mg_read(conn, buf, sizeof(buf));
+	}
+	mg_printf(conn, "0\r\n");
+
+	return 1;
+}
+
+
 int
 WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
 {
@@ -754,6 +850,8 @@ main(int argc, char *argv[])
 	    "DES-CBC3-SHA:AES128-SHA:AES128-GCM-SHA256",
 #endif
 #endif
+	    "enable_auth_domain_check",
+	    "no",
 	    0};
 	struct mg_callbacks callbacks;
 	struct mg_context *ctx;
@@ -849,6 +947,9 @@ main(int argc, char *argv[])
 	/* Add handler for /cookie example */
 	mg_set_request_handler(ctx, "/cookie", CookieHandler, 0);
 
+	/* Add handler for /postresponse example */
+	mg_set_request_handler(ctx, "/postresponse", PostResponser, 0);
+
 	/* Add HTTP site to open a websocket connection */
 	mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
 

+ 14 - 1
include/civetweb.h

@@ -432,7 +432,7 @@ CIVETWEB_API void mg_set_websocket_handler_with_subprotocols(
 
 /* mg_authorization_handler
 
-   Some description here
+   Callback function definition for mg_set_auth_handler
 
    Parameters:
       conn: current connection information.
@@ -484,6 +484,19 @@ CIVETWEB_API void *
 mg_get_user_connection_data(const struct mg_connection *conn);
 
 
+/* Get a formatted link corresponding to the current request
+
+   Parameters:
+      conn: current connection information.
+      buf: string buffer (out)
+      buflen: length of the string buffer
+   Returns:
+      <0: error
+      >=0: ok */
+CIVETWEB_API int
+mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen);
+
+
 #if defined(MG_LEGACY_INTERFACE)
 /* Return array of strings that represent valid configuration options.
    For each option, option name and default value is returned, i.e. the

+ 81 - 0
src/civetweb.c

@@ -2870,6 +2870,87 @@ mg_get_request_info(const struct mg_connection *conn)
 }
 
 
+int
+mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
+{
+	if ((buflen < 1) || (buf == 0) || (conn == 0)) {
+		return -1;
+	} else {
+
+		int truncated = 0;
+		const struct mg_request_info *ri = &conn->request_info;
+
+		if (ri->local_uri == NULL) {
+			return -1;
+		}
+
+		if ((ri->request_uri != NULL)
+		    && strcmp(ri->local_uri, ri->request_uri)) {
+			mg_snprintf(conn,
+			            &truncated,
+			            buf,
+			            buflen,
+			            "%s%s://%s",
+			            (is_websocket_protocol(conn) ? "ws" : "http"),
+			            (ri->is_ssl ? "s" : ""),
+			            ri->request_uri);
+			if (truncated) {
+				return -1;
+			}
+			return 0;
+		} else {
+
+#if USE_IPV6
+			int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
+			int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port)
+			                   : htons(conn->client.lsa.sin.sin_port);
+#else
+			int port = htons(conn->client.lsa.sin.sin_port);
+#endif
+			int def_port = ri->is_ssl ? 443 : 80;
+			int auth_domain_check_enabled =
+			    conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK]
+			    && (!strcmp(conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK],
+			                "yes"));
+			const char *server_domain =
+			    conn->ctx->config[AUTHENTICATION_DOMAIN];
+
+			char portstr[16];
+			char server_ip[48];
+
+			if (port != def_port) {
+				sprintf(portstr, ":%u", (unsigned)port);
+			} else {
+				portstr[0] = 0;
+			}
+
+			if (!auth_domain_check_enabled || !server_domain) {
+
+				sockaddr_to_string(server_ip,
+				                   sizeof(server_ip),
+				                   &conn->client.lsa);
+
+				server_domain = server_ip;
+			}
+
+			mg_snprintf(conn,
+			            &truncated,
+			            buf,
+			            buflen,
+			            "%s%s://%s%s%s",
+			            (is_websocket_protocol(conn) ? "ws" : "http"),
+			            (ri->is_ssl ? "s" : ""),
+			            server_domain,
+			            portstr,
+			            ri->local_uri);
+			if (truncated) {
+				return -1;
+			}
+			return 0;
+		}
+	}
+}
+
 /* Skip the characters until one of the delimiters characters found.
  * 0-terminate resulting word. Skip the delimiter and following whitespaces.
  * Advance pointer to buffer to the next word. Return found 0-terminated word.