Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
900bbe72
Commit
900bbe72
authored
Oct 26, 2016
by
Marko Mikulicic
Committed by
Cesanta Bot
Oct 26, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mongoose forwarding
PUBLISHED_FROM=51652f0157bb951a43508f0fe948c62c351e96ba
parent
f5a28576
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
327 additions
and
35 deletions
+327
-35
intro.md
docs/c-api/http_server.h/intro.md
+1
-0
mg_http_send_error.md
docs/c-api/http_server.h/mg_http_send_error.md
+11
-0
struct_mg_serve_http_opts.md
docs/c-api/http_server.h/struct_mg_serve_http_opts.md
+8
-4
Makefile
examples/reverse_proxy/Makefile
+4
-0
hello.html
examples/reverse_proxy/frontend/hello.html
+6
-0
reverse_proxy.c
examples/reverse_proxy/reverse_proxy.c
+127
-0
mongoose.c
mongoose.c
+150
-27
mongoose.h
mongoose.h
+20
-4
No files found.
docs/c-api/http_server.h/intro.md
View file @
900bbe72
...
...
@@ -8,6 +8,7 @@ items:
-
{
name
:
mg_get_http_var.md
}
-
{
name
:
mg_http_check_digest_auth.md
}
-
{
name
:
mg_http_parse_header.md
}
-
{
name
:
mg_http_send_error.md
}
-
{
name
:
mg_http_send_redirect.md
}
-
{
name
:
mg_http_serve_file.md
}
-
{
name
:
mg_parse_http.md
}
...
...
docs/c-api/http_server.h/mg_http_send_error.md
0 → 100644
View file @
900bbe72
---
title
:
"
mg_http_send_error()"
decl_name
:
"
mg_http_send_error"
symbol_kind
:
"
func"
signature
:
|
void mg_http_send_error(struct mg_connection *nc, int code, const char *reason);
---
Sends an error response. If reason is NULL, the message will be inferred
from the error code (if supported).
docs/c-api/http_server.h/struct_mg_serve_http_opts.md
View file @
900bbe72
...
...
@@ -100,16 +100,19 @@ signature: |
/* IP ACL. By default, NULL, meaning all IPs are allowed to connect */
const char *ip_acl;
#if MG_ENABLE_HTTP_URL_REWRITES
/* URL rewrites.
*
* Comma-separated list of `uri_pattern=file_or_directory_path` rewrites.
* Comma-separated list of `uri_pattern=
url_
file_or_directory_path` rewrites.
* When HTTP request is received, Mongoose constructs a file name from the
* requested URI by combining `document_root` and the URI. However, if the
* rewrite option is used and `uri_pattern` matches requested URI, then
* `document_root` is ignored. Instead, `file_or_directory_path` is used,
* `document_root` is ignored. Instead, `
url_
file_or_directory_path` is used,
* which should be a full path name or a path relative to the web server's
* current working directory. Note that `uri_pattern`, as all Mongoose
* patterns, is a prefix pattern.
* current working directory. It can also be an URI (http:// or https://)
* in which case mongoose will behave as a reverse proxy for that destination.
*
* Note that `uri_pattern`, as all Mongoose patterns, is a prefix pattern.
*
* If uri_pattern starts with `@` symbol, then Mongoose compares it with the
* HOST header of the request. If they are equal, Mongoose sets document root
...
...
@@ -123,6 +126,7 @@ signature: |
* automatically appended to the redirect location.
*/
const char *url_rewrites;
#endif
/* DAV document root. If NULL, DAV requests are going to fail. */
const char *dav_document_root;
...
...
examples/reverse_proxy/Makefile
0 → 100644
View file @
900bbe72
PROG
=
reverse_proxy
MODULE_CFLAGS
=
SSL_LIB
=
include
../examples.mk
examples/reverse_proxy/frontend/hello.html
0 → 100644
View file @
900bbe72
<!DOCTYPE html>
<html>
<body>
Hello
</body>
</html>
examples/reverse_proxy/reverse_proxy.c
0 → 100644
View file @
900bbe72
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
/*
* This example shows how mongoose can be used as a reverse
* proxy for another http server.
*
* A common setup is to have a frontend web server that delegates
* some urls to a backend web server.
*
* In this example we create two webservers. The frontend listens on port
* 8000 and servers a static file and forwards any call matching the /api prefix
* to the backend.
*
* The backend listens on port 8001 and replies a simple JSON object which
* shows the request URI that the backend http server receives.
*
* Things to try out:
*
* curl http://localhost:8000/
* curl http://localhost:8000/api
* curl http://localhost:8000/api/foo
* curl http://localhost:8001/foo
*
* The reverse proxy functionality is enabled via the url rewrite functionality:
*
* ```
* s_frontend_server_opts.url_rewrites =
* "/api=http://localhost:8001,/=frontend/hello.html";
* ```
*
* This example maps the /api to a remote http server, and / to a
* specific file on the filesystem.
*
* Obviously you can use any http server as the backend, we spawn
* another web server from the same process in order to make the example easy
* to run.
*/
#include "../../mongoose.h"
static
const
char
*
s_frontend_port
=
"8000"
;
static
struct
mg_serve_http_opts
s_frontend_server_opts
;
static
const
char
*
s_backend_port
=
"8001"
;
static
struct
mg_serve_http_opts
s_backend_server_opts
;
static
void
frontend_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
ev_data
;
switch
(
ev
)
{
case
MG_EV_HTTP_REQUEST
:
mg_serve_http
(
nc
,
hm
,
s_frontend_server_opts
);
/* Serve static content */
break
;
default:
break
;
}
}
static
void
backend_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
ev_data
;
int
i
;
switch
(
ev
)
{
case
MG_EV_HTTP_REQUEST
:
mg_send_response_line
(
nc
,
200
,
"Content-Type: text/html
\r\n
"
"Connection: close
\r\n
"
);
mg_printf
(
nc
,
"{
\"
uri
\"
:
\"
%.*s
\"
,
\"
method
\"
:
\"
%.*s
\"
,
\"
body
\"
:
\"
%.*s
\"
, "
"
\"
headers
\"
: {"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
,
(
int
)
hm
->
method
.
len
,
hm
->
method
.
p
,
(
int
)
hm
->
body
.
len
,
hm
->
body
.
p
);
for
(
i
=
0
;
i
<
MG_MAX_HTTP_HEADERS
&&
hm
->
header_names
[
i
].
len
>
0
;
i
++
)
{
struct
mg_str
hn
=
hm
->
header_names
[
i
];
struct
mg_str
hv
=
hm
->
header_values
[
i
];
mg_printf
(
nc
,
"%s
\"
%.*s
\"
:
\"
%.*s
\"
"
,
(
i
!=
0
?
","
:
""
),
(
int
)
hn
.
len
,
hn
.
p
,
(
int
)
hv
.
len
,
hv
.
p
);
}
mg_printf
(
nc
,
"}}"
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
break
;
default:
break
;
}
}
int
main
(
int
argc
,
char
*
argv
[])
{
struct
mg_mgr
mgr
;
struct
mg_connection
*
nc
;
int
i
;
/* Open listening socket */
mg_mgr_init
(
&
mgr
,
NULL
);
/* configure frontend web server */
nc
=
mg_bind
(
&
mgr
,
s_frontend_port
,
frontend_handler
);
mg_set_protocol_http_websocket
(
nc
);
s_frontend_server_opts
.
document_root
=
"frontend"
;
s_frontend_server_opts
.
url_rewrites
=
"/api=http://localhost:8001,/=frontend/hello.html"
;
/* configure backend web server */
nc
=
mg_bind
(
&
mgr
,
s_backend_port
,
backend_handler
);
mg_set_protocol_http_websocket
(
nc
);
s_backend_server_opts
.
document_root
=
"backend"
;
/* Parse command line arguments */
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
if
(
strcmp
(
argv
[
i
],
"-D"
)
==
0
)
{
mgr
.
hexdump_file
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-r"
)
==
0
)
{
s_frontend_server_opts
.
document_root
=
argv
[
++
i
];
}
}
printf
(
"Starting web server on port %s
\n
"
,
s_frontend_port
);
for
(;;)
{
mg_mgr_poll
(
&
mgr
,
1000
);
}
}
mongoose.c
View file @
900bbe72
...
...
@@ -1181,6 +1181,19 @@ int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
if
(
i
<
str2
.
len
)
return
-
1
;
return
0
;
}
int
mg_strncmp
(
const
struct
mg_str
str1
,
const
struct
mg_str
str2
,
size_t
n
)
{
struct
mg_str
s1
=
str1
;
struct
mg_str
s2
=
str2
;
if
(
s1
.
len
>
n
)
{
s1
.
len
=
n
;
}
if
(
s2
.
len
>
n
)
{
s2
.
len
=
n
;
}
return
mg_strcmp
(
s1
,
s2
);
}
#ifdef MG_MODULE_LINES
#line 1 "common/sha1.c"
#endif
...
...
@@ -3970,6 +3983,10 @@ struct mg_http_proto_data {
};
static
void
mg_http_conn_destructor
(
void
*
proto_data
);
struct
mg_connection
*
mg_connect_http_base
(
struct
mg_mgr
*
mgr
,
mg_event_handler_t
ev_handler
,
struct
mg_connect_opts
opts
,
const
char
*
schema
,
const
char
*
schema_ssl
,
const
char
*
url
,
const
char
**
path
,
char
**
addr
);
static
struct
mg_http_proto_data
*
mg_http_get_proto_data
(
struct
mg_connection
*
c
)
{
...
...
@@ -5039,40 +5056,37 @@ void mg_set_protocol_http_websocket(struct mg_connection *nc) {
nc
->
proto_handler
=
mg_http_handler
;
}
void
mg_send_response_line_s
(
struct
mg_connection
*
nc
,
int
status_code
,
const
struct
mg_str
extra_headers
)
{
const
char
*
status_message
=
"OK"
;
const
char
*
mg_status_message
(
int
status_code
)
{
switch
(
status_code
)
{
case
206
:
status_message
=
"Partial Content"
;
break
;
return
"Partial Content"
;
case
301
:
status_message
=
"Moved"
;
break
;
return
"Moved"
;
case
302
:
status_message
=
"Found"
;
break
;
return
"Found"
;
case
401
:
status_message
=
"Unauthorized"
;
break
;
return
"Unauthorized"
;
case
403
:
status_message
=
"Forbidden"
;
break
;
return
"Forbidden"
;
case
404
:
status_message
=
"Not Found"
;
break
;
return
"Not Found"
;
case
416
:
status_message
=
"Requested range not satisfiable"
;
break
;
return
"Requested range not satisfiable"
;
case
418
:
status_message
=
"I'm a teapot"
;
break
;
return
"I'm a teapot"
;
case
500
:
status_message
=
"Internal Server Error"
;
break
;
return
"Internal Server Error"
;
case
502
:
return
"Bad Gateway"
;
default:
return
"OK"
;
}
mg_printf
(
nc
,
"HTTP/1.1 %d %s
\r\n
Server: %s
\r\n
"
,
status_code
,
status_message
,
mg_version_header
);
}
void
mg_send_response_line_s
(
struct
mg_connection
*
nc
,
int
status_code
,
const
struct
mg_str
extra_headers
)
{
mg_printf
(
nc
,
"HTTP/1.1 %d %s
\r\n
Server: %s
\r\n
"
,
status_code
,
mg_status_message
(
status_code
),
mg_version_header
);
if
(
extra_headers
.
len
>
0
)
{
mg_printf
(
nc
,
"%.*s
\r\n
"
,
(
int
)
extra_headers
.
len
,
extra_headers
.
p
);
}
...
...
@@ -5116,10 +5130,9 @@ void mg_send_head(struct mg_connection *c, int status_code,
mg_send
(
c
,
"
\r\n
"
,
2
);
}
#if MG_ENABLE_FILESYSTEM
static
void
mg_http_send_error
(
struct
mg_connection
*
nc
,
int
code
,
void
mg_http_send_error
(
struct
mg_connection
*
nc
,
int
code
,
const
char
*
reason
)
{
if
(
!
reason
)
reason
=
""
;
if
(
!
reason
)
reason
=
mg_status_message
(
code
)
;
DBG
((
"%p %d %s"
,
nc
,
code
,
reason
));
mg_send_head
(
nc
,
code
,
strlen
(
reason
),
"Content-Type: text/plain
\r\n
Connection: close"
);
...
...
@@ -5127,6 +5140,7 @@ static void mg_http_send_error(struct mg_connection *nc, int code,
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
#if MG_ENABLE_FILESYSTEM
static
void
mg_http_construct_etag
(
char
*
buf
,
size_t
buf_len
,
const
cs_stat_t
*
st
)
{
snprintf
(
buf
,
buf_len
,
"
\"
%lx.%"
INT64_FMT
"
\"
"
,
(
unsigned
long
)
st
->
st_mtime
,
...
...
@@ -5784,6 +5798,7 @@ MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
DBG
((
"[%s] [%s]"
,
path
,
(
*
index_file
?
*
index_file
:
""
)));
}
#if MG_ENABLE_HTTP_URL_REWRITES
static
int
mg_http_send_port_based_redirect
(
struct
mg_connection
*
c
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
...
...
@@ -5807,6 +5822,103 @@ static int mg_http_send_port_based_redirect(
return
0
;
}
static
void
mg_reverse_proxy_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
ev_data
;
struct
mg_connection
*
upstream
=
(
struct
mg_connection
*
)
nc
->
user_data
;
switch
(
ev
)
{
case
MG_EV_CONNECT
:
if
(
*
(
int
*
)
ev_data
!=
0
)
{
mg_http_send_error
(
upstream
,
502
,
NULL
);
}
break
;
/* TODO(mkm): handle streaming */
case
MG_EV_HTTP_REPLY
:
mg_send
(
upstream
,
hm
->
message
.
p
,
hm
->
message
.
len
);
upstream
->
flags
|=
MG_F_SEND_AND_CLOSE
;
nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
break
;
case
MG_EV_CLOSE
:
upstream
->
flags
|=
MG_F_SEND_AND_CLOSE
;
break
;
}
}
void
mg_handle_reverse_proxy
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
struct
mg_str
mount
,
struct
mg_str
upstream
)
{
struct
mg_connection
*
be
;
char
burl
[
256
],
*
purl
=
burl
;
char
*
addr
=
NULL
;
const
char
*
path
=
NULL
;
int
i
;
struct
mg_connect_opts
opts
;
memset
(
&
opts
,
0
,
sizeof
(
opts
));
mg_asprintf
(
&
purl
,
sizeof
(
burl
),
"%.*s%.*s"
,
(
int
)
upstream
.
len
,
upstream
.
p
,
(
int
)
(
hm
->
uri
.
len
-
mount
.
len
),
hm
->
uri
.
p
+
mount
.
len
);
be
=
mg_connect_http_base
(
nc
->
mgr
,
mg_reverse_proxy_handler
,
opts
,
"http://"
,
"https://"
,
purl
,
&
path
,
&
addr
);
DBG
((
"Proxying %.*s to %s (rule: %.*s)"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
,
purl
,
(
int
)
mount
.
len
,
mount
.
p
));
if
(
be
==
NULL
)
{
mg_http_send_error
(
nc
,
502
,
NULL
);
goto
cleanup
;
}
be
->
user_data
=
nc
;
/* send request upstream */
mg_printf
(
be
,
"%.*s %s HTTP/1.1
\r\n
"
,
(
int
)
hm
->
method
.
len
,
hm
->
method
.
p
,
path
);
mg_printf
(
be
,
"Host: %s
\r\n
"
,
addr
);
for
(
i
=
0
;
i
<
MG_MAX_HTTP_HEADERS
&&
hm
->
header_names
[
i
].
len
>
0
;
i
++
)
{
struct
mg_str
hn
=
hm
->
header_names
[
i
];
struct
mg_str
hv
=
hm
->
header_values
[
i
];
/* we rewrite the host header */
if
(
mg_vcasecmp
(
&
hn
,
"Host"
)
==
0
)
continue
;
/*
* Don't pass chunked transfer encoding to the client because hm->body is
* already dechunked when we arrive here.
*/
if
(
mg_vcasecmp
(
&
hn
,
"Transfer-encoding"
)
==
0
&&
mg_vcasecmp
(
&
hv
,
"chunked"
)
==
0
)
{
mg_printf
(
be
,
"Content-Length: %"
SIZE_T_FMT
"
\r\n
"
,
hm
->
body
.
len
);
continue
;
}
mg_printf
(
be
,
"%.*s: %.*s
\r\n
"
,
(
int
)
hn
.
len
,
hn
.
p
,
(
int
)
hv
.
len
,
hv
.
p
);
}
mg_send
(
be
,
"
\r\n
"
,
2
);
mg_send
(
be
,
hm
->
body
.
p
,
hm
->
body
.
len
);
cleanup:
if
(
purl
!=
burl
)
MG_FREE
(
purl
);
}
static
int
mg_http_handle_forwarding
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
a
,
b
;
struct
mg_str
p1
=
MG_MK_STR
(
"http://"
),
p2
=
MG_MK_STR
(
"https://"
);
while
((
rewrites
=
mg_next_comma_list_entry
(
rewrites
,
&
a
,
&
b
))
!=
NULL
)
{
if
(
mg_strncmp
(
a
,
hm
->
uri
,
a
.
len
)
==
0
)
{
if
(
mg_strncmp
(
b
,
p1
,
p1
.
len
)
==
0
||
mg_strncmp
(
b
,
p2
,
p2
.
len
)
==
0
)
{
mg_handle_reverse_proxy
(
nc
,
hm
,
a
,
b
);
return
1
;
}
}
}
return
0
;
}
#endif
MG_INTERNAL
int
mg_uri_to_local_path
(
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
,
char
**
local_path
,
...
...
@@ -5820,7 +5932,12 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
remainder
->
len
=
0
;
{
/* 1. Determine which root to use. */
#if MG_ENABLE_HTTP_URL_REWRITES
const
char
*
rewrites
=
opts
->
url_rewrites
;
#else
const
char
*
rewrites
=
""
;
#endif
struct
mg_str
*
hh
=
mg_get_http_header
(
hm
,
"Host"
);
struct
mg_str
a
,
b
;
/* Check rewrites first. */
...
...
@@ -6154,9 +6271,15 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
return
;
}
#if MG_ENABLE_HTTP_URL_REWRITES
if
(
mg_http_handle_forwarding
(
nc
,
hm
,
&
opts
))
{
return
;
}
if
(
mg_http_send_port_based_redirect
(
nc
,
hm
,
&
opts
))
{
return
;
}
#endif
if
(
opts
.
document_root
==
NULL
)
{
opts
.
document_root
=
"."
;
...
...
mongoose.h
View file @
900bbe72
...
...
@@ -1354,6 +1354,7 @@ int mg_vcasecmp(const struct mg_str *str2, const char *str1);
struct
mg_str
mg_strdup
(
const
struct
mg_str
s
);
int
mg_strcmp
(
const
struct
mg_str
str1
,
const
struct
mg_str
str2
);
int
mg_strncmp
(
const
struct
mg_str
str1
,
const
struct
mg_str
str2
,
size_t
n
);
#ifdef __cplusplus
}
...
...
@@ -1779,6 +1780,11 @@ char *strdup(const char *src);
#define MG_ENABLE_MQTT 1
#endif
#ifndef MG_ENABLE_HTTP_URL_REWRITES
#define MG_ENABLE_HTTP_URL_REWRITES \
(CS_PLATFORM == CS_P_WINDOWS || CS_PLATFORM == CS_P_UNIX)
#endif
#endif
/* CS_MONGOOSE_SRC_FEATURES_H_ */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/net.h"
...
...
@@ -3226,16 +3232,19 @@ struct mg_serve_http_opts {
/* IP ACL. By default, NULL, meaning all IPs are allowed to connect */
const
char
*
ip_acl
;
#if MG_ENABLE_HTTP_URL_REWRITES
/* URL rewrites.
*
* Comma-separated list of `uri_pattern=file_or_directory_path` rewrites.
* Comma-separated list of `uri_pattern=
url_
file_or_directory_path` rewrites.
* When HTTP request is received, Mongoose constructs a file name from the
* requested URI by combining `document_root` and the URI. However, if the
* rewrite option is used and `uri_pattern` matches requested URI, then
* `document_root` is ignored. Instead, `file_or_directory_path` is used,
* `document_root` is ignored. Instead, `
url_
file_or_directory_path` is used,
* which should be a full path name or a path relative to the web server's
* current working directory. Note that `uri_pattern`, as all Mongoose
* patterns, is a prefix pattern.
* current working directory. It can also be an URI (http:// or https://)
* in which case mongoose will behave as a reverse proxy for that destination.
*
* Note that `uri_pattern`, as all Mongoose patterns, is a prefix pattern.
*
* If uri_pattern starts with `@` symbol, then Mongoose compares it with the
* HOST header of the request. If they are equal, Mongoose sets document root
...
...
@@ -3249,6 +3258,7 @@ struct mg_serve_http_opts {
* automatically appended to the redirect location.
*/
const
char
*
url_rewrites
;
#endif
/* DAV document root. If NULL, DAV requests are going to fail. */
const
char
*
dav_document_root
;
...
...
@@ -3449,6 +3459,12 @@ void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...);
void
mg_send_response_line
(
struct
mg_connection
*
nc
,
int
status_code
,
const
char
*
extra_headers
);
/*
* Sends an error response. If reason is NULL, the message will be inferred
* from the error code (if supported).
*/
void
mg_http_send_error
(
struct
mg_connection
*
nc
,
int
code
,
const
char
*
reason
);
/*
* Sends a redirect response.
* `status_code` should be either 301 or 302 and `location` point to the
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment