#include "http_server.h"

int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req);

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.

struct mg_str *mg_get_http_header(struct http_message *hm, const char *name);

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");

int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
                         size_t buf_size);

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_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
                           char *pass, size_t pass_len);

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_parse_http_basic_auth(struct mg_str *hdr, 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.

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);

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:

   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;

int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
                    size_t dst_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.

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$|**.shtmDOC_CONTENTquot; 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");

This structure defines how mg_serve_http() works. Best practice is to set only required settings, and leave the rest as NULL.

void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
                   struct mg_serve_http_opts opts);

Serves given HTTP request according to the options.

Example code snippet:

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_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);

Serves a specific file with a given MIME type and optional extra headers.

Example code snippet:

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;
    }
    ...
  }
}

typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc,
                                        struct mg_str fname);

Callback prototype for mg_file_upload_handler().

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));

File upload handler. This handler can be used to implement file uploads with minimum code. This handler will process MG_EV_HTTPPART 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:

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_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
                               MG_CB(mg_event_handler_t handler,
                                     void *user_data));

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:

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);
}

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);

int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
                              FILE *fp);

Authenticates a HTTP request against an opened password file. Returns 1 if authenticated, 0 otherwise.

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);

Authenticates given response params against an opened password file. Returns 1 if authenticated, 0 otherwise.

It's used by mg_http_check_digest_auth().

void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len);

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_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...);

Sends a printf-formatted HTTP chunk. Functionality is similar to mg_send_http_chunk().

void mg_send_response_line(struct mg_connection *nc, int status_code,
                           const char *extra_headers);

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_http_send_error(struct mg_connection *nc, int code, const char *reason);

Sends an error response. If reason is NULL, the message will be inferred from the error code (if supported).

void mg_http_send_redirect(struct mg_connection *nc, int status_code,
                           const struct mg_str location,
                           const struct mg_str extra_headers);

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_send_head(struct mg_connection *n, int status_code,
                  int64_t content_length, const char *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_printf_html_escape(struct mg_connection *nc, const char *fmt, ...);

Sends a printf-formatted HTTP chunk, escaping HTML tags.

void mg_http_reverse_proxy(struct mg_connection *nc,
                           const struct http_message *hm, struct mg_str mount,
                           struct mg_str upstream);

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.