diff --git a/docs/README.md b/docs/README.md
index 07bd84aaf74f589f6f7bcde5f0bd90434f8d9886..38725453db619566995d00e1a3519cf249fab3d2 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -28,55 +28,57 @@ event-driven application:
 
 **Step 1.** Declare and initialize an event manager:
 
-  ```c
-  struct mg_mgr mgr;
-  mg_mgr_init(&mgr);
-  ```
+```c
+struct mg_mgr mgr;
+mg_mgr_init(&mgr);
+```
 
 **Step 2.** Create connections. For example, a server application should create listening
   connections. When any connection is created (listening or outgoing), an
   event handler function must be specified. An event handler function defines
   connection's behavior.
 
-  ```c
-  struct mg_connection *c = mg_http_listen(&mgr, "0.0.0.0:8000", fn, arg);
-  ```
+```c
+static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+// ...
+}
+
+struct mg_connection *c = mg_http_listen(&mgr, "0.0.0.0:8000", fn, arg);
+```
 
 **Step 3.** Create an event loop by calling `mg_mgr_poll()`:
 
-  ```c
-   for (;;) {
-     mg_mgr_poll(&mgr, 1000);
-   }
-  ```
+```c
+  for (;;) {
+    mg_mgr_poll(&mgr, 1000);
+  }
+```
 
-`mg_mgr_poll()` iterates over all sockets, accepts new connections, sends and
+`mg_mgr_poll()` iterates over all connections, accepts new connections, sends and
 receives data, closes connections and calls event handler functions for the
-respective events. 
+respective events.
 
-Since the Mongoose's core is not protected against concurrent accesses,
-make sure that all `mg_*` API functions are called from the same thread
-or RTOS task.
+<span class="badge bg-danger">NOTE: </span>Since the Mongoose's core is not protected against concurrent accesses,
+make sure that all `mg_*` API functions are called from the same thread or RTOS task.
 
 ## Send and receive buffers
 
-
 Each connection has a send and receive buffer:
 - `struct mg_connection::send` - data to be sent to a peer
 - `struct mg_connection::recv` - data received from a peer
 
 When data arrives, Mongoose appends received data to the `recv` and triggers an
 `MG_EV_READ` event. The user may send data back by calling one of the output
-functions, like `mg_send()` or `mg_printf()`. Output functions append data to
-the `send` buffer.  When Mongoose successfully writes data to the socket, it
-discards data from struct `mg_connection::send` and sends an `MG_EV_SEND`
-event.
+functions, like `mg_send()`, `mg_printf()` or protocol specific function like
+`mg_ws_send`. Output functions append data to the `send` buffer.  When Mongoose
+successfully writes data to the socket, it discards data from struct `mg_connection::send`
+and sends an `MG_EV_SEND` event.
 
 ## Event handler function
 
 Each connection has an event handler function associated with it. That function
 must be implemented by the user. Event handler is the key element of the
-Mongoose application, since it defines the connection's behaviour. This is
+Mongoose application, since it defines the connection's behavior. This is
 what an event handler function looks like:
 
 ```c
@@ -124,6 +126,7 @@ enum {
   MG_EV_WRITE,      // Data written to socket       int *num_bytes_written
   MG_EV_CLOSE,      // Connection closed            NULL
   MG_EV_HTTP_MSG,   // HTTP request/response        struct mg_http_message *
+  MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg)     struct mg_http_message *
   MG_EV_WS_OPEN,    // Websocket handshake done     struct mg_http_message *
   MG_EV_WS_MSG,     // Websocket msg, text or bin   struct mg_ws_message *
   MG_EV_WS_CTL,     // Websocket control msg        struct mg_ws_message *
@@ -144,7 +147,7 @@ that connection is UDP or not.  Some flags can be changed by application, for
 example, `is_draining` flag, if set by an application, tells Mongoose to send
 the remaining data to peer, and when everything is sent, close the connection.
 
-User-changeable flags are: `is_hexdumping`, `is_draining`, `is_closing`.
+<span class="badge bg-danger">NOTE: </span>User-changeable flags are: `is_hexdumping`, `is_draining`, `is_closing`.
 
 This is taken from `mongoose.h` as-is:
 
@@ -190,11 +193,9 @@ $ cc app2.c mongoose.c -D MG_ARCH=MG_ARCH_FREERTOS_LWIP       # Set architecture
 $ cc app3.c mongoose.c -D MG_ENABLE_SSI=0 -D MG_ENABLE_LOG=0  # Multiple options
 ```
 
