Refactor Mongoose documentation

PUBLISHED_FROM=e9a4e5c7b4a1d03b93a2a79e29de19e60e919929
This commit is contained in:
Sergey Lyubka authored and Cesanta Bot committed 2016-09-01 14:35:02 +00:00
1 parent 4120f953c7
commit 12437fd7fe
87 files changed
+977 -332

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
---
title: CGI
---
[CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface)
is a simple mechanism to generate dynamic content.
In order to use CGI, call `mg_serve_http()` function and use
`.cgi` file extension for the CGI files. To be more precise,
all files that match `cgi_file_pattern` setting in the
`struct mg_serve_http_opts` are treated as CGI.
If `cgi_file_pattern` is NULL, `**.cgi$|**.php$` is used.
If Mongoose recognises a file as CGI, it executes it, and sends the output
back to the client. Therefore,
CGI file must be executable. Mongoose honours the shebang line - see
http://en.wikipedia.org/wiki/Shebang_(Unix).
For example, if both PHP and Perl CGIs are used, then
``#!/path/to/php-cgi.exe` and ``#!/path/to/perl.exe` must be the first lines
of the respective CGI scripts.
It is possible to hardcode the path to the CGI interpreter for all
CGI scripts and disregard the shebang line. To do that, set the
`cgi_interpreter` setting in the `struct mg_serve_http_opts`.
NOTE: PHP scripts must use `php-cgi.exe` as CGI interpreter, not `php.exe`.
Example:
```c
opts.cgi_interpreter = "C:\\ruby\\ruby.exe";
```
+44
View File
@@ -0,0 +1,44 @@
---
title: HTTP client example
---
To create an HTTP client, follow this pattern:
1. Create an outbound connection by calling `mg_connect_http()`
2. Create an event handler function that handles `MG_EV_HTTP_REPLY` event
Here's an example of the simplest HTTP client.
Error checking is omitted for the sake of clarity:
```c
#include "mongoose.h"
static const char *url = "http://www.google.com";
static int exit_flag = 0;
static void ev_handler(struct mg_connection *c, int ev, void *p) {
if (ev == MG_EV_HTTP_REPLY) {
c->flags |= MG_F_CLOSE_IMMEDIATELY;
fwrite(hm->message.p, 1, hm->message.len, stdout);
putchar('\n');
exit_flag = 1;
}
}
int main(void) {
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL);
mg_connect_http(mgr, ev_handler, url, NULL, NULL);
while (exit_flag == 0) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
```
See full source code at [HTTP client example](https://github.com/cesanta/dev/tree/master/mongoose/examples/http_client).
+5
View File
@@ -0,0 +1,5 @@
---
title: Digest Authentication
---
TBD
+39
View File
@@ -0,0 +1,39 @@
---
title: HTTP events
---
As discussed in the overview, `mg_set_protocol_http_websocket()` function
parses incoming data, treats it as HTTP or WebSocket, and triggers high-level
HTTP or WebSocket events. Here is a list of events specific to HTTP.
- MG_EV_HTTP_REQUEST: An HTTP request has arrived. Parsed request
is passed as
`struct http_message` through the handler's `void *ev_data` pointer.
- MG_EV_HTTP_REPLY: An HTTP reply has arrived. Parsed reply is
passed as `struct http_message` through the handler's `void *ev_data`
pointer.
- MG_EV_HTTP_MULTIPART_REQUEST: A multipart POST request has arrived.
This event is sent before body is parsed. After this, the user
should expect a sequence of MG_EV_HTTP_PART_BEGIN/DATA/END requests.
This is also the last time when headers and other request fields are
accessible.
- MG_EV_HTTP_CHUNK: An HTTP chunked-encoding chunk has arrived.
The parsed HTTP reply is passed as `struct http_message` through the
handler's `void *ev_data` pointer. `http_message::body` would contain
incomplete, reassembled HTTP body.
It will grow with every new chunk that arrives, and it can
potentially consume a lot of memory. The event handler may process
the body as chunks are coming, and signal Mongoose to delete processed
body by setting `MG_F_DELETE_CHUNK` in `mg_connection::flags`. When
the last zero chunk is received,
Mongoose sends `MG_EV_HTTP_REPLY` event with
full reassembled body (if handler did not signal to delete chunks) or
with empty body (if handler did signal to delete chunks).
- MG_EV_HTTP_PART_BEGIN: a new part of multipart message is started,
extra parameters are passed in mg_http_multipart_part
- MG_EV_HTTP_PART_DATA: a new portion of data from the multiparted message
no additional headers are available, only data and data size
- MG_EV_HTTP_PART_END: a final boundary received, analogue to maybe used to
find the end of packet
Note: Mongoose should be compiled with MG_ENABLE_HTTP_STREAMING_MULTIPART
to enable multipart events.
+46
View File
@@ -0,0 +1,46 @@
---
title: Serving files
---
API function `mg_serve_http()` makes it easy to serve files from a filesystem.
Generally speaking, that function is an implementation of the HTTP server
that serves static files, CGI and SSI. It's behavior is driven by a list
of options that are consolidated into the `struct mg_serve_http_opts`
structure. See [struct mg_serve_http_opts](#) definition for the full list
of capabilities of `mg_serve_http()`.
For example, in order to create a web server that serves static files
from the current directory, implement event handler function as follows:
```c
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_REQUEST) {
struct mg_serve_http_opts opts;
memset(&opts, 0, sizeof(opts); // Reset all options to defaults
opts.document_root = "."; // Serve files from the current directory
mg_serve_http(c, (struct http_message *) ev_data, s_http_server_opts);
}
}
```
See working example at [simplest web server](https://github.com/cesanta/mongoose/tree/master/examples/simplest_web_server).
Sometimes there is no need to implement a full static web server, for example
if one works on a RESTful server. If certain endpoints must return the contents
of a static file, a simpler `mg_http_serve_file()` function can be used:
```c
static void ev_handler(struct mg_connection *c, 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(c, hm, "file.txt",
mg_mk_str("text/plain"), mg_mk_str(""));
break;
}
...
}
}
```
+16
View File
@@ -0,0 +1,16 @@
---
title: HTTP
items:
- { name: server_example.md }
- { name: client_example.md }
- { name: events.md }
- { name: files.md }
- { name: cgi.md }
- { name: ssi.md }
- { name: upload.md }
- { name: ssl.md }
- { name: digest_auth.md }
- { name: ../c-api/http.h/ }
- { name: ../c-api/http_server.h/ }
- { name: ../c-api/http_client.h/ }
---
+53
View File
@@ -0,0 +1,53 @@
---
title: HTTP server example
---
To create an HTTP server, follow this pattern:
1. Create a listening connection by calling `mg_bind()` or `mg_bind_opt()`
2. Call `mg_set_protocol_http_websocket()` for that listening connection.
That attaches a built-in HTTP event handler which parses incoming
data and triggers HTTP-specific events. For example, when an HTTP request
is fully buffered, a built-in HTTP handler parses the request and
calls user-defined event handler with `MG_EV_HTTP_REQUEST` event and
parsed HTTP request as an event data.
3. Create event handler function. Note that event handler receives all
events - low level TCP events like `MG_EV_RECV` and high-level HTTP
events like `MG_EV_HTTP_REQUEST`. Normally, an event handler function
should only handle `MG_EV_HTTP_REQUEST` event.
Here's an example of the simplest HTTP server. Error checking is omitted for
the sake of clarity:
```c
#include "mongoose.h"
static const char *s_http_port = "8000";
static void ev_handler(struct mg_connection *c, int ev, void *p) {
if (ev == MG_EV_HTTP_REQUEST) {
struct http_message *hm = (struct http_message *) p;
// We have received an HTTP request. Parsed request is contained in `hm`.
// Send HTTP reply to the client which shows full original request.
mg_send_head(c, 200, hm.message.len, "Content-Type: text/plain");
mg_printf(c, "%.*s", hm.message.len, hm.message.p);
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *c;
mg_mgr_init(&mgr, NULL);
c = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(c);
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
```
+59
View File
@@ -0,0 +1,59 @@
---
title: 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 to use SSI, call `mg_serve_http()` function and use
`.shtml` file extension for the SSI files. To be more precise,
all files that match `ssi_pattern` setting in the
`struct mg_serve_http_opts` are treated as SSI.
If `ssi_pattern` is NULL, `**.shtml$|**.shtm$` is used.
Unknown SSI directives are silently ignored by Mongoose. Currently,
the following SSI directives are supported:
- `<!--#include FILE_TO_INCLUDE -->` - inject the content of some other file
- `<!--#exec "COMMAND_TO_EXECUTE" -->` - runs a command and inject the output
- `<!--#call COMMAND -->` - triggers `MG_EV_SSI_CALL` event
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" -->`, `<!--#include "path" -->`
Path is relative to current document
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 PARAMS -->` directive,
Mongoose calls a registered event handler with `MG_EV_SSI_CALL` event.
Event parameter will point to the `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:
```c
case MG_EV_SSI_CALL: {
const char *param = (const char *) ev_data;
if (strcmp(param, "foo") == 0) {
mg_printf(c, "hello from foo");
} else if (strcmp(param, "bar") == 0) {
mg_printf(c, "hello from bar");
}
break;
}
```
+33
View File
@@ -0,0 +1,33 @@
---
title: Enabling HTTPS
---
To enable SSL on the server side, please follow these steps:
- Obtain SSL certificate file and private key file
- Declare `struct mg_bind_opts`, initialize `ssl_cert` and `ssl_key`
- Use `mg_bind_opt()` to create listening socket
Example:
```c
int main(void) {
struct mg_mgr mgr;
struct mg_connection *c;
struct mg_bind_opts bind_opts;
mg_mgr_init(&mgr, NULL);
memset(&bind_opts, 0, sizeof(bind_opts));
bind_opts.ssl_cert = "server.pem";
bind_opts.ssl_key = "key.pem";
// Use bind_opts to specify SSL certificate & key file
c = mg_bind_opt(&mgr, "443", ev_handler, bind_opts);
mg_set_protocol_http_websocket(c);
...
}
```
For the full example, please see the [Simplest HTTPS server example](https://github.com/cesanta/dev/tree/master/mongoose/examples/simplest_web_server_ssl).
+36
View File
@@ -0,0 +1,36 @@
---
title: Handling file uploads
---
In order to handle file uploads, use the following HTML snippet:
```HTML
&lt;form method="POST" action="/upload" enctype="multipart/form-data"&gt;
&lt;input type="file" name="file"&gt;
&lt;input type="submit" value="Upload"&gt;
&lt;/form&gt;
```
Uploaded files will be sent to the `/upload` endpoint via the `POST` request.
HTTP body will contain multipart-encoded buffer with the file contents.
To save the uploaded file, use this code snippet:
```c
struct mg_str cb(struct mg_connection *c, struct mg_str file_name) {
// Return the same filename. Do not actually do this except in test!
// fname is user-controlled and needs to be sanitized.
return file_name;
}
void ev_handler(struct mg_connection *c, 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(c, ev, ev_data, cb);
break;
}
}
```