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.

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 manager
  • url - A URL, specifies local IP address and port to listen on, e.g. http://0.0.0.0:8000. If this URL is 'https', the is_tls flag will be set
  • fn - An event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->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 manager
  • url - A URL, specifies remote URL, e.g. http://google.com. If this URL is 'https', the is_tls flag will be set
  • fn - An event handler function
  • fn_data - an arbitrary pointer, which will be stored in the connection structure as c->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 request
  • buf_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
Function mg_http_get_request_len()

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 string
  • len - A request string length
  • hm - 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 pointer
  • fmt - A string, format specified in printf semantics

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 pointer
  • buf - Data to write
  • len - 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=1 build flag.

NOTE: Avoid double dots .. in the root_dir. If you need to reference an upper-level directory, use an absolute path.

Parameters:

  • c - Connection to use
  • hm - HTTP message, that should be served
  • opts - Serve options. Note that opts.root_dir can optionally accept extra comma-separated uri=path pairs, 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_dir settings is ignored by this function.

NOTE: opts->extra_headers, if not NULL, must end with \r\n.

Parameters:

  • c - Connection to use
  • hm - HTTP message to serve
  • path - Path to file to serve
  • opts - 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 use
  • status_code - An HTTP response code
  • headers - Extra headers, default NULL. If not NULL, must end with \r\n
  • fmt - A format string for the HTTP body, in a printf semantics

Return value: None

Function mg_http_reply()

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 header
  • name - 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 header
  • name - 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 string
  • name - 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 body
  • name - Variable name
  • buf - Buffer to write decoded variable
  • len - 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 Authorization HTTP header,
    • Basic auth fills both user and pass
    • Bearer auth fills only pass
  • from the access_token cookie, 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 credentials
  • user - buffer to receive user name
  • userlen - size of user buffer
  • pass - buffer to receive password
  • passlen - size of pass buffer

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 use
  • user - User name
  • pass - 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.

HTTP part

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 body
  • offset - Start offset
  • part - Pointer to struct mg_http_part to fill

Return value: offset to the next chunk, or 0 if there are no more chunks.

Usage example (or see form upload tutorial ):

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:

Function mg_http_next_multipart()

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 connection
  • hm - a parsed HTTP message
  • fs - a filesystem where to write the files, e.g. &mg_fs_posix
  • dir - a directory path where to write the files
  • max_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
    }
  }
}