-The list of supported
-architectures is defined in the
-[arch.h](https://github.com/cesanta/mongoose/blob/master/src/arch.h) header
-file. Normally, there is no need to explicitly specify the architecture.  The
-architecture is guessed during the build, so setting it is not usually required.
+The list of supported architectures is defined in the [arch.h](https://github.com/cesanta/mongoose/blob/master/src/arch.h)
+header file. Normally, there is no need to explicitly specify the architecture.
+The architecture is guessed during the build, so setting it is not usually required.
 
 | Name | Description |
 | ---- | ----------- |
@@ -206,13 +207,11 @@ architecture is guessed during the build, so setting it is not usually required.
 |MG_ARCH_FREERTOS_TCP | All systems with FreeRTOS kernel and FreeRTOS-Plus-TCP IP stack |
 |MG_ARCH_CUSTOM | A custom architecture, discussed in the next section |
 
-
 The other class of build constants is defined in
 [src/config.h](https://github.com/cesanta/mongoose/blob/master/src/config.h)
 together with their default values. They are tunables that include/exclude
 a certain functionality or change relevant parameters.
 
-
 Here is a list of build constants and their default values:
 
 | Name | Default | Description |
@@ -232,7 +231,6 @@ Here is a list of build constants and their default values:
 |MG_MAX_HTTP_HEADERS | 40 | Maximum number of HTTP headers |
 |MG_ENABLE_LINES | undefined | If defined, show source file names in logs |
 
-
 <span class="badge bg-danger">NOTE:</span> the `MG_IO_SIZE` constant also sets
 maximum UDP message size, see
 [issues/907](https://github.com/cesanta/mongoose/issues/907) for details. If
@@ -254,7 +252,7 @@ and optionally other structures like `DIR *` depending on the functionality
 you have enabled - see previous section. Below is an example:
 
 ```c
-#include <stdbool.h>            // For bool
+#include <stdbool.h>
 #include <stdarg.h>
 
 #define MG_DIRSEP '/'
@@ -262,10 +260,9 @@ you have enabled - see previous section. Below is an example:
 #define MG_ENABLE_SOCKET 0      // Disable BSD socket API, implement your own
 ```
 
-3. This step is optional. If you have disabled BSD socket API, your build is
-going to fail due to several undefined symbols. Create `mongoose_custom.c`
-and implement the following functions (take a look at `src/sock.c` for the
-reference implementation):
+3. This step is optional. If you have disabled BSD socket API, your build is going
+to fail due to several undefined symbols. Create `mongoose_custom.c` and implement
+the following functions (take a look at `src/sock.c` for the reference implementation):
 
 ```c
 struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
@@ -331,10 +328,10 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
 
 int main(int argc, char *argv[]) {
   struct mg_mgr mgr;
-  mg_mgr_init(&mgr);
-  mg_listen(&mgr, "tcp://0.0.0.0:1234", cb, &mgr);
-  for (;;) mg_mgr_poll(&mgr, 1000);
-  mg_mgr_free(&mgr);
+  mg_mgr_init(&mgr);                                // Init manager
+  mg_listen(&mgr, "tcp://0.0.0.0:1234", cb, &mgr);  // Setup listener
+  for (;;) mg_mgr_poll(&mgr, 1000);                 // Event loop
+  mg_mgr_free(&mgr);                                // Cleanup
   return 0;
 }
 ```
@@ -344,7 +341,20 @@ int main(int argc, char *argv[]) {
 
 ## Core
 
-### struct mg_mgr
+### struct mg\_addr
+
+```c
+struct mg_addr {
+  uint16_t port;    // TCP or UDP port in network byte order
+  uint32_t ip;      // IP address in network byte order
+  uint8_t ip6[16];  // IPv6 address
+  bool is_ip6;      // True when address is IPv6 address
+};
+```
+
+This structure contains network address, it can be considered as a Mongoose equivalent for sockets `sockaddr` structure.
+
+### struct mg\_mgr
 
 ```c
 struct mg_mgr {
@@ -397,7 +407,7 @@ struct mg_connection {
 A connection - either a listening connection, or an accepted connection,
 or an outbound connection.
 
-### mg\_mgr_init()
+### mg\_mgr\_init()
 
 ```c
 void mg_mgr_init(struct mg_mgr *mgr);
@@ -422,7 +432,7 @@ mg_mgr_init(&mgr);
 
 
 
-### mg\_mgr_poll()
+### mg\_mgr\_poll()
 
 ```c
 void mg_mgr_poll(struct mg_mgr *mgr, int ms);
@@ -441,6 +451,11 @@ protocol-specific handler function that is set implicitly. For example, a
 protocol-specific handler is called before user-specific handler.  It parses
 incoming data and may invoke protocol-specific events like `MG_EV_HTTP_MSG`.
 
+Usage example:
+
+```c
+while (running == true) mg_mgr_poll(&mgr, 1000 /* 1 sec */);
+```
 
 ### mg\_mgr\_free()
 
@@ -450,6 +465,14 @@ void mg_mgr_free(struct mg_mgr *mgr);
 
 Close all connections, and free all resources.
 
+Usage example:
+
+```c
+struct mg_mgr mgr;
+mg_mgr_init(&mgr);
+while (running == true) mg_mgr_poll(&mgr, 1000);   // Event loop
+mg_mgr_free(&mgr);
+```
 
 ### mg\_listen()
 
@@ -468,6 +491,12 @@ Create a listening connection, append this connection to `mgr->conns`.
 
 Return value: created connection, or `NULL` on error.
 
+Usage example:
+
+```c
+struct mg_connection *c = mg_listen(&mgr, "tcp://127.0.0.1:8080", fn, NULL);
+```
+
 ### mg\_connect()
 
 ```c
@@ -484,6 +513,15 @@ Create an outbound connection, append this connection to `mgr->conns`.
 
 Return value: created connection, or `NULL` on error.
 
+Note: this function does not connect to peer, it allocates required resources and
+starts connect process. Once peer is really connected `MG_EV_CONNECT` event is sent
+to connection event handler.
+
+Usage example:
+
+```c
+struct mg_connection *c = mg_connect(&mgr, "http://example.org", fn, NULL);
+```
 
 ### mg\_send()
 
@@ -498,17 +536,26 @@ Note: this function does not push data to the network! It only appends data to
 the output buffer.  The data is being sent when `mg_mgr_poll()` is called. If
 `mg_send()` is called multiple times, the output buffer grows.
 
+Usage example:
+
+```c
+mg_send(c, "hi", 2);  // Append string "hi" to the output buffer
+```
 
 ### mg\_printf()
 
 ```c
 int mg_printf(struct mg_connection *, const char *fmt, ...);
-
 ```
 
 Same as `mg_send()`, but formats data using `printf()` semantics. Return
 number of bytes appended to the output buffer.
 
+Usage example:
+
+```c
+mg_printf(c, "Hello, %s!", "world"); // Add "Hello, world!" to output buffer
+```
 
 ### mg\_vprintf()
 
@@ -518,6 +565,31 @@ int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
 
 Same as `mg_printf()`, but takes `va_list` argument as a parameter.
 
+Usage example:
+
+```c
+void foo(struct mg_connection *c, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  mg_vprintf(c, fmt, ap);
+  va_end(ap);
+}
+```
+
+### mg\_straddr
+
+```c
+char *mg_straddr(struct mg_connection *c, char *buf, size_t len);
+```
+
+Write stringified IP address, associated with given connection to `buf` (maximum size `len`)
+
+Usage example:
+
+```c
+char buf[1024];
+mg_straddr(c, buf, sizeof(buf)); // `buf` is now IP address string, like "127.0.0.1:8080"
+```
 
 ### mg\_mkpipe()
 
@@ -526,7 +598,7 @@ struct mg_connection *mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *);
 ```
 
 Create a "pipe" connection which is safe to pass to a different task/thread,
-and which is used to wake up event manager from a different task. These 
+and which is used to wake up event manager from a different task. These
 functions are designed to implement multi-threaded support, to handle two
 common use cases:
 
@@ -545,9 +617,9 @@ Another task can wake up a sleeping event manager (in `mg_mgr_poll()` call)
 using `mg_mgr_wakeup()`. When an event manager is woken up, a pipe
 connection event handler function receives `MG_EV_READ` event.
 
-See [examples/multi-threaded](../examples/multi-threaded) for a usage example.
+Usage example: see [examples/multi-threaded](../examples/multi-threaded).
 
-### mg\_mgr_wakeup()
+### mg\_mgr\_wakeup()
 
 ```c
 void mg_mgr_wakeup(struct mg_connection *pipe);
@@ -558,7 +630,7 @@ must be called from a separate task/thread. Parameters:
 
 - `pipe` - a special connection created by the `mg_mkpipe()` call
 
-Return values: none
+Usage example: see [examples/multi-threaded](../examples/multi-threaded).
 
 
 ## HTTP
@@ -567,25 +639,29 @@ Return values: none
 
 ```c
 struct mg_http_header {
-  struct mg_str name;
-  struct mg_str value;
+  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
 
 ```c
 struct mg_http_message {
-  //        GET /foo/bar/baz?aa=b&cc=ddd HTTP/1.1
-  // method |-| |----uri---| |--query--| |proto-|
-
-  struct mg_str method, uri, query, proto;  // Request/response line
+  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
+  struct mg_str body;                                  // Body
+  struct mg_str message;                               // Request line + headers + body
 };
 ```
 
+Structure represents the HTTP message.
+
+<img src="images/mg_http_message.png">
+
 ### mg\_http\_listen()
 
 ```c
@@ -601,6 +677,12 @@ Create HTTP listener.
   event handler is called. This pointer is also stored in a connection
   structure as `c->fn_data`
 
+Usage example:
+
+```c
+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()
 
@@ -616,7 +698,16 @@ Create HTTP client connection.
   event handler is called. This pointer is also stored in a connection
   structure as `c->fn_data`
 
+Note: this function does not connect to peer, it allocates required resources and
+starts connect process. Once peer is really connected `MG_EV_CONNECT` event is
+sent to connection event handler.
+
+Usage example:
 
+```c
+struct mg_connection *c = mg_http_connect(&mgr, "http://google.com", fn, NULL);
+if (c == NULL) fatal_error("Cannot create connection");
+```
 
 
 ### mg\_http\_get\_request\_len()
@@ -625,11 +716,20 @@ Create HTTP client connection.
 int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
 ```
 
-Return value: -1 on error,
-0 if a message is incomplete, or the 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.
+Return length of request in `buf` (with maximum len `buf_len`).
+
+The length of request is a number of bytes till the end of HTTP headers. It does
+not include length of HTTP body.
+Return value: -1 on error, 0 if a message is incomplete, or the length of request.
+
+Usage example:
+
+```c
+const char *buf = "GET /test \n\nGET /foo\n\n";
+int req_len = mg_http_get_request_len(buf, strlen(buf));  // req_len == 12
+```
 
+<img src="images/mg_http_get_request_len.png">
 
 ### mg\_http\_parse()
 
@@ -637,18 +737,30 @@ length of HTTP body.
 int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm);
 ```
 
-Parse string `s`, `len` into a structure `hm`. Return request length - see
-`mg_http_get_request_len()`.
+Parse string `s` (with maximum size `len`) into a structure `hm`. Return request
+ length - see `mg_http_get_request_len()`.
+
+Usage example:
 
+```c
+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 *cnn, const char *fmt, ...);
+```c
+void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...);
 ```
 
 Write a chunk of data in chunked encoding format, using `printf()` semantic.
 
+Usage example:
+
+```c
+mg_http_printf_chunk(c, "Hello, %s!", "world");
+```
 
 ### mg\_http\_write\_chunk()
 
@@ -658,6 +770,31 @@ void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
 
 Write a chunk of data in chunked encoding format.
 
+Usage example:
+
+```c
+mg_http_write_chunk(c, "hi", 2);
+```
+
+### mg\_http\_delete\_chunk()
+
+```c
+void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
+```
+
+Remove chunk specified by `hm` from input buffer.
+
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_HTTP_CHUNK) {
+    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
+    mg_http_delete_chunk(c, hm); // Remove received chunk
+  }
+}
+```
 
 ### mg\_http\_serve\_dir()
 
@@ -674,6 +811,20 @@ void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
 Serve static files according to the given options. Note that in order to
 enable SSI, set a `-DMG_ENABLE_SSI=1` build flag.
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_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 = "/my_root";
+    mg_http_serve_dir(c, hm, &opts);
+  }
+}
+```
 
 ### mg\_http\_serve\_file()
 
@@ -682,55 +833,63 @@ void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
                         const char *path, struct mg_http_serve_opts *opts);
 ```
 
-Serve static file. Note that the `extra_headers` must end with `\r\n`. Here
-is an example call:
+Serve static file. Note that the `extra_headers` must end with `\r\n`.
+
+Usage example:
 
 ```c
-struct mg_http_serve_opts opts = {.mime_types = "png=image/png", 
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_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_serve_file(c, hm, "a.png", &opts);  // Send file
+  }
+}
 ```
 
-
-
 ### mg\_http\_reply()
 
 ```c
-void mg_http_reply(struct mg_connection *c, int status_code, const char *headers,
-                   const char *body_fmt, ...);
+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.
+`Content-Length` header. Extra headers could be passed via `headers` parameter.
 
 - `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
 
-Example - send a simple JSON respose:
-  ```c
-  mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\": %d}", 123);
-  ```
+<img src="images/mg_http_reply.png">
 
-Example - send JSON response using [mjson](https://github.com/cesanta/mjson) library:
-  ```c
-  char *json = NULL;
-  mjson_printf(mjson_print_dynamic_buf, &json, "{%Q:%d}", "name", 123);
-  mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", json);
-  free(json);
-  ```
+Usage examples:
 
-Example - send a 302 redirect:
-  ```c
-  mg_http_reply(c, 302, "Location: /\r\n", "");
-  ```
+Send a simple JSON respose:
+```c
+mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"result\": %d}", 123);
+```
 
-Example - send error:
-  ```c
-  mg_http_reply(c, 403, "", "%s", "Not Authorised\n");
-  ```
+Send JSON response using [mjson](https://github.com/cesanta/mjson) library:
+```c
+char *json = NULL;
+mjson_printf(mjson_print_dynamic_buf, &json, "{%Q:%d}", "name", 123);
+mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", json);
+free(json);
+```
+
+Send a 302 redirect:
+```c
+mg_http_reply(c, 302, "Location: /\r\n", "");
+```
+
+Send error:
+```c
+mg_http_reply(c, 403, "", "%s", "Not Authorized\n");
+```
 
 ### mg\_http\_get\_header()
 
@@ -738,7 +897,24 @@ Example - send error:
 struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
 ```
 
-Return value of HTTP header, or NULL if not found.
+Return value of `name` HTTP header, or NULL if not found.
+
+Usage example:
+
+```c
+// Mongoose event handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_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->ptr);
+    } else {
+      mg_http_reply(c, 200, "", "Oh no, header is not set...");
+    }
+  }
+}
+```
 
 ### mg\_http\_get\_var()
 
