HTTP
struct mg_http_header
struct mg_http_header {
struct mg_str name; // Header name
struct mg_str value; // Header value
};
Structure represents HTTP header, like Content-Type: text/html.
Content-Type is a header name and text/html is a header value.
struct mg_http_message
struct mg_http_message {
struct mg_str method, uri, query, proto; // Request/response line
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
struct mg_str body; // Body
struct mg_str message; // Request line + headers + body
};
Structure represents the HTTP message.
mg_http_listen()
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data);
Create HTTP listener.
Parameters:
mgr- An event managerurl- A URL, specifies local IP address and port to listen on, e.g.http://0.0.0.0:8000. If this URL is 'https', theis_tlsflag will be setfn- An event handler functionfn_data- an arbitrary pointer, which will be stored in the connection structure asc->fn_data, so the event handler can use it when called.
Return value: Pointer to created connection or NULL in case of error
Usage example:
struct mg_connection *c = mg_http_listen(&mgr, "0.0.0.0:8000", fn, arg);
if (c == NULL) fatal_error("Cannot create listener");
mg_http_connect()
struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data);
Create HTTP client connection.
Parameters:
mgr- An event managerurl- A URL, specifies the remote URL, e.g.http://google.com. If this URL is 'https', theis_tlsflag will be set. See mg_connect()fn- An event handler functionfn_data- an arbitrary pointer, which will be stored in the connection structure asc->fn_data, so the event handler can use it when called.
Return value: created connection, or NULL on error. Possible errors are: not enough memory, a NULL URL, or, in the case of our built-in TCP/IP stack, the network not being ready.
Note: This function does not connect to the requested peer, it allocates required resources and starts the connection process. Once our peer is really connected, an MG_EV_CONNECT event is sent
to the connection event handler.
Usage example:
struct mg_connection *c = mg_http_connect(&mgr, "http://google.com", fn, NULL);
if (c == NULL) fatal_error("Cannot create connection");
mg_http_status()
int mg_http_status(const struct mg_http_message *hm);
Get status code of the HTTP response. Parameters:
hm- Parsed HTTP response
Return value: status code, e.g. 200 for success.
mg_http_get_request_len()
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
Get length of request.
The length of request is a number of bytes till the end of HTTP headers. It does not include length of HTTP body.
Parameters:
buf- A pointer to a buffer with requestbuf_len- Buffer length
Return value: -1 on error, 0 if a message is incomplete, or the length of request
Usage example:
const char *buf = "GET /test \n\nGET /foo\n\n";
int req_len = mg_http_get_request_len(buf, strlen(buf)); // req_len == 12
mg_http_parse()
int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm);
Parse string request into mg_http_message structure
Parameters:
s- A request stringlen- A request string lengthhm- A pointer to a structure to store parsed request
Return value: request length (see mg_http_get_request_len())
Usage example:
struct mg_http_message hm;
const char *buf = "GET / HTTP/1.0\n\n";
if (mg_http_parse(buf, strlen(buf), &hm) > 0) { /* success */ }
mg_http_printf_chunk()
void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...);
Write a chunk of data in chunked encoding format, using printf() semantic.
Parameters:
c- A connection pointerfmt- A string, format specified inprintfsemantics
Return value: None
Usage example:
mg_http_printf_chunk(c, "Hello, %s!", "world");
mg_http_write_chunk()
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
Write a chunk of data in chunked encoding format.
Parameters:
c- A connection pointerbuf- Data to writelen- Data length
Return value: None
Usage example:
mg_http_write_chunk(c, "hi", 2);
struct mg_http_serve_opts
struct mg_http_serve_opts {
const char *root_dir; // Web root directory, must be non-NULL
const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml
const char *extra_headers; // Extra HTTP headers to add in responses
const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,..
const char *page404; // Path to the 404 page, or NULL by default
struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX
};
A structure passed to mg_http_serve_dir() and mg_http_serve_file(), which
drives the behavior of those two functions.
In addition to overwriting autodetection based on an extension, you can also use * as an extension in mime_types to force a particular MIME type for unknown extensions:
sopts.mime_types = "*=preferred/default,txt=override/text"
mg_http_serve_dir()
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
const struct mg_http_serve_opts *opts);
Serve static files according to the given options. Files can also be gzip compressed, including the directory index. All compressed files must end in .gz and there must not exist a file with the same name without the extension, otherwise it will take precedence; see mg_http_serve_file()
NOTE: In order to enable SSI, you need to set the
-DMG_ENABLE_SSI=1build flag.
NOTE: Avoid double dots
..in theroot_dir. If you need to reference an upper-level directory, use an absolute path.
Parameters:
c- Connection to usehm- HTTP message, that should be servedopts- Serve options. Note thatopts.root_dircan optionally accept extra comma-separateduri=pathpairs, see example below
Return value: None
Usage example:
// Mongoose events handler
void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts));
opts.root_dir = "/var/www,/conf=/etc"; // Serve /var/www. URIs starting with /conf are served from /etc
mg_http_serve_dir(c, hm, &opts);
}
}
mg_http_serve_file()
void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
const char *path, struct mg_http_serve_opts *opts);
Serve a static file. If a file with the filename specified in path does not exist, Mongoose tries appending .gz; and if such a file exists, it will serve it with a Content-Encoding: gzip header
NOTE:
opts->root_dirsettings is ignored by this function.
NOTE:
opts->extra_headers, if not NULL, must end with\r\n.
Parameters:
c- Connection to usehm- HTTP message to servepath- Path to file to serveopts- Serve options
Return value: None
Usage example:
// Mongoose events handler
void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_http_serve_opts opts = {
.mime_types = "png=image/png",
.extra_headers = "AA: bb\r\nCC: dd\r\n"
};
mg_http_serve_file(c, hm, "a.png", &opts);
}
}
mg_http_reply()
void mg_http_reply(struct mg_connection *c, int status_code,
const char *headers, const char *body_fmt, ...);
Send simple HTTP response using printf() semantic. This function formats
response body according to a body_fmt, and automatically appends a correct
Content-Length header. Extra headers could be passed via headers parameter.
Parameters:
c- Connection to usestatus_code- An HTTP response codeheaders- Extra headers, default NULL. If not NULL, must end with\r\nfmt- A format string for the HTTP body, in a printf semantics
Return value: None
Usage examples:
Send a simple JSON response:
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\": %d}", 123);
Send JSON response:
char *json = mg_mprintf("{%m:%d}", MG_ESC("name"), 123);
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\n", json);
mg_free(json);
Send a 302 redirect:
mg_http_reply(c, 302, "Location: /\r\n", "");
Send error:
mg_http_reply(c, 403, "", "%s", "Not Authorized\n");
mg_http_get_header()
struct mg_str *mg_http_get_header(struct mg_http_message *hm, const char *name);
Get HTTP header value
Parameters:
hm- HTTP message to look for headername- Header name
Return value: HTTP header value or NULL if not found
Usage example:
// Mongoose event handler
void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_str *s = mg_http_get_header(hm, "X-Extra-Header");
if (s != NULL) {
mg_http_reply(c, 200, "", "Holly molly! Header value: %.*s", (int) s->len, s->buf);
} else {
mg_http_reply(c, 200, "", "Oh no, header is not set...");
}
}
}
mg_http_get_header_var()
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
Parse HTTP header (e.g. Cookie header) which has form
name1=value1; name2=value2; ... and fetch a given variable.
Parameters:
s- HTTP headername- variable name name
Return value: a requested variable, or an empty string.
Usage example:
struct mg_str *cookie = mg_http_get_header(hm, "Cookie");
struct mg_str token = mg_str("");
if (cookie != NULL) {
token = mg_http_get_header_var(*cookie, mg_str("access_token"));
}
mg_http_var()
struct mg_str mg_http_var(struct mg_str buf, struct mg_str name);
Fetch an undecoded HTTP variable. Parameters:
buf- a url-encoded string: HTTP request body or query stringname- a variable name to fetch
Return value: variable's value. If not found, it is a NULL string.
// We have received a request to /my/uri?a=b&c=d%20
// The hm->query points to "a=b&c=d%20"
struct mg_str v = mg_http_var(hm->query, mg_str("c")); // v = "d%20"
mg_http_get_var()
int mg_http_get_var(const struct mg_str *var, const char *name, char *buf, int len);
Fetch and decode an HTTP variable
Parameters:
var- HTTP request bodyname- Variable namebuf- Buffer to write decoded variablelen- Buffer size
Return value: Length of decoded variable. A zero or negative value means error
Usage example:
char buf[100] = "";
mg_http_get_var(&hm->body, "key1", buf, sizeof(buf)) {
...
}
mg_http_creds()
void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
char *pass, size_t passlen);
Fetch authentication credential from the request, and store into the
user, userlen and pass, passlen buffers. The credentials are looked
up in the following order:
- from the
AuthorizationHTTP header,- Basic auth fills both user and pass
- Bearer auth fills only pass
- from the
access_tokencookie, fills pass - from the
?access_token=...query string parameter, fills pass
If none is found, then both user and pass are set to empty nul-terminated strings.
Parameters:
hm- HTTP message to look for credentialsuser- buffer to receive user nameuserlen- size ofuserbufferpass- buffer to receive passwordpasslen- size ofpassbuffer
Return value: None
Usage example:
// Mongoose events handler
void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
char user[100], pass[100];
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass)); // "user" is now user name and "pass" is now password from request
}
}
mg_http_bauth()
void mg_http_bauth(struct mg_connection *c, const char *user, const char *pass);
Write a Basic Authorization header to the output buffer.
Parameters:
c- Connection to useuser- User namepass- Password
Return value: None
Usage example which uses Basic auth to create Stripe subscription:
mg_printf(c, "POST /v1/subscriptions HTTP/1.1\r\n"
"Host: api.stripe.com\r\n"
"Transfer-Encoding: chunked\r\n");
mg_http_bauth(c, stripe_private_key, NULL); // Add Basic auth header
mg_printf(c, "%s", "\r\n"); // End HTTP headers
mg_http_printf_chunk(c, "&customer=%s", customer_id); // Set customer
mg_http_printf_chunk(c, "&items[0][price]=%s", price); // And price
mg_http_printf_chunk(c, ""); // End request
struct mg_http_part
// Parameter for mg_http_next_multipart
struct mg_http_part {
struct mg_str name; // Form field name
struct mg_str filename; // Filename for file uploads
struct mg_str body; // Part contents
};
Structure that describes a single part of a HTTP multipart message.
mg_http_next_multipart()
size_t mg_http_next_multipart(struct mg_str body, size_t offset, struct mg_http_part *part);
Parse the multipart chunk in the body at a given offset. An initial
offset should be 0. Fill up parameters in the provided part, which could be
NULL. Return offset to the next chunk, or 0 if there are no more chunks.
Parameters:
body- Message bodyoffset- Start offsetpart- Pointer tostruct mg_http_partto fill
Return value: offset to the next chunk, or 0 if there are no more chunks.
struct mg_http_part part;
size_t pos = 0;
while ((pos = mg_http_next_multipart(body, pos, &part)) != 0) {
MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
part.name.len, part.name.buf,
part.filename.len, part.filename.buf, part.body.len));
// Use this chunk ....
}
A diagram below shows how mg_http_next_multipart() in action:
mg_http_upload()
long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *dir, size_t max_size);
This is a helper utility function that is used to upload large files by small chunks.
Append HTTP POST data to a file in a specified directory. A file name and
file offset are specified by the query string parameters:
POST /upload?file=firmware.bin&offset=2048 HTTP/1.1. If the offset is 0, then the
file is truncated. It is the client's responsibility to divide files into
smaller chunks and send a sequence of POST requests that will be handled by
this function. The full path will be checked for sanity
Parameters:
c- a connectionhm- a parsed HTTP messagefs- a filesystem where to write the files, e.g.&mg_fs_posixdir- a directory path where to write the filesmax_size- maximum allowed file size
Return value: file size after write, or negative number on error
Usage example:
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/upload"), NULL)) {
mg_http_upload(c, hm, &mg_fs_posix, "/tmp", 99999);
} else {
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve
mg_http_serve_dir(c, ev_data, &opts); // static content
}
}
}
mg_http_start_upload()
void mg_http_start_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_str name, struct mg_str dir,
struct mg_fs *fs,
void (*fn)(struct mg_connection *, const char *));
Start streaming an HTTP request body into a file. This helper is intended to be
called from the MG_EV_HTTP_HDRS event, after HTTP headers have been parsed but
before the whole body has been received. It takes over the connection handler,
writes incoming body data to dir/name, and calls fn when the upload finishes
or fails.
Unlike mg_http_upload(), this function does not require the client to split a
file into offset-based chunks. The client sends one POST or PUT request with a
valid Content-Length, and Mongoose streams the body as it arrives.
The file name is checked with mg_path_is_sane(). Path traversal names such as
../file.bin are rejected and reported to the callback.
Parameters:
c- a connectionhm- a parsed HTTP messagename- file name to create underdirdir- target directoryfs- filesystem where to write the file, e.g.&mg_fs_posixfn- completion callback; receivesNULLon success, or an error message on failure
Return value: none
Usage example:
static void upload_done(struct mg_connection *c, const char *errmsg) {
mg_http_reply(c, errmsg == NULL ? 200 : 400, "", "%s\n",
errmsg == NULL ? "ok" : errmsg);
c->is_draining = 1;
}
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/upload/#"), NULL)) {
struct mg_str name = mg_str_n(hm->uri.buf + 8, hm->uri.len - 8);
mg_http_start_upload(c, hm, name, mg_str("/tmp"), &mg_fs_posix,
upload_done);
}
}
}
mg_http_start_ota()
void mg_http_start_ota(struct mg_connection *c, struct mg_http_message *hm,
void (*fn)(struct mg_connection *, const char *));
Start streaming an HTTP request or response body into the OTA writer. This
helper is intended to be called from MG_EV_HTTP_HDRS, after the headers are
available and the firmware image size is known from Content-Length.
The function calls mg_ota_begin(hm->body.len), streams incoming body data with
mg_ota_write(), then calls mg_ota_end() when all expected bytes have been
received. The completion callback receives NULL on success, or an error
message such as ota begin failed, write error, OTA finalize failed, or
connection closed.
Parameters:
c- a connectionhm- a parsed HTTP messagefn- completion callback; receivesNULLon success, or an error message on failure
Return value: none
Usage example:
static void ota_done(struct mg_connection *c, const char *errmsg) {
mg_http_reply(c, errmsg == NULL ? 200 : 500, "", "%s\n",
errmsg == NULL ? "ok" : errmsg);
c->is_draining = 1;
}
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_start_ota(c, hm, ota_done);
}
}
}