mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-29 16:25:54 +08:00
aba60dadec
CL: none PUBLISHED_FROM=d6ebe5fa88c61ae3b8569897d9b09d54610bec73
541 lines
19 KiB
C
541 lines
19 KiB
C
/*
|
|
* === Server API reference
|
|
*/
|
|
|
|
#ifndef CS_MONGOOSE_SRC_HTTP_SERVER_H_
|
|
#define CS_MONGOOSE_SRC_HTTP_SERVER_H_
|
|
|
|
#if MG_ENABLE_HTTP
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
|
|
/*
|
|
* Parses a HTTP message.
|
|
*
|
|
* `is_req` should be set to 1 if parsing a request, 0 if reply.
|
|
*
|
|
* Returns the number of bytes parsed. If HTTP message is
|
|
* incomplete `0` is returned. On parse error, a negative number is returned.
|
|
*/
|
|
int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req);
|
|
|
|
/*
|
|
* Searches and returns the header `name` in parsed HTTP message `hm`.
|
|
* If header is not found, NULL is returned. Example:
|
|
*
|
|
* struct mg_str *host_hdr = mg_get_http_header(hm, "Host");
|
|
*/
|
|
struct mg_str *mg_get_http_header(struct http_message *hm, const char *name);
|
|
|
|
/*
|
|
* Parses the HTTP header `hdr`. Finds variable `var_name` and stores its value
|
|
* in the buffer `buf`, `buf_size`. Returns 0 if variable not found, non-zero
|
|
* otherwise.
|
|
*
|
|
* This function is supposed to parse cookies, authentication headers, etc.
|
|
* Example (error handling omitted):
|
|
*
|
|
* char user[20];
|
|
* struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
|
|
* mg_http_parse_header(hdr, "username", user, sizeof(user));
|
|
*
|
|
* Returns the length of the variable's value. If buffer is not large enough,
|
|
* or variable not found, 0 is returned.
|
|
*/
|
|
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
|
|
size_t buf_size);
|
|
|
|
/*
|
|
* Gets and parses the Authorization: Basic header
|
|
* Returns -1 if no Authorization header is found, or if
|
|
* mg_parse_http_basic_auth
|
|
* fails parsing the resulting header.
|
|
*/
|
|
int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
|
|
char *pass, size_t pass_len);
|
|
|
|
/*
|
|
* Parses the Authorization: Basic header
|
|
* Returns -1 iif the authorization type is not "Basic" or any other error such
|
|
* as incorrectly encoded base64 user password pair.
|
|
*/
|
|
int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len,
|
|
char *pass, size_t pass_len);
|
|
|
|
/*
|
|
* Parses the buffer `buf`, `buf_len` that contains multipart form data chunks.
|
|
* Stores the chunk name in a `var_name`, `var_name_len` buffer.
|
|
* If a chunk is an uploaded file, then `file_name`, `file_name_len` is
|
|
* filled with an uploaded file name. `chunk`, `chunk_len`
|
|
* points to the chunk data.
|
|
*
|
|
* Return: number of bytes to skip to the next chunk or 0 if there are
|
|
* no more chunks.
|
|
*
|
|
* Usage example:
|
|
*
|
|
* ```c
|
|
* static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* switch(ev) {
|
|
* case MG_EV_HTTP_REQUEST: {
|
|
* struct http_message *hm = (struct http_message *) ev_data;
|
|
* char var_name[100], file_name[100];
|
|
* const char *chunk;
|
|
* size_t chunk_len, n1, n2;
|
|
*
|
|
* n1 = n2 = 0;
|
|
* while ((n2 = mg_parse_multipart(hm->body.p + n1,
|
|
* hm->body.len - n1,
|
|
* var_name, sizeof(var_name),
|
|
* file_name, sizeof(file_name),
|
|
* &chunk, &chunk_len)) > 0) {
|
|
* printf("var: %s, file_name: %s, size: %d, chunk: [%.*s]\n",
|
|
* var_name, file_name, (int) chunk_len,
|
|
* (int) chunk_len, chunk);
|
|
* n1 += n2;
|
|
* }
|
|
* }
|
|
* break;
|
|
* ```
|
|
*/
|
|
size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
|
|
size_t var_name_len, char *file_name,
|
|
size_t file_name_len, const char **chunk,
|
|
size_t *chunk_len);
|
|
|
|
/*
|
|
* Fetches a HTTP form variable.
|
|
*
|
|
* Fetches a variable `name` from a `buf` into a buffer specified by `dst`,
|
|
* `dst_len`. The destination is always zero-terminated. Returns the length of
|
|
* a fetched variable. If not found, 0 is returned. `buf` must be valid
|
|
* url-encoded buffer. If destination is too small or an error occured,
|
|
* negative number is returned.
|
|
*/
|
|
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
|
|
size_t dst_len);
|
|
|
|
#if MG_ENABLE_FILESYSTEM
|
|
/*
|
|
* This structure defines how `mg_serve_http()` works.
|
|
* Best practice is to set only required settings, and leave the rest as NULL.
|
|
*/
|
|
struct mg_serve_http_opts {
|
|
/* Path to web root directory */
|
|
const char *document_root;
|
|
|
|
/* List of index files. Default is "" */
|
|
const char *index_files;
|
|
|
|
/*
|
|
* Leave as NULL to disable authentication.
|
|
* To enable directory protection with authentication, set this to ".htpasswd"
|
|
* Then, creating ".htpasswd" file in any directory automatically protects
|
|
* it with digest authentication.
|
|
* Use `mongoose` web server binary, or `htdigest` Apache utility to
|
|
* create/manipulate passwords file.
|
|
* Make sure `auth_domain` is set to a valid domain name.
|
|
*/
|
|
const char *per_directory_auth_file;
|
|
|
|
/* Authorization domain (domain name of this web server) */
|
|
const char *auth_domain;
|
|
|
|
/*
|
|
* Leave as NULL to disable authentication.
|
|
* Normally, only selected directories in the document root are protected.
|
|
* If absolutely every access to the web server needs to be authenticated,
|
|
* regardless of the URI, set this option to the path to the passwords file.
|
|
* Format of that file is the same as ".htpasswd" file. Make sure that file
|
|
* is located outside document root to prevent people fetching it.
|
|
*/
|
|
const char *global_auth_file;
|
|
|
|
/* Set to "no" to disable directory listing. Enabled by default. */
|
|
const char *enable_directory_listing;
|
|
|
|
/*
|
|
* SSI files pattern. If not set, "**.shtml$|**.shtm$" is used.
|
|
*
|
|
* All files that match ssi_pattern are treated as SSI.
|
|
*
|
|
* Server Side Includes (SSI) is a simple interpreted server-side scripting
|
|
* language which is most commonly used to include the contents of a file
|
|
* into a web page. It can be useful when it is desirable to include a common
|
|
* piece of code throughout a website, for example, headers and footers.
|
|
*
|
|
* In order for a webpage to recognize an SSI-enabled HTML file, the
|
|
* filename should end with a special extension, by default the extension
|
|
* should be either .shtml or .shtm
|
|
*
|
|
* Unknown SSI directives are silently ignored by Mongoose. Currently,
|
|
* the following SSI directives are supported:
|
|
* <!--#include FILE_TO_INCLUDE -->
|
|
* <!--#exec "COMMAND_TO_EXECUTE" -->
|
|
* <!--#call COMMAND -->
|
|
*
|
|
* Note that <!--#include ...> directive supports three path
|
|
*specifications:
|
|
*
|
|
* <!--#include virtual="path" --> Path is relative to web server root
|
|
* <!--#include abspath="path" --> Path is absolute or relative to the
|
|
* web server working dir
|
|
* <!--#include file="path" -->, Path is relative to current document
|
|
* <!--#include "path" -->
|
|
*
|
|
* The include directive may be used to include the contents of a file or
|
|
* the result of running a CGI script.
|
|
*
|
|
* The exec directive is used to execute
|
|
* a command on a server, and show command's output. Example:
|
|
*
|
|
* <!--#exec "ls -l" -->
|
|
*
|
|
* The call directive is a way to invoke a C handler from the HTML page.
|
|
* On each occurence of <!--#call COMMAND OPTIONAL_PARAMS> directive,
|
|
* Mongoose calls a registered event handler with MG_EV_SSI_CALL event,
|
|
* and event parameter will point to the COMMAND OPTIONAL_PARAMS string.
|
|
* An event handler can output any text, for example by calling
|
|
* `mg_printf()`. This is a flexible way of generating a web page on
|
|
* server side by calling a C event handler. Example:
|
|
*
|
|
* <!--#call foo --> ... <!--#call bar -->
|
|
*
|
|
* In the event handler:
|
|
* case MG_EV_SSI_CALL: {
|
|
* const char *param = (const char *) ev_data;
|
|
* if (strcmp(param, "foo") == 0) {
|
|
* mg_printf(c, "hello from foo");
|
|
* } else if (strcmp(param, "bar") == 0) {
|
|
* mg_printf(c, "hello from bar");
|
|
* }
|
|
* break;
|
|
* }
|
|
*/
|
|
const char *ssi_pattern;
|
|
|
|
/* IP ACL. By default, NULL, meaning all IPs are allowed to connect */
|
|
const char *ip_acl;
|
|
|
|
#if MG_ENABLE_HTTP_URL_REWRITES
|
|
/* URL rewrites.
|
|
*
|
|
* Comma-separated list of `uri_pattern=url_file_or_directory_path` rewrites.
|
|
* When HTTP request is received, Mongoose constructs a file name from the
|
|
* requested URI by combining `document_root` and the URI. However, if the
|
|
* rewrite option is used and `uri_pattern` matches requested URI, then
|
|
* `document_root` is ignored. Instead, `url_file_or_directory_path` is used,
|
|
* which should be a full path name or a path relative to the web server's
|
|
* current working directory. It can also be an URI (http:// or https://)
|
|
* in which case mongoose will behave as a reverse proxy for that destination.
|
|
*
|
|
* Note that `uri_pattern`, as all Mongoose patterns, is a prefix pattern.
|
|
*
|
|
* If uri_pattern starts with `@` symbol, then Mongoose compares it with the
|
|
* HOST header of the request. If they are equal, Mongoose sets document root
|
|
* to `file_or_directory_path`, implementing virtual hosts support.
|
|
* Example: `@foo.com=/document/root/for/foo.com`
|
|
*
|
|
* If `uri_pattern` starts with `%` symbol, then Mongoose compares it with
|
|
* the listening port. If they match, then Mongoose issues a 301 redirect.
|
|
* For example, to redirect all HTTP requests to the
|
|
* HTTPS port, do `%80=https://my.site.com`. Note that the request URI is
|
|
* automatically appended to the redirect location.
|
|
*/
|
|
const char *url_rewrites;
|
|
#endif
|
|
|
|
/* DAV document root. If NULL, DAV requests are going to fail. */
|
|
const char *dav_document_root;
|
|
|
|
/*
|
|
* DAV passwords file. If NULL, DAV requests are going to fail.
|
|
* If passwords file is set to "-", then DAV auth is disabled.
|
|
*/
|
|
const char *dav_auth_file;
|
|
|
|
/* Glob pattern for the files to hide. */
|
|
const char *hidden_file_pattern;
|
|
|
|
/* Set to non-NULL to enable CGI, e.g. **.cgi$|**.php$" */
|
|
const char *cgi_file_pattern;
|
|
|
|
/* If not NULL, ignore CGI script hashbang and use this interpreter */
|
|
const char *cgi_interpreter;
|
|
|
|
/*
|
|
* Comma-separated list of Content-Type overrides for path suffixes, e.g.
|
|
* ".txt=text/plain; charset=utf-8,.c=text/plain"
|
|
*/
|
|
const char *custom_mime_types;
|
|
|
|
/*
|
|
* Extra HTTP headers to add to each server response.
|
|
* Example: to enable CORS, set this to "Access-Control-Allow-Origin: *".
|
|
*/
|
|
const char *extra_headers;
|
|
};
|
|
|
|
/*
|
|
* Serves given HTTP request according to the `options`.
|
|
*
|
|
* Example code snippet:
|
|
*
|
|
* ```c
|
|
* static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* struct http_message *hm = (struct http_message *) ev_data;
|
|
* struct mg_serve_http_opts opts = { .document_root = "/var/www" }; // C99
|
|
*
|
|
* switch (ev) {
|
|
* case MG_EV_HTTP_REQUEST:
|
|
* mg_serve_http(nc, hm, opts);
|
|
* break;
|
|
* default:
|
|
* break;
|
|
* }
|
|
* }
|
|
* ```
|
|
*/
|
|
void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
|
|
struct mg_serve_http_opts opts);
|
|
|
|
/*
|
|
* Serves a specific file with a given MIME type and optional extra headers.
|
|
*
|
|
* Example code snippet:
|
|
*
|
|
* ```c
|
|
* static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* switch (ev) {
|
|
* case MG_EV_HTTP_REQUEST: {
|
|
* struct http_message *hm = (struct http_message *) ev_data;
|
|
* mg_http_serve_file(nc, hm, "file.txt",
|
|
* mg_mk_str("text/plain"), mg_mk_str(""));
|
|
* break;
|
|
* }
|
|
* ...
|
|
* }
|
|
* }
|
|
* ```
|
|
*/
|
|
void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
|
|
const char *path, const struct mg_str mime_type,
|
|
const struct mg_str extra_headers);
|
|
|
|
#if MG_ENABLE_HTTP_STREAMING_MULTIPART
|
|
|
|
/* Callback prototype for `mg_file_upload_handler()`. */
|
|
typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc,
|
|
struct mg_str fname);
|
|
|
|
/*
|
|
* File upload handler.
|
|
* This handler can be used to implement file uploads with minimum code.
|
|
* This handler will process MG_EV_HTTP_PART_* events and store file data into
|
|
* a local file.
|
|
* `local_name_fn` will be invoked with whatever name was provided by the client
|
|
* and will expect the name of the local file to open. A return value of NULL
|
|
* will abort file upload (client will get a "403 Forbidden" response). If
|
|
* non-null, the returned string must be heap-allocated and will be freed by
|
|
* the caller.
|
|
* Exception: it is ok to return the same string verbatim.
|
|
*
|
|
* Example:
|
|
*
|
|
* ```c
|
|
* struct mg_str upload_fname(struct mg_connection *nc, struct mg_str fname) {
|
|
* // Just return the same filename. Do not actually do this except in test!
|
|
* // fname is user-controlled and needs to be sanitized.
|
|
* return fname;
|
|
* }
|
|
* void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* switch (ev) {
|
|
* ...
|
|
* case MG_EV_HTTP_PART_BEGIN:
|
|
* case MG_EV_HTTP_PART_DATA:
|
|
* case MG_EV_HTTP_PART_END:
|
|
* mg_file_upload_handler(nc, ev, ev_data, upload_fname);
|
|
* break;
|
|
* }
|
|
* }
|
|
* ```
|
|
*/
|
|
void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
|
|
mg_fu_fname_fn local_name_fn
|
|
MG_UD_ARG(void *user_data));
|
|
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
|
|
#endif /* MG_ENABLE_FILESYSTEM */
|
|
|
|
/*
|
|
* Registers a callback for a specified http endpoint
|
|
* Note: if callback is registered it is called instead of the
|
|
* callback provided in mg_bind
|
|
*
|
|
* Example code snippet:
|
|
*
|
|
* ```c
|
|
* static void handle_hello1(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* (void) ev; (void) ev_data;
|
|
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello1]");
|
|
* nc->flags |= MG_F_SEND_AND_CLOSE;
|
|
* }
|
|
*
|
|
* static void handle_hello2(struct mg_connection *nc, int ev, void *ev_data) {
|
|
* (void) ev; (void) ev_data;
|
|
* mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n[I am Hello2]");
|
|
* nc->flags |= MG_F_SEND_AND_CLOSE;
|
|
* }
|
|
*
|
|
* void init() {
|
|
* nc = mg_bind(&mgr, local_addr, cb1);
|
|
* mg_register_http_endpoint(nc, "/hello1", handle_hello1);
|
|
* mg_register_http_endpoint(nc, "/hello1/hello2", handle_hello2);
|
|
* }
|
|
* ```
|
|
*/
|
|
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
|
|
MG_CB(mg_event_handler_t handler,
|
|
void *user_data));
|
|
|
|
struct mg_http_endpoint_opts {
|
|
void *user_data;
|
|
/* Authorization domain (realm) */
|
|
const char *auth_domain;
|
|
const char *auth_file;
|
|
};
|
|
|
|
void mg_register_http_endpoint_opt(struct mg_connection *nc,
|
|
const char *uri_path,
|
|
mg_event_handler_t handler,
|
|
struct mg_http_endpoint_opts opts);
|
|
|
|
/*
|
|
* Authenticates a HTTP request against an opened password file.
|
|
* Returns 1 if authenticated, 0 otherwise.
|
|
*/
|
|
int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
|
|
FILE *fp);
|
|
|
|
/*
|
|
* Authenticates given response params against an opened password file.
|
|
* Returns 1 if authenticated, 0 otherwise.
|
|
*
|
|
* It's used by mg_http_check_digest_auth().
|
|
*/
|
|
int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
|
|
struct mg_str username, struct mg_str cnonce,
|
|
struct mg_str response, struct mg_str qop,
|
|
struct mg_str nc, struct mg_str nonce,
|
|
struct mg_str auth_domain, FILE *fp);
|
|
|
|
/*
|
|
* Sends buffer `buf` of size `len` to the client using chunked HTTP encoding.
|
|
* This function sends the buffer size as hex number + newline first, then
|
|
* the buffer itself, then the newline. For example,
|
|
* `mg_send_http_chunk(nc, "foo", 3)` will append the `3\r\nfoo\r\n` string
|
|
* to the `nc->send_mbuf` output IO buffer.
|
|
*
|
|
* NOTE: The HTTP header "Transfer-Encoding: chunked" should be sent prior to
|
|
* using this function.
|
|
*
|
|
* NOTE: do not forget to send an empty chunk at the end of the response,
|
|
* to tell the client that everything was sent. Example:
|
|
*
|
|
* ```
|
|
* mg_printf_http_chunk(nc, "%s", "my response!");
|
|
* mg_send_http_chunk(nc, "", 0); // Tell the client we're finished
|
|
* ```
|
|
*/
|
|
void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len);
|
|
|
|
/*
|
|
* Sends a printf-formatted HTTP chunk.
|
|
* Functionality is similar to `mg_send_http_chunk()`.
|
|
*/
|
|
void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...);
|
|
|
|
/*
|
|
* Sends the response status line.
|
|
* If `extra_headers` is not NULL, then `extra_headers` are also sent
|
|
* after the response line. `extra_headers` must NOT end end with new line.
|
|
* Example:
|
|
*
|
|
* mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
|
|
*
|
|
* Will result in:
|
|
*
|
|
* HTTP/1.1 200 OK\r\n
|
|
* Access-Control-Allow-Origin: *\r\n
|
|
*/
|
|
void mg_send_response_line(struct mg_connection *nc, int status_code,
|
|
const char *extra_headers);
|
|
|
|
/*
|
|
* Sends an error response. If reason is NULL, the message will be inferred
|
|
* from the error code (if supported).
|
|
*/
|
|
void mg_http_send_error(struct mg_connection *nc, int code, const char *reason);
|
|
|
|
/*
|
|
* Sends a redirect response.
|
|
* `status_code` should be either 301 or 302 and `location` point to the
|
|
* new location.
|
|
* If `extra_headers` is not empty, then `extra_headers` are also sent
|
|
* after the response line. `extra_headers` must NOT end end with new line.
|
|
*
|
|
* Example:
|
|
*
|
|
* mg_http_send_redirect(nc, 302, mg_mk_str("/login"), mg_mk_str(NULL));
|
|
*/
|
|
void mg_http_send_redirect(struct mg_connection *nc, int status_code,
|
|
const struct mg_str location,
|
|
const struct mg_str extra_headers);
|
|
|
|
/*
|
|
* Sends the response line and headers.
|
|
* This function sends the response line with the `status_code`, and
|
|
* automatically
|
|
* sends one header: either "Content-Length" or "Transfer-Encoding".
|
|
* If `content_length` is negative, then "Transfer-Encoding: chunked" header
|
|
* is sent, otherwise, "Content-Length" header is sent.
|
|
*
|
|
* NOTE: If `Transfer-Encoding` is `chunked`, then message body must be sent
|
|
* using `mg_send_http_chunk()` or `mg_printf_http_chunk()` functions.
|
|
* Otherwise, `mg_send()` or `mg_printf()` must be used.
|
|
* Extra headers could be set through `extra_headers`. Note `extra_headers`
|
|
* must NOT be terminated by a new line.
|
|
*/
|
|
void mg_send_head(struct mg_connection *n, int status_code,
|
|
int64_t content_length, const char *extra_headers);
|
|
|
|
/*
|
|
* Sends a printf-formatted HTTP chunk, escaping HTML tags.
|
|
*/
|
|
void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...);
|
|
|
|
#if MG_ENABLE_HTTP_URL_REWRITES
|
|
/*
|
|
* Proxies a given request to a given upstream http server. The path prefix
|
|
* in `mount` will be stripped of the path requested to the upstream server,
|
|
* e.g. if mount is /api and upstream is http://localhost:8001/foo
|
|
* then an incoming request to /api/bar will cause a request to
|
|
* http://localhost:8001/foo/bar
|
|
*
|
|
* EXPERIMENTAL API. Please use http_serve_http + url_rewrites if a static
|
|
* mapping is good enough.
|
|
*/
|
|
void mg_http_reverse_proxy(struct mg_connection *nc,
|
|
const struct http_message *hm, struct mg_str mount,
|
|
struct mg_str upstream);
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
|
|
#endif /* MG_ENABLE_HTTP */
|
|
|
|
#endif /* CS_MONGOOSE_SRC_HTTP_SERVER_H_ */
|