@@ -749,21 +925,18 @@ int mg_http_get_var(const struct mg_str *, const char *name, char *buf, int len)
 Decode HTTP variable `name` into a given buffer. Return length of decoded
 variable. Zero or negative value means error.
 
-### mg\_url\_decode()
+Usage example:
 
 ```c
-int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
+char buf[100] = "";
+mg_http_get_var(&hm->body, "key1", buf, sizeof(buf)) {
 ```
 
-
-URL-decode string `s`, `n` unto a buffer `buf`, `len`. Return decoded length.
-If `form` is non-zero, then `+` is decoded as whitespace.
-
-
 ### mg\_http\_creds()
 
 ```c
-void mg_http_creds(struct mg_http_message *, char *user, int userlen, char *pass, int passlen);
+void mg_http_creds(struct mg_http_message *, char *user, size_t userlen,
+                   char *pass, size_t passlen);
 ```
 
 Fetch authentication credential from the request, and store into the
@@ -777,6 +950,18 @@ up in the following order:
 
 If none is found, then both user and pass are set to empty nul-terminated strings.
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_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\_match\_uri()
 
@@ -786,6 +971,22 @@ bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
 
 Return true if HTTP request matches a given glob pattern; false otherwise.
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_HTTP_MSG) {
+    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
+    if (mg_http_match_uri(hm, "/secret")) {
+      mg_http_reply(c, 200, NULL, "Very big secret!");
+    } else {
+      mg_http_reply(c, 200, NULL, "hello world..");
+    }
+  }
+}
+```
+
 ### mg\_http\_upload()
 
 ```c
@@ -822,6 +1023,17 @@ So, the expected usage of this API function is this:
 - When the last chunk is POSTed, upload finishes
 - POST data must not be encoded in any way, it it saved as-is
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_HTTP_MSG) {
+    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
+    mg_http_upload(c, hm, "."); // Upload to current folder
+  }
+```
+
 ### mg\_http\_bauth()
 
 ```c
@@ -830,6 +1042,12 @@ void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
 
 Write a Basic `Authorization` header to the output buffer.
 
+Usage example:
+
+```c
+mg_http_bauth(c, "user_name", "password") // "user_name:password" is now in output buffer
+```
+
 ### mg\_http\_next\_multipart()
 
 ```c
@@ -839,7 +1057,11 @@ struct mg_http_part {
   struct mg_str filename;  // Filename for file uploads
   struct mg_str body;      // Part contents
 };
+```
 
+<img src="images/mg_http_part.png">
+
+```c
 size_t mg_http_next_multipart(struct mg_str body, size_t offset, struct mg_http_part *part);
 ```
 
@@ -847,8 +1069,18 @@ 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.
 
-See `form-upload` example for a usage example.
+See [examples/form-upload](../examples/form-upload) for full usage example.
 
+<img src="images/mg_http_next_multipart.png">
+
+Usage example:
+
+```c
+struct mg_http_part part;
+if(mg_http_next_multipart(body, 0 /* begin */, &part)) {
+  // Use part
+}
+```
 
 ## Websocket
 
@@ -856,11 +1088,13 @@ See `form-upload` example for a usage example.
 
 ```c
 struct mg_ws_message {
-  struct mg_str data;
-  uint8_t flags;  // Websocket message flags
+  struct mg_str data; // Websocket message data
+  uint8_t flags;      // Websocket message flags
 };
 ```
 
+Structure represents the WebSocket message.
+
 ### mg\_ws\_connect()
 
 ```c
@@ -878,6 +1112,17 @@ Create client Websocket connection.
   structure as `c->fn_data`
 - `fmt` - printf-like format string for additional HTTP headers, or NULL
 
+Note: this function does not connect to peer, it allocates required resources and
+ starts connect process. Once peer is really connected `MG_EV_CONNECT` event is
+ sent to connection event handler.
+
+Usage example:
+
+```c
+struct mg_connection *c = mg_ws_connect(&mgr, "ws://test_ws_server.com:1000",
+                                        handler, NULL, "%s", "Sec-WebSocket-Protocol: echo\r\n");
+if(c == NULL) fatal("Cannot create connection");
+```
 
 ### mg\_ws\_upgrade()
 
@@ -890,6 +1135,17 @@ Upgrade given HTTP connection to Websocket. The `fmt` is a printf-like
 format string for the extra HTTP headers returned to the client in a
 Websocket handshake. Set `fmt` to `NULL` if no extra headers needs to be passed.
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_HTTP_MSG) {
+    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
+    mg_ws_upgrade(c, hm, NULL);  // Upgrade HTTP to WS
+  }
+}
+```
 
 ### mg\_ws\_send()
 
@@ -897,7 +1153,7 @@ Websocket handshake. Set `fmt` to `NULL` if no extra headers needs to be passed.
 size_t mg_ws_send(struct mg_connection *, const char *buf, size_t len, int op);
 ```
 
-Send `buf`, `len` to the websocket peer. `op` is the Websocket message type:
+Send `buf` (`len` size) to the websocket peer. `op` is the Websocket message type:
 
 ```c
 #define WEBSOCKET_OP_CONTINUE 0
@@ -908,31 +1164,103 @@ Send `buf`, `len` to the websocket peer. `op` is the Websocket message type:
 #define WEBSOCKET_OP_PONG 10
 ```
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_WS_OPEN) {
+    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
+    mg_ws_send(c, "opened", 6, WEBSOCKET_OP_BINARY);  // Send "opened" to web socket connection
+  }
+}
+```
+
+### mg\_ws\_wrap()
+
+```c
+size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op)
+```
+
+Convert data in output buffer to WebSocket format. Useful then implementing protocol over WebSocket
+See [examples/mqtt-over-ws-client](../examples/mqtt-over-ws-client) for full example.
+
+Usage example:
+
+```c
+size_t len = c->send.len;         // Store output buffer len
+mg_mqtt_login(c, s_url, &opts);   // Write MQTT login message
+mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY); // Wrap it into WS
+```
+
+## SNTP
+
+### mg_sntp_connect()
+
+```c
+struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
+                                      mg_event_handler_t fn, void *fn_data)
+```
+
+Connect SNTP server specified by `url` or `time.google.com` if NULL.
+Return pointer to created connection or `NULL` on error.
+
+Usage example:
+
+```c
+static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
+  if (ev == MG_EV_SNTP_TIME) {
+    // Time received
+    struct timeval *tv = (struct timeval *tv)evd;
+  }
+}
+...
+mg_sntp_connect(mgr&, NULL /* connect to time.google.com */, sntp_cb, NULL);
+```
+
+### mg_sntp_send()
+
+```c
+void mg_sntp_send(struct mg_connection *c, unsigned long utc)
+```
+
+Send time request to SNTP server. Note, that app can't send SNTP request more often than every 1 hour.
+`utc` is a current time, used to verify if new request is possible.
+
+Usage example:
+
+```c
+mg_sntp_send(c, (unsigned long) time(NULL));
+```
+
 ## MQTT
 
 ### struct mg\_mqtt\_opts
 
 ```c
 struct mg_mqtt_opts {
-  struct mg_str client_id;
-  struct mg_str will_topic;
-  struct mg_str will_message;
-  uint8_t qos;         // Quality of service
-  bool will_retain;    // Retain last will
-  bool clean;          // Use clean session, 0 or 1
-  uint16_t keepalive;  // Keep-alive timer in seconds
+  struct mg_str client_id;    // Client id
+  struct mg_str will_topic;   // Will Topic
+  struct mg_str will_message; // Will Message
+  uint8_t qos;                // Quality of service
+  bool will_retain;           // Retain last will
+  bool clean;                 // Use clean session, 0 or 1
+  uint16_t keepalive;         // Keep-alive timer in seconds
 };
 ```
 
+Structure used to specify MQTT connection options.
+
 ### struct mg\_mqtt\_message
 
 ```c
 struct mg_mqtt_message {
-  struct mg_str topic;
-  struct mg_str data;
+  struct mg_str topic;  // Topic
+  struct mg_str data;   // Message data
 };
 ```
 
+Structure represents the MQTT message.
 
 ### mg\_mqtt\_connect()
 
@@ -950,23 +1278,98 @@ Create client MQTT connection.
   event handler is called. This pointer is also stored in a connection
   structure as `c->fn_data`
 
+Note: this function does not connect to peer, it allocates required resources and
+starts connect process. Once peer is really connected `MG_EV_CONNECT` event is
+sent to connection event handler.
 
-### mg\_mqtt\_pub()
+Usage example:
 
 ```c
-void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
-                 struct mg_str *data, int qos, bool retain);
-```
+void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
+  char *buf = (char *) fnd;
+  if (ev == MG_EV_MQTT_OPEN) {
+    // Connection ready
+  }
+}
 
-Publish message `data` to the topic `topic` with given QoS and retain flag.
+mg_mqtt_connect(&mgr, "mqtt://test.org:1883", NULL, handler, NULL);
+```
 
-### mg\_mqtt\_sub()
+### mg\_mqtt\_listen()
 
 ```c
