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
3671b263
Commit
3671b263
authored
May 29, 2014
by
Daniel O'Connell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
proxy unit test reference implementation
parent
25115a69
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
163 additions
and
68 deletions
+163
-68
proxy.c
examples/proxy.c
+107
-63
index.html
examples/proxy_web_root/app1/index.html
+16
-2
index.html
examples/proxy_web_root/app2/index.html
+37
-0
index.html
examples/proxy_web_root/index.html
+3
-3
No files found.
examples/proxy.c
View file @
3671b263
...
...
@@ -6,18 +6,18 @@
// git clone https://github.com/cesanta/mongoose.git
// cd mongoose/examples
// make proxy
// ./proxy # (then point your browser at http://localhost:2014)
// ./proxy
//
// Configure your browser to use localhost:2014 as a proxy for all protocols
// Then, navigate to https://cesanta.com
#include "net_skeleton.h"
#include "mongoose.h"
static
int
s_received_signal
=
0
;
static
const
char
*
s_ca_cert
=
NULL
;
static
const
char
*
s_cert
=
NULL
;
static
const
char
*
s_sse_port
=
"2014"
;
static
const
char
*
s_proxy_port
=
"2015"
;
static
struct
mg_server
*
s_sse_server
=
NULL
;
static
struct
mg_server
*
s_proxy_server
=
NULL
;
static
struct
mg_server
*
s_server
=
NULL
;
#define SSE_CONNECTION ((void *) 1)
static
void
elog
(
int
do_exit
,
const
char
*
fmt
,
...)
{
va_list
ap
;
...
...
@@ -34,8 +34,7 @@ static void signal_handler(int sig_num) {
}
static
int
sse_push
(
struct
mg_connection
*
conn
,
enum
mg_event
ev
)
{
const
char
*
str
=
(
const
char
*
)
conn
->
connection_param
;
if
(
ev
==
MG_POLL
&&
str
!=
NULL
&&
strcmp
(
str
,
"sse"
)
==
0
)
{
if
(
ev
==
MG_POLL
&&
conn
->
connection_param
==
SSE_CONNECTION
)
{
mg_printf
(
conn
,
"data: %s
\r\n\r\n
"
,
(
const
char
*
)
conn
->
callback_param
);
}
return
MG_TRUE
;
...
...
@@ -43,57 +42,99 @@ static int sse_push(struct mg_connection *conn, enum mg_event ev) {
static
void
*
sse_pusher_thread_func
(
void
*
param
)
{
while
(
s_received_signal
==
0
)
{
mg_wakeup_server_ex
(
s_s
se_s
erver
,
sse_push
,
"%lu %s"
,
mg_wakeup_server_ex
(
s_server
,
sse_push
,
"%lu %s"
,
(
unsigned
long
)
time
(
NULL
),
(
const
char
*
)
param
);
sleep
(
1
);
}
return
NULL
;
}
static
int
sse_handler
(
struct
mg_connection
*
conn
,
enum
mg_event
ev
)
{
// Return: 1 if regular file, 2 if directory, 0 if not found
static
int
exists
(
const
char
*
path
)
{
struct
stat
st
;
return
stat
(
path
,
&
st
)
!=
0
?
0
:
S_ISDIR
(
st
.
st_mode
)
==
0
?
1
:
2
;
}
// Return: 1 if regular file, 2 if directory, 0 if not found
static
int
is_local_file
(
const
char
*
uri
,
char
*
path
,
size_t
path_len
)
{
snprintf
(
path
,
path_len
,
"%s/%s"
,
mg_get_option
(
s_server
,
"document_root"
),
uri
);
return
exists
(
path
);
}
static
int
try_to_serve_locally
(
struct
mg_connection
*
conn
)
{
char
path
[
500
],
buf
[
2000
];
int
n
,
res
;
FILE
*
fp
=
NULL
;
if
((
res
=
is_local_file
(
conn
->
uri
,
path
,
sizeof
(
path
)))
==
2
)
{
strncat
(
path
,
"/index.html"
,
sizeof
(
path
)
-
strlen
(
path
)
-
1
);
res
=
exists
(
path
);
printf
(
"PATH: [%s]
\n
"
,
path
);
#if 0
snprintf(path + strlen(path), sizeof(path) - strlen(path),
"/%s", "index.html");
#endif
}
if
(
res
==
0
)
return
MG_FALSE
;
if
((
fp
=
fopen
(
path
,
"rb"
))
!=
NULL
)
{
printf
(
"Serving [%s] locally
\n
"
,
path
);
mg_send_header
(
conn
,
"Connection"
,
"close"
);
mg_send_header
(
conn
,
"Content-Type"
,
mg_get_mime_type
(
path
,
"text/plain"
));
while
((
n
=
fread
(
buf
,
1
,
sizeof
(
buf
),
fp
))
>
0
)
{
mg_send_data
(
conn
,
buf
,
n
);
}
mg_send_data
(
conn
,
""
,
0
);
fclose
(
fp
);
}
return
fp
==
NULL
?
MG_FALSE
:
MG_TRUE
;
}
static
int
is_resource_present_locally
(
const
char
*
uri
)
{
char
path
[
500
];
return
is_local_file
(
uri
,
path
,
sizeof
(
path
))
||
strcmp
(
uri
,
"/api/sse"
)
==
0
;
}
static
int
proxy_event_handler
(
struct
mg_connection
*
conn
,
enum
mg_event
ev
)
{
static
const
char
target_url
[]
=
"http://cesanta.com"
;
static
int
target_url_size
=
sizeof
(
target_url
)
-
1
;
const
char
*
host
;
switch
(
ev
)
{
case
MG_REQUEST
:
if
(
strcmp
(
conn
->
uri
,
"/"
)
==
0
)
{
mg_printf
(
conn
,
"%s"
,
"HTTP/1.1 302 Moved
\r\n
"
"Location: /sse.html
\r\n\r\n
"
);
return
MG_TRUE
;
host
=
mg_get_header
(
conn
,
"Host"
);
printf
(
"[%s] [%s] [%s]
\n
"
,
conn
->
request_method
,
conn
->
uri
,
host
==
NULL
?
""
:
host
);
if
(
strstr
(
conn
->
uri
,
"/qqq"
)
!=
NULL
)
s_received_signal
=
SIGTERM
;
// Proxied HTTP requests have URI http://.....
// Serve requests for target_url from the local FS.
if
(
memcmp
(
conn
->
uri
,
target_url
,
target_url_size
)
==
0
&&
is_resource_present_locally
(
conn
->
uri
+
target_url_size
))
{
conn
->
uri
+=
target_url_size
;
// Leave only path in the URI
}
if
(
strcmp
(
conn
->
uri
,
"/api/sse"
)
==
0
)
{
conn
->
connection_param
=
(
void
*
)
"sse"
;
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n
"
conn
->
connection_param
=
SSE_CONNECTION
;
mg_printf
(
conn
,
"%s"
,
"HTTP/1.0 200 OK
\r\n
"
"Content-Type: text/event-stream
\r\n
"
"Cache-Control: no-cache
\r\n
"
"
\r\n
"
);
"Cache-Control: no-cache
\r\n\r\n
"
);
return
MG_MORE
;
}
if
(
host
!=
NULL
&&
strstr
(
host
,
"cesanta"
)
!=
NULL
)
{
return
try_to_serve_locally
(
conn
);
}
return
MG_FALSE
;
case
MG_AUTH
:
return
MG_TRUE
;
case
MG_POLL
:
return
MG_FALSE
;
default:
return
MG_FALSE
;
}
}
static
void
*
serve_thread_func
(
void
*
param
)
{
struct
mg_server
*
server
=
(
struct
mg_server
*
)
param
;
printf
(
"Starting on port %s
\n
"
,
mg_get_option
(
server
,
"listening_port"
));
while
(
s_received_signal
==
0
)
{
mg_poll_server
(
server
,
1000
);
}
return
NULL
;
}
static
void
show_usage_and_exit
(
const
char
*
prog
)
{
elog
(
1
,
"Usage: %s [-ca_cert FILE] [-sse_port PORT] [-proxy_port PORT]"
,
prog
);
exit
(
EXIT_FAILURE
);
}
static
void
setopt
(
struct
mg_server
*
s
,
const
char
*
opt
,
const
char
*
val
)
{
const
char
*
err_msg
=
mg_set_option
(
s
,
opt
,
val
);
if
(
err_msg
!=
NULL
)
{
...
...
@@ -102,47 +143,50 @@ static void setopt(struct mg_server *s, const char *opt, const char *val) {
}
int
main
(
int
argc
,
char
*
argv
[])
{
const
char
*
cert
=
NULL
,
*
ca_cert
=
NULL
,
*
port
=
"2014"
;
const
char
*
mitm
=
NULL
,
*
dump
=
NULL
;
int
i
;
// Parse command line options
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
if
(
strcmp
(
argv
[
i
],
"-ca_cert"
)
==
0
&&
i
+
1
<
argc
)
{
s_
ca_cert
=
argv
[
++
i
];
ca_cert
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-cert"
)
==
0
&&
i
+
1
<
argc
)
{
s_cert
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-sse_port"
)
==
0
&&
i
+
1
<
argc
)
{
s_sse_port
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-proxy_port"
)
==
0
&&
i
+
1
<
argc
)
{
s_proxy_port
=
argv
[
++
i
];
cert
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-port"
)
==
0
&&
i
+
1
<
argc
)
{
port
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-mitm"
)
==
0
&&
i
+
1
<
argc
)
{
mitm
=
argv
[
++
i
];
}
else
if
(
strcmp
(
argv
[
i
],
"-dump"
)
==
0
&&
i
+
1
<
argc
)
{
dump
=
argv
[
++
i
];
}
else
{
show_usage_and_exit
(
argv
[
0
]);
elog
(
1
,
"Usage: %s [-cert FILE] [-ca_cert FILE] [-port PORT]"
,
argv
[
0
]);
}
}
signal
(
SIGTERM
,
signal_handler
);
signal
(
SIGINT
,
signal_handler
);
// Create
, configure and start proxy server in a separate thread
s_
proxy_server
=
mg_create_server
(
NULL
,
&
sse
_handler
);
setopt
(
s_
proxy_server
,
"listening_port"
,
s_proxy_port
);
setopt
(
s_
proxy_server
,
"ssl_certificate"
,
s_ce
rt
);
setopt
(
s_
proxy_server
,
"ssl_ca_certificate"
,
s_ca_
cert
);
setopt
(
s_
proxy_server
,
"hexdump_file"
,
"/dev/stdout"
);
mg_start_thread
(
serve_thread_func
,
s_proxy_server
);
// Create, configure and start SSE server and SSE pusher threads
// Create
and configure proxy server
s_
server
=
mg_create_server
(
NULL
,
&
proxy_event
_handler
);
setopt
(
s_
server
,
"document_root"
,
"proxy_web_root"
);
setopt
(
s_
server
,
"listening_port"
,
po
rt
);
setopt
(
s_
server
,
"ssl_certificate"
,
cert
);
setopt
(
s_
server
,
"ssl_ca_certificate"
,
ca_cert
);
setopt
(
s_server
,
"hexdump_file"
,
dump
);
setopt
(
s_server
,
"ssl_mitm_certs"
,
mitm
);
// Start two SSE pushing threads
// Serve SSE server in the main thread
s_sse_server
=
mg_create_server
(
NULL
,
&
sse_handler
);
setopt
(
s_sse_server
,
"listening_port"
,
s_sse_port
);
setopt
(
s_sse_server
,
"document_root"
,
"."
);
mg_start_thread
(
sse_pusher_thread_func
,
(
void
*
)
"sse_pusher_thread_1"
);
mg_start_thread
(
sse_pusher_thread_func
,
(
void
*
)
"sse_pusher_thread_2"
);
serve_thread_func
(
s_sse_server
);
// Start serving in the main thread
printf
(
"Starting on port %s
\n
"
,
mg_get_option
(
s_server
,
"listening_port"
));
while
(
s_received_signal
==
0
)
{
mg_poll_server
(
s_server
,
1000
);
}
printf
(
"Existing on signal %d
\n
"
,
s_received_signal
);
mg_destroy_server
(
&
s_sse_server
);
mg_destroy_server
(
&
s_proxy_server
);
mg_destroy_server
(
&
s_server
);
return
EXIT_SUCCESS
;
}
examples/proxy_web_root/app1/index.html
View file @
3671b263
<html>
<head>
<title>
App1 Index
</title>
<style>
img
{
height
:
40px
;
}
</style>
</head>
<body>
<h1>
This is App1 index page
</h1>
<p>
Image below is
</p>
<h1>
App1 index page. Served locally from the the proxy server filesystem
</h1>
<p>
image that references non-existent local resource. Forwarded to
the 'real' proxy target:
</p>
<img
src=
"http://cesanta.com/images/logo.png"
/>
<p>
Google logo via HTTPS (external resource, served by remote host):
</p>
<img
src=
"https://www.google.ie/images/srpr/logo11w.png"
/>
<p>
Same image via HTTP:
</p>
<img
src=
"http://www.google.ie/images/srpr/logo11w.png"
/>
</body>
</html>
examples/proxy_web_root/app2/index.html
0 → 100644
View file @
3671b263
<html>
<head>
<title>
App2 Index
</title>
<meta
charset=
"utf-8"
>
<script>
window
.
onload
=
function
()
{
// Using secure websocket connection, wss://
var
ws
=
new
WebSocket
(
'wss://echo.websocket.org'
);
var
div
=
document
.
getElementById
(
'events'
);
ws
.
onmessage
=
function
(
ev
)
{
var
el
=
document
.
createElement
(
'div'
);
el
.
innerHTML
=
'websocket message: '
+
ev
.
data
;
div
.
appendChild
(
el
);
// Keep only last 5 messages in the list
while
(
div
.
childNodes
.
length
>
5
)
div
.
removeChild
(
div
.
firstChild
);
};
// Send random stuff to the websocket connection periodically.
// websocket server much echo that stuff back.
window
.
setInterval
(
function
()
{
var
d
=
new
Date
();
ws
.
send
(
d
.
toString
());
},
1000
);
};
</script>
</head>
<body>
<h1>
App2 index page. Served locally from the
the proxy's filesystem.
</h1>
<p>
Following div shows proxy forwarding of websocket connection, served by
ws://echo.websocket.org:
</p>
<div
id=
"events"
></div>
</body>
</html>
examples/proxy_web_root/index.html
View file @
3671b263
<html>
<head>
<title>
example.com index
</title>
<title>
proxy index
</title>
<script
type=
"text/javascript"
>
window
.
onload
=
function
()
{
var
es
=
new
EventSource
(
"/api/sse"
);
...
...
@@ -16,12 +16,12 @@
</script>
</head>
<body>
<h1>
This is an example.com
index page.
</h1>
<h1>
proxy
index page.
</h1>
<ul>
<li><a
href=
"app1"
>
App1
</a>
- App1 root
</li>
<li><a
href=
"app2"
>
App2
</a>
- App2 root
</li>
</ul>
<h2>
SSE pushes, done by separate threads at random times:
</h2>
<div
id=
"events"
></div>
...
...
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