#include "mg_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_header2(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. If the buffer size is not enough, allocates a buffer of required size and writes it to buf, similar to asprintf(). The caller should always check whether the buffer was updated, and free it if so.

This function is supposed to parse cookies, authentication headers, etc. Example (error handling omitted):

char user_buf[20];
char user = user_buf;
struct mg_str hdr = mg_get_http_header(hm, "Authorization");
mg_http_parse_header2(hdr, "username", &user, sizeof(user_buf));
// ... do something useful with user
if (user != user_buf) {
  free(user);
}

Returns the length of the variable's value. If variable is not found, 0 is returned.

int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
                         size_t buf_size)
#ifdef __GNUC__
    __attribute__((deprecated))
#endif
    ;

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

DEPRECATED: use mg_http_parse_header2() instead.

Same as mg_http_parse_header2(), but takes buffer as a char * (instead of char **), and thus it cannot allocate a new buffer if the provided one is not enough, and just returns 0 in that case.

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_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:

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.