-void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic, int qos);
+struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
+                                     mg_event_handler_t fn, void *fn_data);
 ```
 
-Subscribe to topic `topic` with given QoS.
+Create MQTT listener.
+
+- `url` - specifies local IP address and port to listen on, e.g. `mqtt://0.0.0.0:1883`
+- `fn` - an event handler function
+- `fn_data` - an arbitrary pointer, which will be passed as `fn_data` when an
+  event handler is called. This pointer is also stored in a connection
+  structure as `c->fn_data`
+
+Usage example:
+
+```c
+struct mg_connection *c = mg_mqtt_listen(&mgr, "0.0.0.0:1883", fn, arg);
+if (c == NULL) fatal("Cannot create connection");
+```
+
+### mg\_mqtt\_login
+
+```c
+void mg_mqtt_login(struct mg_connection *c, const char *url,
+                   struct mg_mqtt_opts *opts);
+```
+
+Send MQTT login request.
+
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
+  char *buf = (char *) fnd;
+  if (ev == MG_EV_MQTT_OPEN) {
+    struct mg_mqtt_opts opts = {.qos = 1,
+                                .will_topic = mg_str("my topic"),
+                                .will_message = mg_str("goodbye")};
+    mg_mqtt_login(c, s_url, &opts);
+  }
+}
+```
+
+### mg\_mqtt\_pub()
+
+```c
+void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
+                 struct mg_str *data, int qos, bool retain);
+```
+
+Publish message `data` to the topic `topic` with given QoS and retain flag.
+
+Usage example:
+
+```c
+struct mg_str topic = mg_str("topic");
+struct mg_str data = mg_str("data");
+mg_mqtt_pub(c, &topic, &data, 1, false);
+```
+
+### mg\_mqtt\_sub()
+
+```c
+void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic, int qos);
+```
+
+Subscribe to topic `topic` with given QoS.
+
+```c
+struct mg_str topic = mg_str("topic");
+mg_mqtt_sub(c, &topic, 1);
+```
 
 ### mg\_mqtt\_next\_sub()
 
@@ -974,19 +1377,25 @@ Subscribe to topic `topic` with given QoS.
 size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, size_t pos);
 ```
 
-Traverse list of subscribed topics. 
+Traverse list of subscribed topics.
 Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received.
 Return next position, or 0 when done. Initial position `pos` should be 4. Example:
 
+Usage example:
+
 ```c
-if (ev == MG_EV_MQTT_CMD) {
-  struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
-  if (mm->cmd == MQTT_CMD_SUBSCRIBE) {
-    size_t pos = 4;
-    uint8_t qos;
-    struct mg_str topic;
-    while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
-      LOG(LL_INFO, ("SUB [%.*s]", (int) topic.len, topic.ptr));
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
+  if (ev == MG_EV_MQTT_CMD) {
+    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
+    if (mm->cmd == MQTT_CMD_SUBSCRIBE) {
+      size_t pos = 4;
+      uint8_t qos;
+      struct mg_str topic;
+      // Iterate over all subscribed topics
+      while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
+        LOG(LL_INFO, ("SUB [%.*s]", (int) topic.len, topic.ptr));
+      }
     }
   }
 }
@@ -1001,6 +1410,111 @@ size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, siz
 Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference
 is that there is no QoS in unsubscribe request.
 
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *evd, void *fnd) {
+  if (ev == MG_EV_MQTT_CMD) {
+    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
+    if (mm->cmd == MQTT_CMD_UNSUBSCRIBE) {
+      size_t pos = 4;
+      struct mg_str topic;
+      if (mm->cmd == MQTT_CMD_UNSUBSCRIBE) {
+        // Iterate over all unsubscribed topics
+        while ((pos = mg_mqtt_next_unsub(mm, &topic, pos)) > 0) {
+          LOG(LL_INFO, ("SUB [%.*s]", (int) topic.len, topic.ptr));
+        }
+      }
+   }
+  }
+}
+```
+
+### mg\_mqtt\_send_header()
+
+```c
+void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, uint32_t len);
+```
+Send MQTT command header. Useful in MQTT server implementation. Command can be one of the following value:
+
+```c
+#define MQTT_CMD_CONNECT 1
+#define MQTT_CMD_CONNACK 2
+#define MQTT_CMD_PUBLISH 3
+#define MQTT_CMD_PUBACK 4
+#define MQTT_CMD_PUBREC 5
+#define MQTT_CMD_PUBREL 6
+#define MQTT_CMD_PUBCOMP 7
+#define MQTT_CMD_SUBSCRIBE 8
+#define MQTT_CMD_SUBACK 9
+#define MQTT_CMD_UNSUBSCRIBE 10
+#define MQTT_CMD_UNSUBACK 11
+#define MQTT_CMD_PINGREQ 12
+#define MQTT_CMD_PINGRESP 13
+#define MQTT_CMD_DISCONNECT 14
+```
+
+Usage example:
+
+```c
+// Mongoose events handler
+void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
+  if (ev == MG_EV_MQTT_CMD) {
+    struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
+    if (mm->cmd == MQTT_CMD_CONNECT) {
+        uint8_t response[] = {0, 0};
+        mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response));  // Send acknowledgement
+        mg_send(c, response, sizeof(response));
+    }
+  }
+}
+```
+
+### mg\_mqtt\_ping()
+
+```c
+void mg_mqtt_ping(struct mg_connection *);
+```
+
+Send `MQTT_CMD_PINGREQ` command via `mg_mqtt_send_header`
+
+Usage example:
+
+```c
+// Send periodic pings to all WS connections
+static void timer_fn(void *arg) {
+  struct mg_mgr *mgr = (struct mg_mgr *) arg;
+  for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
+    if (c->is_websocket) mg_mqtt_ping(c);
+  }
+}
+```
+
+### mg_mqtt_parse
+
+```c
+int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);
+```
+
+Parse buffer and fill `m` if buffer contain MQTT message.
+Return `MQTT_OK` if message succesfully parsed, `MQTT_INCOMPLETE` if message
+isn't fully receives and `MQTT_MALFORMED` is message has wrong format.
+
+Usage example:
+
+```c
+// Iterate over all MQTT frames contained in buf, len
+struct mg_mqtt_message mm;
+while ((mg_mqtt_parse(buf, len, &mm)) == 0) {
+  switch (mm.cmd) {
+    case MQTT_CMD_CONNACK:
+      ...
+  }
+  buf += mm.dgram.len;
+  len -= mm.dgram.len;
+}
+```
 
 ## TLS
 
@@ -1036,18 +1550,23 @@ set both `ca` and `cert`, whilst client-side - only `ca`.
 ### mg\_tls\_init()
 
 ```c
-int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts);
+void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts);
 ```
 
 Initialise TLS on a given connection.
 
-<span class="badge bg-danger">NOTE:</span> mbedTLS implementation uses `mg_random` as RNG. The `mg_random`
-can be overridden by setting `MG_ENABLE_CUSTOM_RANDOM` and defining
-your own `mg_random()` implementation.
+<span class="badge bg-danger">NOTE:</span> mbedTLS implementation uses `mg_random`
+as RNG. The `mg_random` can be overridden by setting `MG_ENABLE_CUSTOM_RANDOM`
+and defining your own `mg_random()` implementation.
 
+Usage example:
 
-## Time
+```c
+struct mg_tls_opts opts = {.cert = "ca.pem"};
+mg_tls_init(c, &opts);
+```
 
+## Timer
 
 ### struct mg\_timer
 
@@ -1071,7 +1590,8 @@ as the `mg_mgr_poll()` timeout argument in the main event loop.
 ### mg\_timer\_init()
 
 ```c
-void mg_timer_init(struct mg_timer *, int ms, int flags, void (*fn)(void *), void *fn_data);
+void mg_timer_init(struct mg_timer *, unsigned long ms, unsigned flags,
+                   void (*fn)(void *), void *fn_data);
 ```
 
 Setup a timer.
@@ -1080,10 +1600,16 @@ Setup a timer.
 - `fn` - function to invoke
 - `fn_data` - function argument
 
-A timer gets initialized and linked into the `g_timers` list:
+A timer gets initialized and linked into the internal timers list:
 
+Usage example:
 ```c
-struct mg_timer *g_timers;
+void timer_fn(void *data) {
+  // ...
+}
+
+struct mg_timer timer;
+mg_timer_init(&timer, 1000 /* 1sec */, MG_TIMER_REPEAT, timer_fn, NULL);
 ```
 
 ### mg\_timer\_free()
@@ -1092,7 +1618,14 @@ struct mg_timer *g_timers;
 void mg_timer_free(struct mg_timer *);
 ```
 
-Free timer, remove it from the `g_timers` list.
+Free timer, remove it from the internal timers list.
+
+Usage example:
+```c
+struct mg_timer timer;
+// ...
+mg_timer_free(&timer);
+```
 
 ### mg\_timer\_poll()
 
@@ -1103,6 +1636,18 @@ void mg_timer_poll(unsigned long uptime_ms);
 Traverse list of timers, and call them if current timestamp `uptime_ms` is
 past the timer's expiration time.
 
+Note, that `mg_mgr_poll` function internally calls `mg_timer_poll`, therefore,
+in most cases it is unnecessary to call it explicitly.
+
+Usage example:
+
+```c
+unsigned long now = mg_millis();
+mg_timer_poll(now);
+```
+
+## Time
+
 ### mg\_time()
 
 ```
@@ -1111,6 +1656,11 @@ double mg_time(void);
 
 Return current time as UNIX epoch, using `double` value for sub-second accuracy.
 
+Usage example:
+
+```c
+double now = mg_time()
+```
 
 ### mg\_millis()
 
@@ -1120,6 +1670,11 @@ unsigned long mg_millis(void);
 
 Return current uptime in milliseconds.
 
+Usage example:
+
+```c
+unsigned long uptime = mg_millis();
+```
 
 ### mg\_usleep()
 
@@ -1127,235 +1682,835 @@ Return current uptime in milliseconds.
 void mg_usleep(unsigned long usecs);
 ```
 
-Block for a given number of microseconds.
+Block thread execution for a given number of microseconds.
 
+Usage example:
 
+```c
+mg_usleep(1000000 /* 1 sec */)
+```
 
 ## String
 
-### mg\_globmatch()
-
-```c
-bool mg_globmatch(const char *pattern, int plen, const char *s, int n);
-```
+### mg\_str
 
-Return true if string `s`, `n` matches glob pattern `pattern`, `plen`.
-The glob pattern matching rules are as follows:
+In most cases, Mongoose uses `mg_str` struct for string representation rather than NULL-terminated C-strings.
 
-- `?` matches any single character 
-- `*` matches zero or more characters except `/`
-- `#` matches zero or more characters
-- any other character matches itself
+```
+struct mg_str {
+  const char *ptr;  // Pointer to string data
+  size_t len;       // String len
+};
+```
 
