mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-24 11:54:49 +00:00
Refactor Mongoose documentation
PUBLISHED_FROM=e9a4e5c7b4a1d03b93a2a79e29de19e60e919929
This commit is contained in:
1 parent
4120f953c7
commit
12437fd7fe
87 files changed
+977
-332
No files matched your search
@@ -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";
|
||||
```
|
||||
@@ -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).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Digest Authentication
|
||||
---
|
||||
|
||||
TBD
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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/ }
|
||||
---
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
@@ -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).
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Handling file uploads
|
||||
---
|
||||
|
||||
In order to handle file uploads, use the following HTML snippet:
|
||||
|
||||
```HTML
|
||||
<form method="POST" action="/upload" enctype="multipart/form-data">
|
||||
<input type="file" name="file">
|
||||
<input type="submit" value="Upload">
|
||||
</form>
|
||||
```
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in new issue
Block a user