+Note, that in general, `ptr` points to non-NULL terminated string, so, do not use functions from C standard library on it.
 
-### mg\_commalist()
+### mg\_str()
 
 ```c
-bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v);
+struct mg_str mg_str(const char *s)
 ```
 
-Parse string `s`, which is a comma-separated list of entries. An entry could be
-either an arbitrary string, which gets stored in `v`, or a `KEY=VALUE` which
-gets stored in `k` and `v` respectively.
+Create Mongoose string from NULL-terminated C-string. This function doesn't
+duplicate provided string, and stores pointer within created `mg_str` structure.
+
+Note, that is you have problems in C++ (constructor shadowing), there is `mg_str_s`
+synonym for this function.
 
-IMPORTANT: this function modifies `s` by pointing to the next entry. Usage
-example:
+Usage example:
 
 ```c
-struct mg_str k, v, s = mg_str("a=333,b=777");
-while (mg_commalist(&s, &k, &v))               // This loop output:
-  printf("[%.*s] set to [%.*s]\n",                    // [a] set to [333]
-         (int) k.len, k.ptr, (int) v.len, v.ptr);     // [b] set to [777]
+struct mg_str str = mg_str("Hello, world!);
 ```
 
-### mg\_hexdump()
+### mg\_str\_n()
 
 ```c
-char *mg_hexdump(const void *buf, int len);
+struct mg_str mg_str_n(const char *s, size_t n);
 ```
 
-Hexdump binary data `buf`, `len` into malloc-ed buffer and return it.
-It is a caller's responsibility to free() returned pointer.
+Create Mongoose string from C-string `s` (can be non-NULL terminated, len is specified in `n`). <br>
+Note: this function doesn't duplicate provided string, but stores pointer within created `mg_str` structure.
 
-### mg\_hex()
+Usage example:
 
 ```c
-char *mg_hex(const void *buf, int len, char *dst);
+struct mg_str str = mg_str_n("hi", 2);
 ```
 
-Hex-encode binary data `buf`, `len` into a buffer `dst` and nul-terminate it.
-The output buffer must be at least 2 x `len` + 1 big.
-Return value: `dst` pointer. The encoded characters are lowercase,
-for example `mg_hex("hi", 2, buf)` outputs `6869` and 0 byte, 5 bytes overall.
-
-
-### mg\_unhex()
+### mg\_casecmp()
 
 ```c
-void mg_unhex(const char *buf, int len, unsigned char *to);
+int mg_casecmp(const char *s1, const char *s2);
 ```
 
-Hex-decode string `buf`, `len` into a buffer `to`. The `to` buffer should be
-at least `lsn` / 2 big.
+Case insensitive compare two NULL-terminated strings.
+Return value is 0 if strings are equal, more than zero if first argument is greater then second, and less than zero otherwise.
+
+Usage example:
 
+```c
+if (mg_casecmp("hello", "HELLO") == 0) {
+  // Strings are equal
+}
+```
 
-### mg\_unhexn()
+### mg\_ncasecmp()
 
 ```c
-unsigned long mg_unhexn(const char *s, int len);
+int mg_ncasecmp(const char *s1, const char *s2, size_t len);
 ```
 
-Parse `len` characters of the hex-encoded string `s`, return parsed value.
-The maximum value of `len` is the width of the `long` x 2, for example
-on 32-bit platforms it is 8.
+Case insensitive compare two C-strings, not more than `len` symbols or until meet `\0` symbol.
 
+Return value is 0 if strings are equal, more than zero if first argument is
+greater then second and less than zero otherwise.
 
-### mg\_asprintf()
+Usage example:
 
 ```c
-int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
+if (mg_ncasecmp("hello1", "HELLO2", 5) == 0) {
+  // Strings are equal
+}
 ```
 
-Print message specified by printf-like format string `fmt` into a buffer
-pointed by `buf` of size `size`. If `size` is large enough to hold the whole
-message, then a message is stored in `*buf`. If it does not fit, then
-a large enough buffer is allocated to hold a message, and `buf` is changed to
-point to that buffer. Return value: number of bytes printed.
-
-
-### mg\_vasprintf()
+### mg\_vcmp()
 
 ```c
-int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
+int mg_vcmp(const struct mg_str *s1, const char *s2);
 ```
 
-Same as `mg_asprintf()` but uses `va_list` argument.
+Сompare mongoose string and C-string.
 
+Return value is 0 if strings are equal, more than zero if first argument is
+greater then second and less than zero otherwise.
 
-### mg\_to64()
+Usage example:
 
 ```c
-int64_t mg_to64(const char *s);
+struct mg_str str = mg_str("hello");
+if (mg_vcmp(str, "hello") == 0) {
+  // Strings are equal
+}
 ```
 
-Parse 64-bit integer value held by string `s`.
-
-### mg\_aton()
+### mg\_vcasecmp()
 
 ```c
-bool mg_aton(struct mg_str str, uint32_t *ipaddr);
+int mg_vcasecmp(const struct mg_str *str1, const char *str2);
 ```
 
-Parse IP address held by `str` and store it in `ipaddr`. Return true on success.
+Case insensitive compare mongoose string and C-string.
 
+Return value is 0 if strings are equal, more than zero if first argument is
+greater then second and less than zero otherwise.
 
-### mg\_ntoa()
+Usage example:
 
 ```c
-char *mg_ntoa(const struct mg_addr *, char *buf, size_t len);
+struct mg_str str = mg_str("hello");
+if (mg_vcasecmp(str, "HELLO") == 0) {
+  // Strings are equal
+}
 ```
 
-Stringify IP address `ipaddr` into a buffer `buf`, `len`. Return `buf`.
-
+### mg\_strcmp()
 
+```c
+int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
+```
 
-## Utility
+Сompare two mongoose strings.
 
+Return value is 0 if strings are equal, more than zero if first argument is
+greater then second and less than zero otherwise.
 
-### mg\_file\_read()
+Usage example:
 
 ```c
-char *mg_file_read(const char *path, size_t *sizep);
+struct mg_str str1 = mg_str("hello");
+struct mg_str str2 = mg_str("hello");
+if (mg_strcmp(str1, str2) == 0) {
+  // Strings are equal
+}
 ```
 
-Read file contents into a nul-terminated malloc-ed string. It is a caller's
-responsibility to free() a returned pointer. If `sizep` is not NULL, it will
-return a file size in bytes.
-
-### mg\_file\_write()
+### mg\_strdup()
 
 ```c
-bool mg_file_write(const char *path, const void *buf, size_t len);
+struct mg_str mg_strdup(const struct mg_str s);
 ```
 
-Write data to a file, return `true` if written, `false` otherwise.
-The write is atomic, i.e. data gets written to a temporary file first,
-then `rename()-ed` to a destination file name.
-
+Duplicate provided string. Return new string or `MG_NULL_STR` on error.
+Note: this function allocates memory for returned string. You may need to free it using `free` function.
 
-### mg\_file\_printf()
+Usage example:
 
 ```c
-int mg_file_printf(const char *path, const char *fmt, ...);
+struct mg_str str1 = mg_str("hello");
+struct mg_str str2 = mg_strdup(str1);
+//...
+free(str1.ptr);
 ```
 
-Write into a file `path` using `printf()` semantics.
-Return `true` on success, `false` otherwise. This function prints data to
-a temporary in-memory buffer first, then calls `mg_file_write()`.
-
 
-### mg\_random()
+### mg\_strstr()
 
 ```c
-void mg_random(void *buf, size_t len);
+const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle)
 ```
 
-Fill in buffer `buf`, `len` with random data.
+Search for `needle` substring in `haystack` string. Return pointer to `needle`
+occurrence within `haystack` or `NULL` if not found.
+
+Usage example:
 
+```c
+struct mg_str str = mg_str("Hello, world");
+struct mg_str sub_str = mg_str("world");
 
-### mg\_ntohs()
+if (mg_strstr(str, sub_str) != NULL) {
+  // Found
+}
+```
+
+### mg\_strstrip()
 
 ```c
-uint16_t mg_ntohs(uint16_t net);
+struct mg_str mg_strstrip(struct mg_str s)
 ```
 
-Convert `uint16_t` value to host order.
+Remove heading and trailing whitespace from mongoose string `s`.
 
+Usage example:
 
-### mg\_ntohl()
+```c
+struct mg_str str = mg_strstrip(mg_str("   Hello, world   "));
+if (mg_vcmp(str, "Hello, world") == 0) {
+  // Strings are equal
+}
+```
+
+### mg\_globmatch()
 
 ```c
-uint32_t mg_ntohl(uint32_t net);
+bool mg_globmatch(const char *pattern, size_t p_len, const char *s, size_t s_len);
 ```
 
-Convert `uint32_t` value to host order.
+Return true if string `s` (limited to `s_len` symbols) matches glob pattern `pattern`, (limited to `p_len` symbols).
+The glob pattern matching rules are as follows:
 
+- `?` matches any single character
+- `*` matches zero or more characters except `/`
+- `#` matches zero or more characters
+- any other character matches itself
 
-### mg\_crc32()
+Usage example:
 
 ```c
-uint32_t mg_crc32(uint32_t crc, const uint8_t *buf, size_t len);
-```
+struct mg_str pattern = mg_str("#, ?????");
+struct mg_str s = mg_str("Hello, world");
 
-Calculate CRC32 checksum for a given buffer. An initial `crc` value should
-be `0`.
+if (mg_globmatch(pattern.ptr, pattern.len, s.otr, s.len)) {
+  // Match
+}
+```
 
-### mg\_check\_ip\_acl()
+### mg\_commalist()
 
 ```c
-int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip);
+bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v);
 ```
 
-Check IPv4 address `remote_ip` against the IP ACL `acl`. Parameters:
+Parse string `s`, which is a comma-separated list of entries. An entry could be
+either an arbitrary string, which gets stored in `v`, or a `KEY=VALUE` which
+gets stored in `k` and `v` respectively.
 
-- `acl` - an ACL string, e.g. `-0.0.0.0/0,+1.2.3.4`
-- `remote_ip` - IPv4 address in network byte order
+IMPORTANT: this function modifies `s` by pointing to the next entry.
 
-Return value: 1 if `remote_ip` is allowed, 0 if not, and <0 if `acl` is
-invalid.
+<img src="images/mg_commalist.png">
 
 Usage example:
 
 ```c
-  if (mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.2.3.4"), c->peer.ip) != 1) {
-    LOG(LL_INFO, ("NOT ALLOWED!"));
-  }
+struct mg_str k, v, s = mg_str("a=333,b=777");
+while (mg_commalist(&s, &k, &v))                      // This loop output:
+  printf("[%.*s] set to [%.*s]\n",                    // [a] set to [333]
+         (int) k.len, k.ptr, (int) v.len, v.ptr);     // [b] set to [777]
 ```
 
-## IO Buffers
+### mg\_hexdump()
 
-IO buffer, described by the `struct mg_iobuf`, is a simple data structure
-that insert or delete chunks of data at arbitrary offsets and grow/shrink
+```c
+char *mg_hexdump(const void *buf, int len);
+```
+
+Hexdump binary data `buf`, `len` into malloc-ed buffer and return it.
+It is a caller's responsibility to free() returned pointer.
+
+Usage example:
+
+```c
+char arr[] = "\0x1\0x2\0x3";
+char *hex = mg_hexdump(arr, sizeof(arr));
+LOG(LL_INFO, ("%s", hex)); // Output "0000  01 02 03 00";
+free(hex);
+```
+
+### mg\_hex()
+
+```c
+char *mg_hex(const void *buf, size_t len, char *dst);
+```
+
+Hex-encode binary data `buf`, `len` into a buffer `dst` and nul-terminate it.
+The output buffer must be at least 2 x `len` + 1 big.
+Return value: `dst` pointer. The encoded characters are lowercase.
+
+Usage example:
+
+```c
+char data[] = "\x1\x2\x3";
+char buf[sizeof(data)*2];
+char *hex = mg_hex(data, sizeof(data) - 1, buf);
+LOG(LL_INFO, ("%s", hex)); // Output "010203";
+free(hex);
+```
+
+### mg\_unhex()
+
+```c
+void mg_unhex(const char *buf, size_t len, unsigned char *to);
+```
+
+Hex-decode string `buf`, `len` into a buffer `to`. The `to` buffer should be
+at least `lsn` / 2 big.
+
+Usage example:
+
+```c
+char data[] = "010203";
+char *buf[sizeof(data)/2];
+char *hex = mg_unhex(data, sizeof(data) - 1, buf); // buf is now [1,2,3]
+free(hex);
+```
+
+### mg\_unhexn()
+
+```c
+unsigned long mg_unhexn(const char *s, size_t len);
+```
+
+Parse `len` characters of the hex-encoded string `s`, return parsed value.
+The maximum value of `len` is the width of the `long` x 2, for example
+on 32-bit platforms it is 8.
+
+Usage example:
+
+```c
+char data[] = "010203";
+char *buf[sizeof(data)/2];
+unsigned long val = mg_unhex(data, sizeof(data) - 1); // val is now 123
+```
+
+
+### mg\_asprintf()
+
+```c
+int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
+```
+
+Print message specified by printf-like format string `fmt` into a buffer
+pointed by `buf` of size `size`. If `size` is large enough to hold the whole
+message, then a message is stored in `*buf`. If it does not fit, then a large
+enough buffer is allocated to hold a message, and `buf` is changed to point to
+that buffer. Return value: number of bytes printed.
+
+Usage example:
+
+```c
+char buf[1024], *pbuf = &buf;
+mg_asprintf(&pbuf, sizeof(buf), "Hello, %s!", "world"); // buf is now "Hello, world!"
+```
+
+### mg\_vasprintf()
+
+```c
+int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
+```
+
+Same as `mg_asprintf()` but uses `va_list` argument.
+
+Usage example:
+```c
+void foo(const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  char buf[1024], *pbuf = buf;
+  mg_vasprintf(&pbuf, sizeof(buf), fmt, ap);
+  va_end(ap);
+
+  printf("%s\n", buf);
+}
+
+// ...
+
+foo("Hello, %s!", "world"); // Print "Hello, world!
+
+```
+
+### mg\_to64()
+
+```c
+int64_t mg_to64(struct mg_str str);
+```
+
+Parse 64-bit integer value held by string `s`.
+
+Usage example:
+
+```c
+int64_t val = mg_to64(mg_str("123")); // Val is now 123
+```
+
+### mg\_aton()
+
+```c
+bool mg_aton(struct mg_str str, struct mg_addr *addr);
+```
+
+Parse IP address held by `str` and store it in `addr`. Return true on success.
+
+Usage example:
+
+```c
+struct mg_addr addr;
+if (mg_aton(mg_str("127.0.0.1"), &addr)) {
+  // addr is now binary representation of 127.0.0.1 IP address
+}
+```
+
+### mg\_ntoa()
+
+```c
+char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len);
+```
+
+Stringify IP address `ipaddr` into a buffer `buf`, `len`. Return `buf`.
+
+Usage example:
+
+```c
+char buf[100];
+mg_ntoa(&c->peer, buf, sizeof(buf));
+```
+
+## Utility
+
+### mg\_call()
+
+```c
+void mg_call(struct mg_connection *c, int ev, void *ev_data);
+```
+
+Send `ev` event to `c` event handler. This function is useful then implementing
+your own protocol.
+
+Usage example:
+
+```c
+// In a timer callback, send MG_EV_USER event to all connections
+static void timer_fn(void *arg) {
+  struct mg_mgr *mgr = (struct mg_mgr *) arg;
+  for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
+    mg_call(c, MG_EV_USER, "hi!");
+  }
+}
+```
+
+### mg\_error()
+
+```c
+void mg_error(struct mg_connection *c, const char *fmt, ...);
+```
+
+Send `MG_EV_ERROR` to connection event handler with error message formatted using printf semantics.
+
+Usage example:
+
+```c
+mg_error(c, "Operation failed, error code: %d", errno);
+```
+
+### mg\_md5\_init()
+
+```c
+void mg_md5_init(mg_md5_ctx *c);
+```
+
+Initialize context for MD5 hashing.
+
+Usage example:
+
+```c
+mg_md5_ctx ctx;
+mg_md5_init(&ctx);
+```
+
+### mg\_md5\_update()
+
+```c
+void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len);
+```
+Hash `len` bytes of data pointed by `data` using MD5 algorithm.
+
+Usage example:
+
+```c
+mg_md5_ctx ctx;
+// Context initialization
+// ...
+
+mg_md5_update(&ctx, "data", 4);       // hash "data" string
+mg_md5_update(&ctx, "more data", 9);  // hash "more data" string
+```
+
+### mg\_md5\_final()
+
+```c
+void mg_md5_final(mg_md5_ctx *c, unsigned char[16]);
+```
+
+Get current MD5 hash for context.
+
+Usage example:
+
+```c
+mg_md5_ctx ctx;
+// Context initialization
+// ...
+
+unsigned char buf[16];
+mg_md5_final(&ctx, buf);  // `buf` is now MD5 hash
+```
+
+### mg\_sha1\_init()
+
+```c
+void mg_sha1_init(mg_sha1_ctx *);
+```
+
+Initialize context for calculating SHA1 hash
+
+Usage example:
+
+```c
+mg_sha1_ctx ctx;
+mg_sha1_init(&ctx);
+```
+
+### mg\_sha1\_update()
+
+```c
+void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len);
+```
+
+Hash `len` bytes of `data` using SHA1 algorithm.
+
+Usage example:
+
+```c
+mg_sha1_ctx ctx;
+// Context initialization
+// ...
+
+mg_sha1_update(&ctx, "data", 4);      // hash "data" string
+mg_sha1_update(&ctx, "more data", 9); // hash "more data" string
+```
+
+### mg\_sha1\_final()
+
+```c
+void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *);
+```
+
+Get current SHA1 hash for context.
+
+Usage example:
+
+```c
+mg_sha1_ctx ctx;
+// Context initialization
+// ...
+
+unsigned char buf[20];
+mg_sha1_final(buf, &ctx); // `buf` is now SHA1 hash
+```
+
+### mg\_base64\_update()
+
+```c
+int mg_base64_update(unsigned char p, char *out, int pos);
+```
+
+Encode `p` byte to base64 and write result into `out` buffer starting with `pos` position.
+Return new position for futher operations.
+
+Usage example:
+
+```c
+char buf[10];
+mg_base64_update((unsigned char)"a", buf, 0); // Encode "a" into base64 and write it to the beginning of buf
+```
+
+### mg\_base64\_final()
+
+```c
+int mg_base64_final(char *buf, int pos);
+```
+
+Add base64 finish mark and `\0` symbol to `buf` at `pos` position.
+
+```c
+char buf[10];
+int pos;
+// ...
+
+mg_base64_final(buf, pos);
+```
+
+### mg\_base64\_encode()
+
+```c
+int mg_base64_encode(const unsigned char *p, int n, char *to);
+```
+
+Encode `n` bytes data pointed by `p` using base64 and write result into `to`. Return written symbols number.
+
+Usage example:
+
+```c
+char buf[128];
+mg_base64_encode((uint8_t *) "abcde", 5, buf); // buf is now YWJjZGU=
+```
+
+### mg\_base64\_decode()
+
+```c
+int mg_base64_decode(const char *src, int n, char *dst);
+```
+
+Decode `n` bytes of base64-ed `src` and write it to `dst`. Return number of written symbols.
+
+Usage example:
+
+```c
+char buf[128];
+mg_base64_decode("Q2VzYW50YQ==", 12, buf); // buf is now "Cesanta"
+```
+
+### mg\_file\_read()
+
+```c
+char *mg_file_read(const char *path, size_t *sizep);
+```
+
+Read file contents into a nul-terminated malloc-ed string. It is a caller's
+responsibility to free() a returned pointer. If `sizep` is not NULL, it will
+return a file size in bytes. Return `NULL` on error.
+
+Usage example:
+
+```c
+size_t file_size;
+char* data = mg_file_read("myfile.txt", &file_size);
+if (data != NULL) {
+  // `data` is now pointer to information readen from file and `file_size` is it size.
+}
+free(data);
+```
+
+### mg\_file\_write()
+
+```c
+bool mg_file_write(const char *path, const void *buf, size_t len);
+```
+
+Write data to a file, return `true` if written, `false` otherwise.
+The write is atomic, i.e. data gets written to a temporary file first, then `rename()-ed` to a destination file name.
+
+Usage example:
+
+```c
+char data[] = "Hello, world!";
+if(mg_file_write("my_file.txt", data, sizeof(data) - 1)) {
+  // File contains "Hello, world!" string
+}
+```
+
+### mg\_file\_printf()
+
+```c
+int mg_file_printf(const char *path, const char *fmt, ...);
+```
+
+Write into a file `path` using `printf()` semantics.
+Return `true` on success, `false` otherwise. This function prints data to a
+temporary in-memory buffer first, then calls `mg_file_write()`.
+
+```c
+if (mg_file_printf("my_file.txt", "Hello, %s!", "world") {
+  // File contains "Hello, world!" string
+}
+```
+
+### mg\_random()
+
+```c
+void mg_random(void *buf, size_t len);
+```
+
+Fill in buffer `buf`, `len` with random data. Note: Mongoose uses this
+function for TLS and some other routines that require RNG (random number
+generator). It is possible to override a built-in `mg_random()` by specifying
+a `MG_ENABLE_CUSTOM_RANDOM=1` build preprocessor constant.
+
+Usage example:
+```c
+char buf[10];
+mg_random(buf, sizeof(buf)); // `buf` is now random bytes
+```
+
+### mg\_ntohs()
+
+```c
+uint16_t mg_ntohs(uint16_t net);
+```
+
+Convert `uint16_t` value to host order.
+
+Usage example:
+
+```c
+uint16_t val = mg_ntohs(0x1234);
+```
+
+### mg\_ntohl()
+
+```c
+uint32_t mg_ntohl(uint32_t net);
+```
+
+Convert `uint32_t` value to host order.
+
+Usage example:
+
+```c
+uint32_t val = mg_ntohl(0x12345678);
+```
+
+### mg\_ntohs()
+
+```c
+uint16_t mg_htons(uint16_t net);
+```
+
+Convert `uint16_t` value to network order.
+
+Usage example:
+
+```c
+uint16_t val = mg_htons(0x1234);
+```
+
+### mg\_htonl()
+
+```c
+uint32_t mg_ntohl(uint32_t net);
+```
+
+Convert `uint32_t` value to network order.
+
+Usage example:
+
+```c
+uint32_t val = mg_htonl(0x12345678);
+```
+
+### mg\_crc32()
+
+```c
+uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
+```
+
+Calculate CRC32 checksum for a given buffer. An initial `crc` value should be `0`.
+
+Usage example:
+
+```c
+char data[] = "hello";
+uint32_t crc = mg_crc32(0, data, sizeof(data));
+```
+
+### mg\_check\_ip\_acl()
+
+```c
+int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip);
+```
+
+Check IPv4 address `remote_ip` against the IP ACL `acl`. Parameters:
+
+- `acl` - an ACL string, e.g. `-0.0.0.0/0,+1.2.3.4`
+- `remote_ip` - IPv4 address in network byte order
+
+Return value: 1 if `remote_ip` is allowed, 0 if not, and <0 if `acl` is invalid.
+
+Usage example:
+
+```c
+if (mg_check_ip_acl(mg_str("-0.0.0.0/0,+1.2.3.4"), c->peer.ip) != 1) {
+  LOG(LL_INFO, ("NOT ALLOWED!"));
+}
+```
+
+### mg\_url\_decode()
+
+```c
+int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
+```
+
+Decode URL-encoded string `s` and write it into `to` buffer.
+If `form` is non-zero, then `+` is decoded as whitespace.
+
+Usage example:
+
+```c
+char url[] = "eexample.org%2Ftest";
+char buf[1024];
+mg_url_encode(url, sizeof(url) - 1, buf, sizeof(buf), 0); // buf is now "example.org/test"
+```
+
+### mg\_url\_encode
+
+```c
+size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
+```
+
+Encode `s` string to URL-encoding and write encoded string into `buf`.
+Return number of characters written to `buf`
+
+Usage example:
+
+```c
+char url[] = "example.org/test";
+char buf[1024];
+mg_url_encode(url, sizeof(url) - 1, buf, sizeof(buf)); // buf is now "example.org%2Ftest"
+```
+
+## IO Buffers
+
+IO buffer, described by the `struct mg_iobuf`, is a simple data structure
+that insert or delete chunks of data at arbitrary offsets and grow/shrink
 automatically.
 
 ### struct mg\_iobuf
@@ -1371,15 +2526,24 @@ struct mg_iobuf {
 Generic IO buffer. The `size` specifies an allocation size of the data pointed
 by `buf`, and `len` specifies number of bytes currently stored.
 
+<img src="images/mg_iobuf.png">
+
 ### mg\_iobuf\_init()
 
 ```c
 int mg_iobuf_init(struct mg_iobuf *io, size_t size);
 ```
 
-Initialize IO buffer, allocate `size` bytes. Return 1 on success,
-0 on allocation failure.
+Initialize IO buffer, allocate `size` bytes. Return 1 on success, 0 on allocation failure.
 
+Usage example:
+
+```c
+struct mg_iobuf io;
+if (mg_iobuf_init(&io)) {
+  // io successfully initialized
+}
+```
 
 ### mg\_iobuf\_resize()
 
@@ -1392,6 +2556,17 @@ change after this, for example if the buffer grows. If `size` is 0, then the
 `io->buf` is freed and set to NULL, and both `size` and `len` are set to 0.
 Return 1 on success, 0 on allocation failure.
 
+Usage example:
+
+```c
+struct mg_iobuf io;
+// IO buffer initialization
+// ...
+
+if (mg_iobuf_resize(&io, 1024)) {
+  // New io size is 1024 bytes
+}
+```
 
 ### mg\_iobuf\_free()
 
@@ -1399,9 +2574,18 @@ Return 1 on success, 0 on allocation failure.
 void mg_iobuf_free(struct mg_iobuf *io);
 ```
 
-Free memory pointed by `io->buf` and set to NULL. Both `size` and `len` are set
-to 0.
+Free memory pointed by `io->buf` and set to NULL. Both `size` and `len` are set to 0.
+
+Usage example:
+
+```c
+struct mg_iobuf io;
+// IO buffer initialization
+// ...
 
+// Time to cleanup
+mg_iobuf_free(&io);
+```
 
 ### mg\_iobuf\_add()
 
@@ -1409,10 +2593,11 @@ to 0.
 size_t mg_iobuf_add(struct mg_iobuf *io, size_t offset, const void *buf, size_t len, size_t align);
 ```
 
-Insert data buffer `buf`, `len` at offset `offset`. The iobuf gets
-is expanded if required. The resulting `io->size` is always
-aligned to the `align` byte boundary - therefore, to avoid memory fragmentation
-and frequent reallocations, set `align` to a higher value. Example:
+Insert data buffer `buf`, `len` at offset `offset`. The iobuf gets is expanded
+if required. The resulting `io->size` is always aligned to the `align` byte boundary - therefore,
+to avoid memory fragmentation and frequent reallocations, set `align` to a higher value.
+
+Usage example:
 
 ```c
 struct mg_iobuf io;
@@ -1420,13 +2605,267 @@ mg_iobuf_init(&io, 0);               // Empty buffer
 mg_iobuf_add(&io, 0, "hi", 2, 512);  // io->len is 2, io->size is 512
 ```
 
+<img src="images/mg_iobuf_add.png">
+
 ### mg\_iobuf\_del()
 
 ```c
 size_t mg_iobuf_del(struct mg_iobuf *io, size_t offset, size_t len);
 ```
 
-Delete `len` bytes starting from `offset`, and shift the remaining
-bytes. If `len` is greater than `io->len`, nothing happens,
-so such call is silently ignored.
+Delete `len` bytes starting from `offset`, and shift the remaining bytes.
+If `len` is greater than `io->len`, nothing happens, so such call is silently ignored.
+
+Usage example:
+
+```c
+struct mg_iobuf io;
+mg_iobuf_init(&io, 0);               // Empty buffer
+mg_iobuf_add(&io, 0, "hi", 2, 512);  // io->len is 2, io->size is 512
+// ...
+mg_iobuf_del(&io, 0, "hi", 2, 512);  // io->len is 0, io->size is still 512
+
+```
+
+<img src="images/mg_iobug_del.png">
+
+## URL
+
+### mg\_url\_port()
+
+```c
+unsigned short mg_url_port(const char *url);
+```
+
+Return port for given `url` or `0` if url doesn't contain port and there isn't default port for url protocol.
+
+Usage example:
+
+```c
+unsigned short port1 = mg_url_port("htts://myhost.com") // port1 is now 443 (default https port)
+unsigned short port2 = mg_url_port("127.0.0.1:567") // port2 is now 567
+```
+
+### mg\_url\_is_ssl()
+
+```c
+int mg_url_is_ssl(const char *url);
+```
+
+Return `0` is given URL uses encrypted scheme and non-zero otherwise.
+
+Usage example:
+
+```c
+if (mg_url_is_ssl("https://example.org") == 0) {
+  // scheme is encrypted
+}
+```
+
+### mg\_url\_host()
+
+```c
+struct mg_str mg_url_host(const char *url);
+```
+
+Extract host name from given URL.
+
+Usage example:
+
+```c
+struct mg_str host = mg_url_host("https://my.example.org:1234"); // host is now "my.example.org"
+```
+
+### mg\_url\_user()
+
+```c
+struct mg_str mg_url_user(const char *url);
+```
+
+Extract user name from given URL.
+
+Usage example:
+
+```c
+struct mg_str user_name = mg_url_user("https://user@password@my.example.org"); // user_name is now "user"
+```
+
+### mg\_url\_pass()
+
+```c
+struct mg_str mg_url_pass(const char *url);
+```
+
+Extract user name from given URL.
+
+Usage example:
+
+```c
+struct mg_str pwd = mg_url_user("https://user@password@my.example.org"); // pwd is now "password"
+```
+
+### mg\_url\_uri()
+
+```c
+const char *mg_url_uri(const char *url);
+```
+
+Extract URI from given URL. Return `/` if no URI found.
+Note, that function returns pointer within `url`, no need to free() it explicitly.
+
+Usage example:
+
+```c
+const char *uri = mg_url_uri("https://example.org/subdir/subsubdir"); // `uri` is now pointer to "subdir/subsubdir"
+```
+
+
+
+## Logging
+
+Mongoose provides a set of functions and macroses for logging. Application can
+use these functions for its own purposes as well as the rest of Mongoose API.
+
+### LOG()
+
+```c
+#define LOG(level, args)
+```
+
+General way to log is using `LOG` macro.
+`LOG` prints to log only is `MG_ENABLE_LOG` macro defined, otherwise is does nothing.
+
+This macro has two arguments: log level and information to log. Second argument is a printf-alike format string.
+
+Log levels defined as:
+```c
+enum { LL_NONE, LL_ERROR, LL_INFO, LL_DEBUG, LL_VERBOSE_DEBUG };
+```
+
+Usage example:
+```c
+LOG(LL_ERROR, ("Hello %s!", "world"));  // Output "Hello, world"
+```
+
+### mg\_log\_set()
+
+```c
+void mg_log_set(const char *spec);
+```
+
+Set mongoose logging level. `spec` is a string, containing log level, can be one of the following values:
+
+- `0` - disable logging
+- `1` - log errors only
+- `2` - log errors and info messages
+- `3` - log errors, into and debug messages
+- `4` - log everything
+
+It is possible to override log level per source file basis. For example, if
+there is a file called `foo.c`, and you'd like to set a global level to `2`
+(info) but increase log level for file foo.c to `debug`. Then, a `spec` should
+look like `"2,foo.c=3"`. There could be several comma-separated overrides.
+
+Usage example:
+```c
+mg_log_set("2");                  // Set log level to info
+mg_log_set("2,foo.c=3,bar.c=0");  // Set log level to info, with overrides
+```
+
+### mg\_log\_set\_callback()
+
+```c
+void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *fnd);
+```
+
+By default, `LOG` writes to standard output stream (aka `stdout`), but this behaviour
+can be changes via `mg_log_set_callback`. This function allows to set callback,
+which called once mongoose (or host application) calls `LOG`
+
+Usage example:
+
+```c
+void log_via_printf(const void *buf, size_t len, void *userdata) {
+  (void) userdata;
+  printf("*.%s", buf, len);
+}
+
+// ...
+mg_log_set_callback(&log_via_printf, NULL);
+```
+
+## Filesystem
+
+### FS virtualisation
+
+Mongoose allows to override file i/o operations in order to support different
+storages, like programmable flash, no-filesystem devices etc.
+In order to accomplish this, Mongoose provides a `struct mg_fs` API to
+specify a custom filesystem. In addition to this, Mongoose provides two
+built-in APIs - a standard POSIX API, and a "packed FS" API. A packed FS
+allows to embed a filesystem into the application or firmware binary,
+and it is described below.
+
+```c
+enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 };
+
+// Filesystem API functions
+// stat() returns MG_FS_* flags and populates file size and modification time
+// list() calls fn() for every directory entry, allowing to list a directory
+struct mg_fs {
+  int (*stat)(const char *path, size_t *size, time_t *mtime);
+  void (*list)(const char *path, void (*fn)(const char *, void *), void *);
+  struct mg_fd *(*open)(const char *path, int flags);      // Open file
+  void (*close)(struct mg_fd *fd);                         // Close file
+  size_t (*read)(void *fd, void *buf, size_t len);         // Read file
+  size_t (*write)(void *fd, const void *buf, size_t len);  // Write file
+  size_t (*seek)(void *fd, size_t offset);                 // Set file position
+};
+```
+
+HTTP server's `struct mg_http_serve_opts` has a `fs` pointer which specifies
+which filesystem to use when serving static files. By default, `fs` is set
+to NULL and therefore a standard POSIX API is used. That could be overridden
+and a packed FS, or any other user-defined custom FS could be used:
+
+```c
+struct mg_http_serve_opts opts;
+opts.fs = &mg_fs_posix;
+mg_http_serve_dir(c, hm, &opts);
+```
+
+### Packed filesystem
+
+Packed filesystem allow to "pack" filesystem into single file, for example, into
+executable or flashable image. This is useful, for example, for implementation of HTTP-server on devices without filesystem.
+
+In order to use packed filesystem do the following:
+
+1. Compile file test\pack.c:
+  ```sh
+  $ cc -o pack pack.c
+  ```
+
+2. Convert list of files into single .c:
+  ```sh
+  $ ./pack file1.data file2.data > fs.c
+  ```
+
+3. Build your app with fs.c:
+  ```sh
+  $ cc -o my_app my_app.c fs.c
+  ```
+
+4. In your application code, you can access files using this function:<br>
+   `const char *mg_unpack(const char *file_name, size_t *size)` or app can also
+   force `mg_http_serve_dir` function to use packed file system:
+
+```c
+struct mg_http_serve_opts opts;
+opts.fs = &mg_fs_packed; // Set packed ds as a file system
+mg_http_serve_dir(c, hm, &opts);
+```
+
+<img src="images/packed.png">
 
+<img src="images/packed2.png">
diff --git a/docs/images/mg_commalist.png b/docs/images/mg_commalist.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9b97c4707f91293f988c667716a1f61c1c6c0ec
Binary files /dev/null and b/docs/images/mg_commalist.png differ
diff --git a/docs/images/mg_http_get_request_len.png b/docs/images/mg_http_get_request_len.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a1ef93161e72e3716f1559ccbe0ea053153fded
Binary files /dev/null and b/docs/images/mg_http_get_request_len.png differ
diff --git a/docs/images/mg_http_message.png b/docs/images/mg_http_message.png
new file mode 100644
index 0000000000000000000000000000000000000000..11ffdda71e93ee441b9c7cfa840a1b268914cfb1
Binary files /dev/null and b/docs/images/mg_http_message.png differ
diff --git a/docs/images/mg_http_next_multipart.png b/docs/images/mg_http_next_multipart.png
new file mode 100644
index 0000000000000000000000000000000000000000..a414559cc7332e488ace57e9c85ef2b90264d902
Binary files /dev/null and b/docs/images/mg_http_next_multipart.png differ
diff --git a/docs/images/mg_http_part.png b/docs/images/mg_http_part.png
new file mode 100644
index 0000000000000000000000000000000000000000..a32c2f928a5c89cfad9f99966810dde4d2d18204
Binary files /dev/null and b/docs/images/mg_http_part.png differ
diff --git a/docs/images/mg_http_reply.png b/docs/images/mg_http_reply.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba3a9cc20a0185494ed2a3f17b6288be8cf5b69d
Binary files /dev/null and b/docs/images/mg_http_reply.png differ
diff --git a/docs/images/mg_iobuf.png b/docs/images/mg_iobuf.png
new file mode 100644
index 0000000000000000000000000000000000000000..35c509410ee858af8058412dc54f9531acc6e1b4
Binary files /dev/null and b/docs/images/mg_iobuf.png differ
diff --git a/docs/images/mg_iobuf_add.png b/docs/images/mg_iobuf_add.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1fd940aa34b59a90aa962e3f95d43b66d40752c
Binary files /dev/null and b/docs/images/mg_iobuf_add.png differ
diff --git a/docs/images/mg_iobug_del.png b/docs/images/mg_iobug_del.png
new file mode 100644
index 0000000000000000000000000000000000000000..52b8e154b59a23ed2e7dd6545f71f72239d2bdd4
Binary files /dev/null and b/docs/images/mg_iobug_del.png differ
diff --git a/docs/images/packed.png b/docs/images/packed.png
new file mode 100644
index 0000000000000000000000000000000000000000..a2ae271fe78ac64c763ee9fa28e54003b6d6676c
Binary files /dev/null and b/docs/images/packed.png differ
diff --git a/docs/images/packed2.png b/docs/images/packed2.png
new file mode 100644
index 0000000000000000000000000000000000000000..ada6a0240d2b719cc7416086c0a9208602163ab7
Binary files /dev/null and b/docs/images/packed2.png differ