Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
mongoose
Commits
dbb38fff
Commit
dbb38fff
authored
Mar 04, 2016
by
Alexander Alashkin
Committed by
Marko Mikulicic
Mar 04, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make (http) proto_data persistent
PUBLISHED_FROM=8210f4730a3411b3298274d792fc33da79f47b8a
parent
672a6821
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
470 additions
and
427 deletions
+470
-427
mongoose.c
mongoose.c
+467
-422
mongoose.h
mongoose.h
+3
-5
No files found.
mongoose.c
View file @
dbb38fff
...
...
@@ -2147,6 +2147,9 @@ void mg_if_poll(struct mg_connection *nc, time_t now) {
}
static
void
mg_destroy_conn
(
struct
mg_connection
*
conn
)
{
if
(
conn
->
proto_data
!=
NULL
&&
conn
->
proto_data_destructor
!=
NULL
)
{
conn
->
proto_data_destructor
(
conn
->
proto_data
);
}
mg_if_destroy_conn
(
conn
);
#ifdef MG_ENABLE_SSL
if
(
conn
->
ssl
!=
NULL
)
SSL_free
(
conn
->
ssl
);
...
...
@@ -2155,9 +2158,6 @@ static void mg_destroy_conn(struct mg_connection *conn) {
mbuf_free
(
&
conn
->
recv_mbuf
);
mbuf_free
(
&
conn
->
send_mbuf
);
mbuf_free
(
&
conn
->
endpoints
);
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
mbuf_free
(
&
conn
->
strm_state
);
#endif
memset
(
conn
,
0
,
sizeof
(
*
conn
));
MG_FREE
(
conn
);
...
...
@@ -2598,7 +2598,6 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
nc
=
mg_create_connection
(
lc
->
mgr
,
lc
->
handler
,
opts
);
if
(
nc
==
NULL
)
return
NULL
;
nc
->
listener
=
lc
;
nc
->
proto_data
=
lc
->
proto_data
;
nc
->
proto_handler
=
lc
->
proto_handler
;
nc
->
user_data
=
lc
->
user_data
;
nc
->
recv_mbuf_limit
=
lc
->
recv_mbuf_limit
;
...
...
@@ -2686,7 +2685,6 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
nc
->
sock
=
lc
->
sock
;
nc
->
listener
=
lc
;
nc
->
sa
=
*
sa
;
nc
->
proto_data
=
lc
->
proto_data
;
nc
->
proto_handler
=
lc
->
proto_handler
;
nc
->
user_data
=
lc
->
user_data
;
nc
->
recv_mbuf_limit
=
lc
->
recv_mbuf_limit
;
...
...
@@ -4161,19 +4159,82 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
/* Amalgamated: #include "common/sha1.h" */
/* Amalgamated: #include "common/md5.h" */
enum
http_proto_data_type
{
DATA_NONE
,
DATA_FILE
,
DATA_PUT
,
DATA_CGI
};
enum
mg_http_proto_data_type
{
DATA_NONE
,
DATA_FILE
,
DATA_PUT
};
struct
mg_http_proto_data_file
{
FILE
*
fp
;
/* Opened file. */
int64_t
cl
;
/* Content-Length. How many bytes to send. */
int64_t
sent
;
/* How many bytes have been already sent. */
enum
mg_http_proto_data_type
type
;
};
struct
proto_data_http
{
struct
mg_http_proto_data_cgi
{
struct
mg_connection
*
cgi_nc
;
};
struct
mg_http_proto_data_chuncked
{
int64_t
body_len
;
/* How many bytes of chunked body was reassembled. */
};
struct
mg_http_proto_data
{
#ifndef MG_DISABLE_FILESYSTEM
FILE
*
fp
;
/* Opened file. */
struct
mg_http_proto_data_file
file
;
#endif
int64_t
cl
;
/* Content-Length. How many bytes to send. */
int64_t
sent
;
/* How many bytes have been already sent. */
int64_t
body_len
;
/* How many bytes of chunked body was reassembled. */
struct
mg_connection
*
cgi_nc
;
enum
http_proto_data_type
type
;
#ifndef MG_DISABLE_CGI
struct
mg_http_proto_data_cgi
cgi
;
#endif
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
struct
mbuf
strm_state
;
/* Used by multi-part streaming */
#endif
struct
mg_http_proto_data_chuncked
chunk
;
};
static
void
mg_http_conn_destructor
(
void
*
proto_data
);
static
struct
mg_http_proto_data
*
mg_http_get_proto_data
(
struct
mg_connection
*
c
)
{
if
(
c
->
proto_data
==
NULL
)
{
c
->
proto_data
=
MG_CALLOC
(
1
,
sizeof
(
struct
mg_http_proto_data
));
c
->
proto_data_destructor
=
mg_http_conn_destructor
;
}
return
(
struct
mg_http_proto_data
*
)
c
->
proto_data
;
}
#ifndef MG_DISABLE_FILESYSTEM
static
void
mg_http_free_proto_data_file
(
struct
mg_http_proto_data_file
*
d
)
{
if
(
d
!=
NULL
)
{
if
(
d
->
fp
!=
NULL
)
{
fclose
(
d
->
fp
);
}
memset
(
d
,
0
,
sizeof
(
struct
mg_http_proto_data_file
));
}
}
#endif
#ifndef MG_DISABLE_CGI
static
void
mg_http_free_proto_data_cgi
(
struct
mg_http_proto_data_cgi
*
d
)
{
if
(
d
!=
NULL
)
{
if
(
d
->
cgi_nc
!=
NULL
)
d
->
cgi_nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
memset
(
d
,
0
,
sizeof
(
struct
mg_http_proto_data_cgi
));
}
}
#endif
static
void
mg_http_conn_destructor
(
void
*
proto_data
)
{
struct
mg_http_proto_data
*
pd
=
(
struct
mg_http_proto_data
*
)
proto_data
;
#ifndef MG_DISABLE_FILESYSTEM
mg_http_free_proto_data_file
(
&
pd
->
file
);
#endif
#ifndef MG_DISABLE_CGI
mg_http_free_proto_data_cgi
(
&
pd
->
cgi
);
#endif
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
mbuf_free
(
&
pd
->
strm_state
);
#endif
free
(
proto_data
);
}
/*
* This structure helps to create an environment for the spawned CGI program.
* Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
...
...
@@ -4184,7 +4245,7 @@ struct proto_data_http {
* We satisfy both worlds: we create an envp array (which is vars), all
* entries are actually pointers inside buf.
*/
struct
cgi_env_block
{
struct
mg_
cgi_env_block
{
struct
mg_connection
*
nc
;
char
buf
[
MG_CGI_ENVIRONMENT_SIZE
];
/* Environment buffer */
const
char
*
vars
[
MG_MAX_CGI_ENVIR_VARS
];
/* char *envp[] */
...
...
@@ -4198,7 +4259,7 @@ static const struct {
const
char
*
extension
;
size_t
ext_len
;
const
char
*
mime_type
;
}
static_builtin_mime_types
[]
=
{
}
mg_
static_builtin_mime_types
[]
=
{
MIME_ENTRY
(
"html"
,
"text/html"
),
MIME_ENTRY
(
"html"
,
"text/html"
),
MIME_ENTRY
(
"htm"
,
"text/html"
),
...
...
@@ -4262,8 +4323,8 @@ static int mg_mkdir(const char *path, uint32_t mode) {
}
#endif
static
struct
mg_str
get_mime_type
(
const
char
*
path
,
const
char
*
dflt
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
struct
mg_str
mg_
get_mime_type
(
const
char
*
path
,
const
char
*
dflt
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
ext
,
*
overrides
;
size_t
i
,
path_len
;
struct
mg_str
r
,
k
,
v
;
...
...
@@ -4278,11 +4339,11 @@ static struct mg_str get_mime_type(const char *path, const char *dflt,
}
}
for
(
i
=
0
;
static_builtin_mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
ext
=
path
+
(
path_len
-
static_builtin_mime_types
[
i
].
ext_len
);
if
(
path_len
>
static_builtin_mime_types
[
i
].
ext_len
&&
ext
[
-
1
]
==
'.'
&&
mg_casecmp
(
ext
,
static_builtin_mime_types
[
i
].
extension
)
==
0
)
{
r
.
p
=
static_builtin_mime_types
[
i
].
mime_type
;
for
(
i
=
0
;
mg_
static_builtin_mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
ext
=
path
+
(
path_len
-
mg_
static_builtin_mime_types
[
i
].
ext_len
);
if
(
path_len
>
mg_
static_builtin_mime_types
[
i
].
ext_len
&&
ext
[
-
1
]
==
'.'
&&
mg_casecmp
(
ext
,
mg_
static_builtin_mime_types
[
i
].
extension
)
==
0
)
{
r
.
p
=
mg_
static_builtin_mime_types
[
i
].
mime_type
;
r
.
len
=
strlen
(
r
.
p
);
return
r
;
}
...
...
@@ -4300,7 +4361,7 @@ static struct mg_str get_mime_type(const char *path, const char *dflt,
* 0 if request is not yet fully buffered
* >0 actual request length, including last \r\n\r\n
*/
static
int
get_request_len
(
const
char
*
s
,
int
buf_len
)
{
static
int
mg_http_
get_request_len
(
const
char
*
s
,
int
buf_len
)
{
const
unsigned
char
*
buf
=
(
unsigned
char
*
)
s
;
int
i
;
...
...
@@ -4318,8 +4379,8 @@ static int get_request_len(const char *s, int buf_len) {
return
0
;
}
static
const
char
*
parse_http_headers
(
const
char
*
s
,
const
char
*
end
,
int
len
,
struct
http_message
*
req
)
{
static
const
char
*
mg_http_parse_headers
(
const
char
*
s
,
const
char
*
end
,
int
len
,
struct
http_message
*
req
)
{
int
i
;
for
(
i
=
0
;
i
<
(
int
)
ARRAY_SIZE
(
req
->
header_names
)
-
1
;
i
++
)
{
struct
mg_str
*
k
=
&
req
->
header_names
[
i
],
*
v
=
&
req
->
header_values
[
i
];
...
...
@@ -4348,7 +4409,7 @@ static const char *parse_http_headers(const char *s, const char *end, int len,
int
mg_parse_http
(
const
char
*
s
,
int
n
,
struct
http_message
*
hm
,
int
is_req
)
{
const
char
*
end
,
*
qs
;
int
len
=
get_request_len
(
s
,
n
);
int
len
=
mg_http_
get_request_len
(
s
,
n
);
if
(
len
<=
0
)
return
len
;
...
...
@@ -4383,7 +4444,7 @@ int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
s
=
mg_skip
(
s
,
end
,
"
\r\n
"
,
&
hm
->
resp_status_msg
);
}
s
=
parse_http
_headers
(
s
,
end
,
len
,
hm
);
s
=
mg_http_parse
_headers
(
s
,
end
,
len
,
hm
);
/*
* mg_parse_http() is used to parse both HTTP requests and HTTP
...
...
@@ -4424,16 +4485,16 @@ struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
#ifndef MG_DISABLE_HTTP_WEBSOCKET
static
int
is_ws_fragment
(
unsigned
char
flags
)
{
static
int
mg_
is_ws_fragment
(
unsigned
char
flags
)
{
return
(
flags
&
0x80
)
==
0
||
(
flags
&
0x0f
)
==
0
;
}
static
int
is_ws_first_fragment
(
unsigned
char
flags
)
{
static
int
mg_
is_ws_first_fragment
(
unsigned
char
flags
)
{
return
(
flags
&
0x80
)
==
0
&&
(
flags
&
0x0f
)
!=
0
;
}
static
void
handle_incoming_websocket_frame
(
struct
mg_connection
*
nc
,
struct
websocket_message
*
wsm
)
{
static
void
mg_
handle_incoming_websocket_frame
(
struct
mg_connection
*
nc
,
struct
websocket_message
*
wsm
)
{
if
(
wsm
->
flags
&
0x8
)
{
mg_call
(
nc
,
nc
->
handler
,
MG_EV_WEBSOCKET_CONTROL_FRAME
,
wsm
);
}
else
{
...
...
@@ -4441,19 +4502,19 @@ static void handle_incoming_websocket_frame(struct mg_connection *nc,
}
}
static
int
deliver_websocket_data
(
struct
mg_connection
*
nc
)
{
static
int
mg_
deliver_websocket_data
(
struct
mg_connection
*
nc
)
{
/* Using unsigned char *, cause of integer arithmetic below */
uint64_t
i
,
data_len
=
0
,
frame_len
=
0
,
buf_len
=
nc
->
recv_mbuf
.
len
,
len
,
mask_len
=
0
,
header_len
=
0
;
unsigned
char
*
p
=
(
unsigned
char
*
)
nc
->
recv_mbuf
.
buf
,
*
buf
=
p
,
*
e
=
p
+
buf_len
;
unsigned
*
sizep
=
(
unsigned
*
)
&
p
[
1
];
/* Size ptr for defragmented frames */
int
ok
,
reass
=
buf_len
>
0
&&
is_ws_fragment
(
p
[
0
])
&&
int
ok
,
reass
=
buf_len
>
0
&&
mg_
is_ws_fragment
(
p
[
0
])
&&
!
(
nc
->
flags
&
MG_F_WEBSOCKET_NO_DEFRAG
);
/* If that's a continuation frame that must be reassembled, handle it */
if
(
reass
&&
!
is_ws_first_fragment
(
p
[
0
])
&&
buf_len
>=
1
+
sizeof
(
*
sizep
)
&&
buf_len
>=
1
+
sizeof
(
*
sizep
)
+
*
sizep
)
{
if
(
reass
&&
!
mg_is_ws_first_fragment
(
p
[
0
]
)
&&
buf_len
>=
1
+
sizeof
(
*
sizep
)
&&
buf_len
>=
1
+
sizeof
(
*
sizep
)
+
*
sizep
)
{
buf
+=
1
+
sizeof
(
*
sizep
)
+
*
sizep
;
buf_len
-=
1
+
sizeof
(
*
sizep
)
+
*
sizep
;
}
...
...
@@ -4493,7 +4554,7 @@ static int deliver_websocket_data(struct mg_connection *nc) {
if
(
reass
)
{
/* On first fragmented frame, nullify size */
if
(
is_ws_first_fragment
(
wsm
.
flags
))
{
if
(
mg_
is_ws_first_fragment
(
wsm
.
flags
))
{
mbuf_resize
(
&
nc
->
recv_mbuf
,
nc
->
recv_mbuf
.
size
+
sizeof
(
*
sizep
));
p
[
0
]
&=
~
0x0f
;
/* Next frames will be treated as continuation */
buf
=
p
+
1
+
sizeof
(
*
sizep
);
...
...
@@ -4509,12 +4570,12 @@ static int deliver_websocket_data(struct mg_connection *nc) {
if
(
wsm
.
flags
&
0x80
)
{
wsm
.
data
=
p
+
1
+
sizeof
(
*
sizep
);
wsm
.
size
=
*
sizep
;
handle_incoming_websocket_frame
(
nc
,
&
wsm
);
mg_
handle_incoming_websocket_frame
(
nc
,
&
wsm
);
mbuf_remove
(
&
nc
->
recv_mbuf
,
1
+
sizeof
(
*
sizep
)
+
*
sizep
);
}
}
else
{
/* TODO(lsm): properly handle OOB control frames during defragmentation */
handle_incoming_websocket_frame
(
nc
,
&
wsm
);
mg_
handle_incoming_websocket_frame
(
nc
,
&
wsm
);
mbuf_remove
(
&
nc
->
recv_mbuf
,
(
size_t
)
frame_len
);
/* Cleanup frame */
}
...
...
@@ -4532,7 +4593,7 @@ struct ws_mask_ctx {
uint32_t
mask
;
};
static
uint32_t
ws_random_mask
(
void
)
{
static
uint32_t
mg_
ws_random_mask
(
void
)
{
/*
* The spec requires WS client to generate hard to
* guess mask keys. From RFC6455, Section 5.3:
...
...
@@ -4586,7 +4647,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
if
(
nc
->
listener
==
NULL
)
{
header
[
1
]
|=
1
<<
7
;
/* set masking flag */
mg_send
(
nc
,
header
,
header_len
);
ctx
->
mask
=
ws_random_mask
();
ctx
->
mask
=
mg_
ws_random_mask
();
mg_send
(
nc
,
&
ctx
->
mask
,
sizeof
(
ctx
->
mask
));
ctx
->
pos
=
nc
->
send_mbuf
.
len
;
}
else
{
...
...
@@ -4595,7 +4656,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
}
}
static
void
ws_mask_frame
(
struct
mbuf
*
mbuf
,
struct
ws_mask_ctx
*
ctx
)
{
static
void
mg_
ws_mask_frame
(
struct
mbuf
*
mbuf
,
struct
ws_mask_ctx
*
ctx
)
{
size_t
i
;
if
(
ctx
->
pos
==
0
)
return
;
for
(
i
=
0
;
i
<
(
mbuf
->
len
-
ctx
->
pos
);
i
++
)
{
...
...
@@ -4609,7 +4670,7 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
mg_send_ws_header
(
nc
,
op
,
len
,
&
ctx
);
mg_send
(
nc
,
data
,
len
);
ws_mask_frame
(
&
nc
->
send_mbuf
,
&
ctx
);
mg_
ws_mask_frame
(
&
nc
->
send_mbuf
,
&
ctx
);
if
(
op
==
WEBSOCKET_OP_CLOSE
)
{
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
...
...
@@ -4631,7 +4692,7 @@ void mg_send_websocket_framev(struct mg_connection *nc, int op,
mg_send
(
nc
,
strv
[
i
].
p
,
strv
[
i
].
len
);
}
ws_mask_frame
(
&
nc
->
send_mbuf
,
&
ctx
);
mg_
ws_mask_frame
(
&
nc
->
send_mbuf
,
&
ctx
);
if
(
op
==
WEBSOCKET_OP_CLOSE
)
{
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
...
...
@@ -4655,13 +4716,14 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op,
}
}
static
void
websocket_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
static
void
mg_websocket_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
mg_call
(
nc
,
nc
->
handler
,
ev
,
ev_data
);
switch
(
ev
)
{
case
MG_EV_RECV
:
do
{
}
while
(
deliver_websocket_data
(
nc
));
}
while
(
mg_
deliver_websocket_data
(
nc
));
break
;
case
MG_EV_POLL
:
/* Ping idle websocket connections */
...
...
@@ -4678,7 +4740,8 @@ static void websocket_handler(struct mg_connection *nc, int ev, void *ev_data) {
}
}
static
void
ws_handshake
(
struct
mg_connection
*
nc
,
const
struct
mg_str
*
key
)
{
static
void
mg_ws_handshake
(
struct
mg_connection
*
nc
,
const
struct
mg_str
*
key
)
{
static
const
char
*
magic
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
;
char
buf
[
MG_VPRINTF_BUFFER_SIZE
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
cs_sha1_ctx
sha_ctx
;
...
...
@@ -4700,28 +4763,14 @@ static void ws_handshake(struct mg_connection *nc, const struct mg_str *key) {
#endif
/* MG_DISABLE_HTTP_WEBSOCKET */
static
void
free_http_proto_data
(
struct
mg_connection
*
nc
)
{
struct
proto_data_http
*
dp
=
(
struct
proto_data_http
*
)
nc
->
proto_data
;
if
(
dp
!=
NULL
)
{
#ifndef MG_DISABLE_FILESYSTEM
if
(
dp
->
fp
!=
NULL
)
fclose
(
dp
->
fp
);
#endif
#ifndef MG_DISABLE_CGI
if
(
dp
->
cgi_nc
!=
NULL
)
dp
->
cgi_nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
#endif
MG_FREE
(
dp
);
nc
->
proto_data
=
NULL
;
}
}
#ifndef MG_DISABLE_FILESYSTEM
static
void
transfer_file_data
(
struct
mg_connection
*
nc
)
{
struct
proto_data_http
*
dp
=
(
struct
proto_data_http
*
)
nc
->
proto_data
;
static
void
mg_http_transfer_file_data
(
struct
mg_connection
*
nc
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
char
buf
[
MG_MAX_HTTP_SEND_MBUF
];
int64_t
left
=
dp
->
cl
-
dp
->
sent
;
int64_t
left
=
pd
->
file
.
cl
-
pd
->
file
.
sent
;
size_t
n
=
0
,
to_read
=
0
;
if
(
dp
->
type
==
DATA_FILE
)
{
if
(
pd
->
file
.
type
==
DATA_FILE
)
{
struct
mbuf
*
io
=
&
nc
->
send_mbuf
;
if
(
io
->
len
<
sizeof
(
buf
))
{
to_read
=
sizeof
(
buf
)
-
io
->
len
;
...
...
@@ -4733,38 +4782,42 @@ static void transfer_file_data(struct mg_connection *nc) {
if
(
to_read
==
0
)
{
/* Rate limiting. send_mbuf is too full, wait until it's drained. */
}
else
if
(
dp
->
sent
<
dp
->
cl
&&
(
n
=
fread
(
buf
,
1
,
to_read
,
dp
->
fp
))
>
0
)
{
}
else
if
(
pd
->
file
.
sent
<
pd
->
file
.
cl
&&
(
n
=
fread
(
buf
,
1
,
to_read
,
pd
->
file
.
fp
))
>
0
)
{
mg_send
(
nc
,
buf
,
n
);
dp
->
sent
+=
n
;
pd
->
file
.
sent
+=
n
;
}
else
{
free_http_proto_data
(
nc
);
mg_http_free_proto_data_file
(
&
pd
->
file
);
#ifdef MG_DISABLE_HTTP_KEEP_ALIVE
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
#endif
}
}
else
if
(
dp
->
type
==
DATA_PUT
)
{
}
else
if
(
pd
->
file
.
type
==
DATA_PUT
)
{
struct
mbuf
*
io
=
&
nc
->
recv_mbuf
;
size_t
to_write
=
left
<=
0
?
0
:
left
<
(
int64_t
)
io
->
len
?
(
size_t
)
left
:
io
->
len
;
size_t
n
=
fwrite
(
io
->
buf
,
1
,
to_write
,
dp
->
fp
);
size_t
n
=
fwrite
(
io
->
buf
,
1
,
to_write
,
pd
->
file
.
fp
);
if
(
n
>
0
)
{
mbuf_remove
(
io
,
n
);
dp
->
sent
+=
n
;
pd
->
file
.
sent
+=
n
;
}
if
(
n
==
0
||
dp
->
sent
>=
dp
->
cl
)
{
free_http_proto_data
(
nc
);
if
(
n
==
0
||
pd
->
file
.
sent
>=
pd
->
file
.
cl
)
{
mg_http_free_proto_data_file
(
&
pd
->
file
);
#ifdef MG_DISABLE_HTTP_KEEP_ALIVE
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
#endif
}
}
else
if
(
dp
->
type
==
DATA_CGI
)
{
}
#ifndef MG_DISABLE_CGI
else
if
(
pd
->
cgi
.
cgi_nc
!=
NULL
)
{
/* This is POST data that needs to be forwarded to the CGI process */
if
(
dp
->
cgi_nc
!=
NULL
)
{
mg_forward
(
nc
,
dp
->
cgi_nc
);
if
(
pd
->
cgi
.
cgi_nc
!=
NULL
)
{
mg_forward
(
nc
,
pd
->
cgi
.
cgi_nc
);
}
else
{
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
}
#endif
}
#endif
/* MG_DISABLE_FILESYSTEM */
...
...
@@ -4773,8 +4826,8 @@ static void transfer_file_data(struct mg_connection *nc) {
* if it's incomplete. If the chunk is fully buffered, return total number of
* bytes in a chunk, and store data in `data`, `data_len`.
*/
static
size_t
parse_chunk
(
char
*
buf
,
size_t
len
,
char
**
chunk_data
,
size_t
*
chunk_len
)
{
static
size_t
mg_http_
parse_chunk
(
char
*
buf
,
size_t
len
,
char
**
chunk_data
,
size_t
*
chunk_len
)
{
unsigned
char
*
s
=
(
unsigned
char
*
)
buf
;
size_t
n
=
0
;
/* scanned chunk length */
size_t
i
=
0
;
/* index in s */
...
...
@@ -4809,24 +4862,17 @@ static size_t parse_chunk(char *buf, size_t len, char **chunk_data,
MG_INTERNAL
size_t
mg_handle_chunked
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
char
*
buf
,
size_t
blen
)
{
struct
proto_data_http
*
dp
;
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
)
;
char
*
data
;
size_t
i
,
n
,
data_len
,
body_len
,
zero_chunk_received
=
0
;
/* If not allocated, allocate proto_data to hold reassembled offset */
if
(
nc
->
proto_data
==
NULL
&&
(
nc
->
proto_data
=
MG_CALLOC
(
1
,
sizeof
(
*
dp
)))
==
NULL
)
{
nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
return
0
;
}
/* Find out piece of received data that is not yet reassembled */
dp
=
(
struct
proto_data_http
*
)
nc
->
proto_data
;
body_len
=
dp
->
body_len
;
body_len
=
pd
->
chunk
.
body_len
;
assert
(
blen
>=
body_len
);
/* Traverse all fully buffered chunks */
for
(
i
=
body_len
;
(
n
=
parse_chunk
(
buf
+
i
,
blen
-
i
,
&
data
,
&
data_len
))
>
0
;
for
(
i
=
body_len
;
(
n
=
mg_http_parse_chunk
(
buf
+
i
,
blen
-
i
,
&
data
,
&
data_len
))
>
0
;
i
+=
n
)
{
/* Collapse chunk data to the rest of HTTP body */
memmove
(
buf
+
body_len
,
data
,
data_len
);
...
...
@@ -4846,7 +4892,7 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
memmove
(
buf
+
body_len
,
buf
+
i
,
blen
-
i
);
memset
(
buf
+
body_len
+
blen
-
i
,
0
,
i
-
body_len
);
nc
->
recv_mbuf
.
len
-=
i
-
body_len
;
dp
->
body_len
=
body_len
;
pd
->
chunk
.
body_len
=
body_len
;
/* Send MG_EV_HTTP_CHUNK event */
nc
->
flags
&=
~
MG_F_DELETE_CHUNK
;
...
...
@@ -4857,19 +4903,19 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
memset
(
buf
,
0
,
body_len
);
memmove
(
buf
,
buf
+
body_len
,
blen
-
i
);
nc
->
recv_mbuf
.
len
-=
body_len
;
hm
->
body
.
len
=
dp
->
body_len
=
0
;
hm
->
body
.
len
=
pd
->
chunk
.
body_len
=
0
;
}
if
(
zero_chunk_received
)
{
hm
->
message
.
len
=
dp
->
body_len
+
blen
-
i
;
hm
->
message
.
len
=
pd
->
chunk
.
body_len
+
blen
-
i
;
}
}
return
body_len
;
}
static
mg_event_handler_t
get_endpoint_handler
(
struct
mg_connection
*
nc
,
struct
mg_str
*
uri_path
)
{
static
mg_event_handler_t
mg_http_get_endpoint_handler
(
struct
mg_connection
*
nc
,
struct
mg_str
*
uri_path
)
{
size_t
pos
=
0
;
mg_event_handler_t
ret
=
NULL
;
int
matched
,
matched_max
=
0
;
...
...
@@ -4900,7 +4946,7 @@ static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc,
}
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
struct
stream_info
{
struct
mg_http_
stream_info
{
struct
mg_str
endpoint
;
struct
mg_str
boundary
;
struct
mg_str
var_name
;
...
...
@@ -4914,7 +4960,8 @@ struct stream_info {
* related data these function can be replaced with usual structs
* TODO(alashkin): replace once those way will be implemented
*/
static
void
mg_parse_stream_info
(
struct
mbuf
*
buf
,
struct
stream_info
*
si
)
{
static
void
mg_http_parse_stream_info
(
struct
mbuf
*
buf
,
struct
mg_http_stream_info
*
si
)
{
const
char
*
ptr
=
buf
->
buf
;
memcpy
(
&
si
->
endpoint
.
len
,
ptr
,
sizeof
(
si
->
endpoint
.
len
));
ptr
+=
sizeof
(
si
->
endpoint
.
len
);
...
...
@@ -4934,7 +4981,8 @@ static void mg_parse_stream_info(struct mbuf *buf, struct stream_info *si) {
ptr
+=
si
->
file_name
.
len
+
1
;
}
static
void
mg_store_stream_info
(
struct
mbuf
*
buf
,
struct
stream_info
*
si
)
{
static
void
mg_http_store_stream_info
(
struct
mbuf
*
buf
,
struct
mg_http_stream_info
*
si
)
{
char
zero
=
0
;
mbuf_remove
(
buf
,
buf
->
len
);
mbuf_append
(
buf
,
&
si
->
endpoint
.
len
,
sizeof
(
si
->
endpoint
.
len
));
...
...
@@ -4951,21 +4999,22 @@ static void mg_store_stream_info(struct mbuf *buf, struct stream_info *si) {
}
#endif
/* MG_ENABLE_HTTP_STREAMING_MULTIPART */
static
void
mg_call_endpoint_handler
(
struct
mg_connection
*
nc
,
int
ev
,
struct
http_message
*
hm
)
{
static
void
mg_
http_
call_endpoint_handler
(
struct
mg_connection
*
nc
,
int
ev
,
struct
http_message
*
hm
)
{
mg_event_handler_t
uri_handler
=
ev
==
MG_EV_HTTP_REQUEST
?
get_endpoint_handler
(
nc
->
listener
,
&
hm
->
uri
)
:
NULL
;
ev
==
MG_EV_HTTP_REQUEST
?
mg_http_get_endpoint_handler
(
nc
->
listener
,
&
hm
->
uri
)
:
NULL
;
mg_call
(
nc
,
uri_handler
?
uri_handler
:
nc
->
handler
,
ev
,
hm
);
}
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
static
void
mg_
multipart_continue
(
struct
mg_connection
*
nc
,
struct
mbuf
*
io
,
int
ev
,
void
*
ev_data
);
static
void
mg_
http_multipart_continue
(
struct
mg_connection
*
nc
,
struct
mbuf
*
io
,
int
ev
,
void
*
ev_data
);
static
void
mg_multipart_begin
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
struct
mbuf
*
io
,
int
req_len
);
static
void
mg_
http_
multipart_begin
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
struct
mbuf
*
io
,
int
req_len
);
#endif
...
...
@@ -4975,21 +5024,22 @@ static void mg_multipart_begin(struct mg_connection *nc,
* even bigger (round up to 4k, from 700 bytes of actual size).
*/
#ifdef __xtensa__
static
void
http_handler2
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
,
struct
http_message
*
hm
)
__attribute__
((
noinline
));
static
void
mg_
http_handler2
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
,
struct
http_message
*
hm
)
__attribute__
((
noinline
));
void
http_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
void
mg_
http_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
struct
http_message
hm
;
http_handler2
(
nc
,
ev
,
ev_data
,
&
hm
);
mg_
http_handler2
(
nc
,
ev
,
ev_data
,
&
hm
);
}
static
void
http_handler2
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
,
struct
http_message
*
hm
)
{
static
void
mg_
http_handler2
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
,
struct
http_message
*
hm
)
{
#else
/* !__XTENSA__ */
void
http_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
void
mg_
http_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
ev_data
)
{
struct
http_message
shm
;
struct
http_message
*
hm
=
&
shm
;
#endif
/* __XTENSA__ */
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
struct
mbuf
*
io
=
&
nc
->
recv_mbuf
;
int
req_len
;
const
int
is_req
=
(
nc
->
listener
!=
NULL
);
...
...
@@ -5005,14 +5055,13 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
int
ev2
=
is_req
?
MG_EV_HTTP_REQUEST
:
MG_EV_HTTP_REPLY
;
hm
->
message
.
len
=
io
->
len
;
hm
->
body
.
len
=
io
->
buf
+
io
->
len
-
hm
->
body
.
p
;
mg_call_endpoint_handler
(
nc
,
ev2
,
hm
);
mg_
http_
call_endpoint_handler
(
nc
,
ev2
,
hm
);
}
free_http_proto_data
(
nc
);
}
#ifndef MG_DISABLE_FILESYSTEM
if
(
nc
->
proto_data
!=
NULL
)
{
transfer_file_data
(
nc
);
if
(
pd
->
file
.
fp
!=
NULL
)
{
mg_http_
transfer_file_data
(
nc
);
}
#endif
...
...
@@ -5022,8 +5071,8 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct
mg_str
*
s
;
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
if
(
nc
->
strm_state
.
len
!=
0
)
{
mg_multipart_continue
(
nc
,
io
,
ev
,
ev_data
);
if
(
pd
->
strm_state
.
len
!=
0
)
{
mg_
http_
multipart_continue
(
nc
,
io
,
ev
,
ev_data
);
return
;
}
#endif
/* MG_ENABLE_HTTP_STREAMING_MULTIPART */
...
...
@@ -5050,25 +5099,25 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
/* We're websocket client, got handshake response from server. */
/* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
mbuf_remove
(
io
,
req_len
);
nc
->
proto_handler
=
websocket_handler
;
nc
->
proto_handler
=
mg_
websocket_handler
;
nc
->
flags
|=
MG_F_IS_WEBSOCKET
;
mg_call
(
nc
,
nc
->
handler
,
MG_EV_WEBSOCKET_HANDSHAKE_DONE
,
NULL
);
websocket_handler
(
nc
,
MG_EV_RECV
,
ev_data
);
mg_
websocket_handler
(
nc
,
MG_EV_RECV
,
ev_data
);
}
else
if
(
nc
->
listener
!=
NULL
&&
(
vec
=
mg_get_http_header
(
hm
,
"Sec-WebSocket-Key"
))
!=
NULL
)
{
/* This is a websocket request. Switch protocol handlers. */
mbuf_remove
(
io
,
req_len
);
nc
->
proto_handler
=
websocket_handler
;
nc
->
proto_handler
=
mg_
websocket_handler
;
nc
->
flags
|=
MG_F_IS_WEBSOCKET
;
/* Send handshake */
mg_call
(
nc
,
nc
->
handler
,
MG_EV_WEBSOCKET_HANDSHAKE_REQUEST
,
hm
);
if
(
!
(
nc
->
flags
&
MG_F_CLOSE_IMMEDIATELY
))
{
if
(
nc
->
send_mbuf
.
len
==
0
)
{
ws_handshake
(
nc
,
vec
);
mg_
ws_handshake
(
nc
,
vec
);
}
mg_call
(
nc
,
nc
->
handler
,
MG_EV_WEBSOCKET_HANDSHAKE_DONE
,
NULL
);
websocket_handler
(
nc
,
MG_EV_RECV
,
ev_data
);
mg_
websocket_handler
(
nc
,
MG_EV_RECV
,
ev_data
);
}
#endif
/* MG_DISABLE_HTTP_WEBSOCKET */
}
else
if
(
hm
->
message
.
len
<=
io
->
len
)
{
...
...
@@ -5119,29 +5168,30 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
if
(
js_callback_handled_request
)
{
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
else
{
mg_call_endpoint_handler
(
nc
,
trigger_ev
,
hm
);
mg_
http_
call_endpoint_handler
(
nc
,
trigger_ev
,
hm
);
}
#else
mg_call_endpoint_handler
(
nc
,
trigger_ev
,
hm
);
mg_
http_
call_endpoint_handler
(
nc
,
trigger_ev
,
hm
);
#endif
mbuf_remove
(
io
,
hm
->
message
.
len
);
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
}
else
{
mg_multipart_begin
(
nc
,
hm
,
io
,
req_len
);
mg_
http_
multipart_begin
(
nc
,
hm
,
io
,
req_len
);
#endif
/* MG_ENABLE_HTTP_STREAMING_MULTIPART */
}
}
}
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
static
void
mg_multipart_begin
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
struct
mbuf
*
io
,
int
req_len
)
{
static
void
mg_http_multipart_begin
(
struct
mg_connection
*
nc
,
struct
http_message
*
hm
,
struct
mbuf
*
io
,
int
req_len
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
struct
mg_str
*
ct
;
const
char
multipart
[]
=
"multipart"
;
char
boundary
[
100
];
int
boundary_len
;
struct
stream_info
si
;
struct
mg_http_
stream_info
si
;
mg_event_handler_t
handler
;
if
(
nc
->
listener
==
NULL
)
{
...
...
@@ -5176,13 +5226,13 @@ static void mg_multipart_begin(struct mg_connection *nc,
/* If we reach this place - that is multipart request */
if
(
nc
->
strm_state
.
len
!=
0
)
{
if
(
pd
->
strm_state
.
len
!=
0
)
{
/*
* Another streaming request was in progress,
* looks like protocol error
*/
nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
mbuf_free
(
&
nc
->
strm_state
);
mbuf_free
(
&
pd
->
strm_state
);
}
else
{
si
.
endpoint
=
hm
->
uri
;
si
.
boundary
.
p
=
boundary
;
...
...
@@ -5190,8 +5240,8 @@ static void mg_multipart_begin(struct mg_connection *nc,
si
.
var_name
.
p
=
si
.
file_name
.
p
=
NULL
;
si
.
var_name
.
len
=
si
.
file_name
.
len
=
0
;
mg_
store_stream_info
(
&
nc
->
strm_state
,
&
si
);
handler
=
get_endpoint_handler
(
nc
->
listener
,
&
si
.
endpoint
);
mg_
http_store_stream_info
(
&
pd
->
strm_state
,
&
si
);
handler
=
mg_http_
get_endpoint_handler
(
nc
->
listener
,
&
si
.
endpoint
);
mg_call
(
nc
,
handler
?
handler
:
nc
->
handler
,
MG_EV_HTTP_MULTIPART_REQUEST
,
hm
);
...
...
@@ -5201,17 +5251,18 @@ exit_mp:
;
}
static
void
mg_
multipart_continue
(
struct
mg_connection
*
nc
,
struct
mbuf
*
io
,
int
ev
,
void
*
ev_data
)
{
static
void
mg_
http_multipart_continue
(
struct
mg_connection
*
nc
,
struct
mbuf
*
io
,
int
ev
,
void
*
ev_data
)
{
/* Continue to stream multipart */
struct
stream_info
si
;
struct
mg_http_
stream_info
si
;
mg_event_handler_t
handler
;
struct
mg_http_multipart_part
mp
;
const
char
*
boundary
;
int
req_len
;
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
mg_
parse_stream_info
(
&
nc
->
strm_state
,
&
si
);
handler
=
get_endpoint_handler
(
nc
->
listener
,
&
si
.
endpoint
);
mg_
http_parse_stream_info
(
&
pd
->
strm_state
,
&
si
);
handler
=
mg_http_
get_endpoint_handler
(
nc
->
listener
,
&
si
.
endpoint
);
memset
(
&
mp
,
0
,
sizeof
(
mp
));
mp
.
var_name
=
si
.
var_name
.
p
;
...
...
@@ -5250,7 +5301,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
sizeof
(
filename
),
&
data
,
&
data_len
);
mp
.
var_name
=
varname
;
mp
.
file_name
=
filename
;
if
((
req_len
=
get_request_len
(
io
->
buf
,
io
->
len
))
>
0
)
{
if
((
req_len
=
mg_http_
get_request_len
(
io
->
buf
,
io
->
len
))
>
0
)
{
const
char
*
tmp
;
mg_call
(
nc
,
handler
?
handler
:
nc
->
handler
,
MG_EV_HTTP_PART_BEGIN
,
&
mp
);
...
...
@@ -5258,7 +5309,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
si
.
var_name
.
len
=
strlen
(
mp
.
var_name
);
si
.
file_name
.
p
=
mp
.
file_name
;
si
.
file_name
.
len
=
strlen
(
mp
.
file_name
);
mg_
store_stream_info
(
&
nc
->
strm_state
,
&
si
);
mg_
http_store_stream_info
(
&
pd
->
strm_state
,
&
si
);
mbuf_remove
(
io
,
req_len
);
mp
.
data
.
p
=
io
->
buf
;
...
...
@@ -5283,7 +5334,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
}
if
(
io
->
len
!=
0
)
{
http_handler
(
nc
,
ev
,
ev_data
);
mg_
http_handler
(
nc
,
ev
,
ev_data
);
}
}
/* else wait for data */
}
else
if
(
has_prefix
&&
has_suffix
)
{
...
...
@@ -5298,7 +5349,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
/* Skip epilogue (if any) */
mbuf_remove
(
io
,
io
->
len
);
mbuf_free
(
&
nc
->
strm_state
);
mbuf_free
(
&
pd
->
strm_state
);
}
else
{
/* Malformed request */
nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
...
...
@@ -5309,7 +5360,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
#endif
/* MG_ENABLE_HTTP_STREAMING_MULTIPART */
void
mg_set_protocol_http_websocket
(
struct
mg_connection
*
nc
)
{
nc
->
proto_handler
=
http_handler
;
nc
->
proto_handler
=
mg_
http_handler
;
}
#ifndef MG_DISABLE_HTTP_WEBSOCKET
...
...
@@ -5384,16 +5435,16 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
mg_send_head
(
nc
,
501
,
0
,
NULL
);
}
#else
static
void
send_http_error
(
struct
mg_connection
*
nc
,
int
code
,
const
char
*
reason
)
{
static
void
mg_http_
send_http_error
(
struct
mg_connection
*
nc
,
int
code
,
const
char
*
reason
)
{
(
void
)
reason
;
mg_send_head
(
nc
,
code
,
0
,
NULL
);
}
#ifndef MG_DISABLE_SSI
static
void
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
FILE
*
,
int
,
const
struct
mg_serve_http_opts
*
);
static
void
mg_
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
FILE
*
,
int
,
const
struct
mg_serve_http_opts
*
);
static
void
send_file_data
(
struct
mg_connection
*
nc
,
FILE
*
fp
)
{
static
void
mg_
send_file_data
(
struct
mg_connection
*
nc
,
FILE
*
fp
)
{
char
buf
[
BUFSIZ
];
size_t
n
;
while
((
n
=
fread
(
buf
,
1
,
sizeof
(
buf
),
fp
))
>
0
)
{
...
...
@@ -5401,9 +5452,9 @@ static void send_file_data(struct mg_connection *nc, FILE *fp) {
}
}
static
void
do_ssi_include
(
struct
mg_connection
*
nc
,
const
char
*
ssi
,
char
*
tag
,
int
include_level
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_do_ssi_include
(
struct
mg_connection
*
nc
,
const
char
*
ssi
,
char
*
tag
,
int
include_level
,
const
struct
mg_serve_http_opts
*
opts
)
{
char
file_name
[
BUFSIZ
],
path
[
MAX_PATH_SIZE
],
*
p
;
FILE
*
fp
;
...
...
@@ -5439,9 +5490,9 @@ static void do_ssi_include(struct mg_connection *nc, const char *ssi, char *tag,
mg_set_close_on_exec
(
fileno
(
fp
));
if
(
mg_match_prefix
(
opts
->
ssi_pattern
,
strlen
(
opts
->
ssi_pattern
),
path
)
>
0
)
{
send_ssi_file
(
nc
,
path
,
fp
,
include_level
+
1
,
opts
);
mg_
send_ssi_file
(
nc
,
path
,
fp
,
include_level
+
1
,
opts
);
}
else
{
send_file_data
(
nc
,
fp
);
mg_
send_file_data
(
nc
,
fp
);
}
fclose
(
fp
);
}
...
...
@@ -5457,13 +5508,13 @@ static void do_ssi_exec(struct mg_connection *nc, char *tag) {
}
else
if
((
fp
=
popen
(
cmd
,
"r"
))
==
NULL
)
{
mg_printf
(
nc
,
"Cannot SSI #exec: [%s]: %s"
,
cmd
,
strerror
(
errno
));
}
else
{
send_file_data
(
nc
,
fp
);
mg_
send_file_data
(
nc
,
fp
);
pclose
(
fp
);
}
}
#endif
/* !MG_DISABLE_POPEN */
static
void
do_ssi_call
(
struct
mg_connection
*
nc
,
char
*
tag
)
{
static
void
mg_
do_ssi_call
(
struct
mg_connection
*
nc
,
char
*
tag
)
{
mg_call
(
nc
,
NULL
,
MG_EV_SSI_CALL
,
tag
);
}
...
...
@@ -5471,9 +5522,9 @@ static void do_ssi_call(struct mg_connection *nc, char *tag) {
* SSI directive has the following format:
* <!--#directive parameter=value parameter=value -->
*/
static
void
send_ssi_file
(
struct
mg_connection
*
nc
,
const
char
*
path
,
FILE
*
fp
,
int
include_level
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_send_ssi_file
(
struct
mg_connection
*
nc
,
const
char
*
path
,
FILE
*
fp
,
int
include_level
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
const
struct
mg_str
btag
=
MG_MK_STR
(
"<!--#"
);
static
const
struct
mg_str
d_include
=
MG_MK_STR
(
"include"
);
static
const
struct
mg_str
d_call
=
MG_MK_STR
(
"call"
);
...
...
@@ -5502,9 +5553,9 @@ static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp,
/* Handle known SSI directives */
if
(
memcmp
(
p
,
d_include
.
p
,
d_include
.
len
)
==
0
)
{
do_ssi_include
(
nc
,
path
,
p
+
d_include
.
len
+
1
,
include_level
,
opts
);
mg_
do_ssi_include
(
nc
,
path
,
p
+
d_include
.
len
+
1
,
include_level
,
opts
);
}
else
if
(
memcmp
(
p
,
d_call
.
p
,
d_call
.
len
)
==
0
)
{
do_ssi_call
(
nc
,
p
+
d_call
.
len
+
1
);
mg_
do_ssi_call
(
nc
,
p
+
d_call
.
len
+
1
);
#ifndef MG_DISABLE_POPEN
}
else
if
(
memcmp
(
p
,
d_exec
.
p
,
d_exec
.
len
)
==
0
)
{
do_ssi_exec
(
nc
,
p
+
d_exec
.
len
+
1
);
...
...
@@ -5544,46 +5595,47 @@ static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp,
}
}
static
void
handle_ssi_request
(
struct
mg_connection
*
nc
,
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_
handle_ssi_request
(
struct
mg_connection
*
nc
,
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
)
{
FILE
*
fp
;
struct
mg_str
mime_type
;
if
((
fp
=
fopen
(
path
,
"rb"
))
==
NULL
)
{
send_http_error
(
nc
,
404
,
NULL
);
mg_http_
send_http_error
(
nc
,
404
,
NULL
);
}
else
{
mg_set_close_on_exec
(
fileno
(
fp
));
mime_type
=
get_mime_type
(
path
,
"text/plain"
,
opts
);
mime_type
=
mg_
get_mime_type
(
path
,
"text/plain"
,
opts
);
mg_send_response_line
(
nc
,
200
,
opts
->
extra_headers
);
mg_printf
(
nc
,
"Content-Type: %.*s
\r\n
"
"Connection: close
\r\n\r\n
"
,
(
int
)
mime_type
.
len
,
mime_type
.
p
);
send_ssi_file
(
nc
,
path
,
fp
,
0
,
opts
);
mg_
send_ssi_file
(
nc
,
path
,
fp
,
0
,
opts
);
fclose
(
fp
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
}
#else
static
void
handle_ssi_request
(
struct
mg_connection
*
nc
,
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_
handle_ssi_request
(
struct
mg_connection
*
nc
,
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
)
{
(
void
)
path
;
(
void
)
opts
;
send_http_error
(
nc
,
500
,
"SSI disabled"
);
mg_http_
send_http_error
(
nc
,
500
,
"SSI disabled"
);
}
#endif
/* MG_DISABLE_SSI */
static
void
construct_etag
(
char
*
buf
,
size_t
buf_len
,
const
cs_stat_t
*
st
)
{
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
,
(
int64_t
)
st
->
st_size
);
}
static
void
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
static
void
mg_
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
strftime
(
buf
,
buf_len
,
"%a, %d %b %Y %H:%M:%S GMT"
,
gmtime
(
t
));
}
static
int
parse_range_header
(
const
struct
mg_str
*
header
,
int64_t
*
a
,
int64_t
*
b
)
{
static
int
mg_http_
parse_range_header
(
const
struct
mg_str
*
header
,
int64_t
*
a
,
int64_t
*
b
)
{
/*
* There is no snscanf. Headers are not guaranteed to be NUL-terminated,
* so we have this. Ugh.
...
...
@@ -5598,17 +5650,15 @@ static int parse_range_header(const struct mg_str *header, int64_t *a,
return
result
;
}
static
void
mg_
send_http
_file2
(
struct
mg_connection
*
nc
,
const
char
*
path
,
static
void
mg_
http_send
_file2
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
st
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
struct
proto_data_http
*
dp
;
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
)
;
struct
mg_str
mime_type
;
DBG
((
"%p [%s]"
,
nc
,
path
));
free_http_proto_data
(
nc
);
if
((
dp
=
(
struct
proto_data_http
*
)
MG_CALLOC
(
1
,
sizeof
(
*
dp
)))
==
NULL
)
{
send_http_error
(
nc
,
500
,
"Server Error"
);
/* LCOV_EXCL_LINE */
}
else
if
((
dp
->
fp
=
fopen
(
path
,
"rb"
))
==
NULL
)
{
mg_http_free_proto_data_file
(
&
pd
->
file
);
if
((
pd
->
file
.
fp
=
fopen
(
path
,
"rb"
))
==
NULL
)
{
int
code
;
switch
(
errno
)
{
case
EACCES
:
...
...
@@ -5620,13 +5670,10 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
default:
code
=
500
;
};
MG_FREE
(
dp
);
nc
->
proto_data
=
NULL
;
send_http_error
(
nc
,
code
,
"Open failed"
);
mg_http_send_http_error
(
nc
,
code
,
"Open failed"
);
}
else
if
(
mg_match_prefix
(
opts
->
ssi_pattern
,
strlen
(
opts
->
ssi_pattern
),
path
)
>
0
)
{
nc
->
proto_data
=
(
void
*
)
dp
;
handle_ssi_request
(
nc
,
path
,
opts
);
mg_handle_ssi_request
(
nc
,
path
,
opts
);
}
else
{
char
etag
[
50
],
current_time
[
50
],
last_modified
[
50
],
range
[
50
];
time_t
t
=
time
(
NULL
);
...
...
@@ -5637,7 +5684,7 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
/* Handle Range header */
range
[
0
]
=
'\0'
;
if
(
range_hdr
!=
NULL
&&
(
n
=
parse_range_header
(
range_hdr
,
&
r1
,
&
r2
))
>
0
&&
r1
>=
0
&&
(
n
=
mg_http_
parse_range_header
(
range_hdr
,
&
r1
,
&
r2
))
>
0
&&
r1
>=
0
&&
r2
>=
0
)
{
/* If range is specified like "400-", set second limit to content len */
if
(
n
==
1
)
{
...
...
@@ -5655,14 +5702,14 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes %"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
r1
,
r1
+
cl
-
1
,
(
int64_t
)
st
->
st_size
);
fseeko
(
dp
->
fp
,
r1
,
SEEK_SET
);
fseeko
(
pd
->
file
.
fp
,
r1
,
SEEK_SET
);
}
}
construct_etag
(
etag
,
sizeof
(
etag
),
st
);
gmt_time_string
(
current_time
,
sizeof
(
current_time
),
&
t
);
gmt_time_string
(
last_modified
,
sizeof
(
last_modified
),
&
st
->
st_mtime
);
mime_type
=
get_mime_type
(
path
,
"text/plain"
,
opts
);
mg_http_
construct_etag
(
etag
,
sizeof
(
etag
),
st
);
mg_
gmt_time_string
(
current_time
,
sizeof
(
current_time
),
&
t
);
mg_
gmt_time_string
(
last_modified
,
sizeof
(
last_modified
),
&
st
->
st_mtime
);
mime_type
=
mg_
get_mime_type
(
path
,
"text/plain"
,
opts
);
/*
* Content length casted to size_t because:
* 1) that's the maximum buffer size anyway
...
...
@@ -5685,10 +5732,9 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
current_time
,
last_modified
,
(
int
)
mime_type
.
len
,
mime_type
.
p
,
(
size_t
)
cl
,
range
,
etag
);
nc
->
proto_data
=
(
void
*
)
dp
;
dp
->
cl
=
cl
;
dp
->
type
=
DATA_FILE
;
transfer_file_data
(
nc
);
pd
->
file
.
cl
=
cl
;
pd
->
file
.
type
=
DATA_FILE
;
mg_http_transfer_file_data
(
nc
);
}
}
...
...
@@ -5854,9 +5900,9 @@ int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
}
#ifndef MG_DISABLE_FILESYSTEM
static
int
is_file_hidden
(
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
,
int
exclude_specials
)
{
static
int
mg_
is_file_hidden
(
const
char
*
path
,
const
struct
mg_serve_http_opts
*
opts
,
int
exclude_specials
)
{
const
char
*
p1
=
opts
->
per_directory_auth_file
;
const
char
*
p2
=
opts
->
hidden_file_pattern
;
...
...
@@ -5873,11 +5919,11 @@ static int is_file_hidden(const char *path,
}
#ifndef MG_DISABLE_HTTP_DIGEST_AUTH
static
void
mkmd5resp
(
const
char
*
method
,
size_t
method_len
,
const
char
*
uri
,
size_t
uri_len
,
const
char
*
ha1
,
size_t
ha1_len
,
const
char
*
nonce
,
size_t
nonce_len
,
const
char
*
nc
,
size_t
nc_len
,
const
char
*
cnonce
,
size_t
cnonce_len
,
const
char
*
qop
,
size_t
qop_len
,
char
*
resp
)
{
static
void
m
g_m
kmd5resp
(
const
char
*
method
,
size_t
method_len
,
const
char
*
uri
,
size_t
uri_len
,
const
char
*
ha1
,
size_t
ha1_len
,
const
char
*
nonce
,
size_t
nonce_len
,
const
char
*
nc
,
size_t
nc_len
,
const
char
*
cnonce
,
size_t
cnonce_len
,
const
char
*
qop
,
size_t
qop_len
,
char
*
resp
)
{
static
const
char
colon
[]
=
":"
;
static
const
size_t
one
=
1
;
char
ha2
[
33
];
...
...
@@ -5900,9 +5946,9 @@ int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
cs_md5
(
ha1
,
user
,
(
size_t
)
strlen
(
user
),
colon
,
one
,
auth_domain
,
(
size_t
)
strlen
(
auth_domain
),
colon
,
one
,
passwd
,
(
size_t
)
strlen
(
passwd
),
NULL
);
mkmd5resp
(
method
,
strlen
(
method
),
uri
,
strlen
(
uri
),
ha1
,
sizeof
(
ha1
)
-
1
,
cnonce
,
strlen
(
cnonce
),
"1"
,
one
,
cnonce
,
strlen
(
cnonce
),
qop
,
sizeof
(
qop
)
-
1
,
resp
);
m
g_m
kmd5resp
(
method
,
strlen
(
method
),
uri
,
strlen
(
uri
),
ha1
,
sizeof
(
ha1
)
-
1
,
cnonce
,
strlen
(
cnonce
),
"1"
,
one
,
cnonce
,
strlen
(
cnonce
),
qop
,
sizeof
(
qop
)
-
1
,
resp
);
return
snprintf
(
buf
,
buf_len
,
"Authorization: Digest username=
\"
%s
\"
,"
"realm=
\"
%s
\"
,uri=
\"
%s
\"
,qop=%s,nc=1,cnonce=%s,"
...
...
@@ -5916,7 +5962,7 @@ int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
* to prevent replay attacks.
* Assumption: nonce is a hexadecimal number of seconds since 1970.
*/
static
int
check_nonce
(
const
char
*
nonce
)
{
static
int
mg_
check_nonce
(
const
char
*
nonce
)
{
unsigned
long
now
=
(
unsigned
long
)
time
(
NULL
);
unsigned
long
val
=
(
unsigned
long
)
strtoul
(
nonce
,
NULL
,
16
);
return
now
<
val
||
now
-
val
<
3600
;
...
...
@@ -5943,7 +5989,7 @@ static int mg_http_check_digest_auth(struct http_message *hm,
mg_http_parse_header
(
hdr
,
"qop"
,
qop
,
sizeof
(
qop
))
==
0
||
mg_http_parse_header
(
hdr
,
"nc"
,
nc
,
sizeof
(
nc
))
==
0
||
mg_http_parse_header
(
hdr
,
"nonce"
,
nonce
,
sizeof
(
nonce
))
==
0
||
check_nonce
(
nonce
)
==
0
)
{
mg_
check_nonce
(
nonce
)
==
0
)
{
return
0
;
}
...
...
@@ -5958,7 +6004,7 @@ static int mg_http_check_digest_auth(struct http_message *hm,
/* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
strcmp
(
auth_domain
,
f_domain
)
==
0
)
{
/* User and domain matched, check the password */
mkmd5resp
(
m
g_m
kmd5resp
(
hm
->
method
.
p
,
hm
->
method
.
len
,
hm
->
uri
.
p
,
hm
->
uri
.
len
+
(
hm
->
query_string
.
len
?
hm
->
query_string
.
len
+
1
:
0
),
f_ha1
,
strlen
(
f_ha1
),
nonce
,
strlen
(
nonce
),
nc
,
strlen
(
nc
),
cnonce
,
...
...
@@ -5971,9 +6017,10 @@ static int mg_http_check_digest_auth(struct http_message *hm,
return
0
;
}
static
int
is_authorized
(
struct
http_message
*
hm
,
const
char
*
path
,
int
is_directory
,
const
char
*
domain
,
const
char
*
passwords_file
,
int
is_global_pass_file
)
{
static
int
mg_is_authorized
(
struct
http_message
*
hm
,
const
char
*
path
,
int
is_directory
,
const
char
*
domain
,
const
char
*
passwords_file
,
int
is_global_pass_file
)
{
char
buf
[
MG_MAX_PATH
];
const
char
*
p
;
FILE
*
fp
;
...
...
@@ -6004,9 +6051,10 @@ static int is_authorized(struct http_message *hm, const char *path,
return
authorized
;
}
#else
static
int
is_authorized
(
struct
http_message
*
hm
,
const
char
*
path
,
int
is_directory
,
const
char
*
domain
,
const
char
*
passwords_file
,
int
is_global_pass_file
)
{
static
int
mg_is_authorized
(
struct
http_message
*
hm
,
const
char
*
path
,
int
is_directory
,
const
char
*
domain
,
const
char
*
passwords_file
,
int
is_global_pass_file
)
{
(
void
)
hm
;
(
void
)
path
;
(
void
)
is_directory
;
...
...
@@ -6040,7 +6088,7 @@ static size_t mg_url_encode(const char *src, size_t s_len, char *dst,
return
j
;
}
static
void
escape
(
const
char
*
src
,
char
*
dst
,
size_t
dst_len
)
{
static
void
mg_
escape
(
const
char
*
src
,
char
*
dst
,
size_t
dst_len
)
{
size_t
n
=
0
;
while
(
*
src
!=
'\0'
&&
n
+
5
<
dst_len
)
{
unsigned
char
ch
=
*
(
unsigned
char
*
)
src
++
;
...
...
@@ -6053,8 +6101,8 @@ static void escape(const char *src, char *dst, size_t dst_len) {
dst
[
n
]
=
'\0'
;
}
static
void
print_dir_entry
(
struct
mg_connection
*
nc
,
const
char
*
file_name
,
cs_stat_t
*
stp
)
{
static
void
mg_
print_dir_entry
(
struct
mg_connection
*
nc
,
const
char
*
file_name
,
cs_stat_t
*
stp
)
{
char
size
[
64
],
mod
[
64
],
href
[
MAX_PATH_SIZE
*
3
],
path
[
MAX_PATH_SIZE
];
int64_t
fsize
=
stp
->
st_size
;
int
is_dir
=
S_ISDIR
(
stp
->
st_mode
);
...
...
@@ -6078,7 +6126,7 @@ static void print_dir_entry(struct mg_connection *nc, const char *file_name,
}
}
strftime
(
mod
,
sizeof
(
mod
),
"%d-%b-%Y %H:%M"
,
localtime
(
&
stp
->
st_mtime
));
escape
(
file_name
,
path
,
sizeof
(
path
));
mg_
escape
(
file_name
,
path
,
sizeof
(
path
));
mg_url_encode
(
file_name
,
strlen
(
file_name
),
href
,
sizeof
(
href
));
mg_printf_http_chunk
(
nc
,
"<tr><td><a href=
\"
%s%s
\"
>%s%s</a></td>"
...
...
@@ -6087,10 +6135,10 @@ static void print_dir_entry(struct mg_connection *nc, const char *file_name,
size
);
}
static
void
scan_directory
(
struct
mg_connection
*
nc
,
const
char
*
dir
,
const
struct
mg_serve_http_opts
*
opts
,
void
(
*
func
)(
struct
mg_connection
*
,
const
char
*
,
cs_stat_t
*
))
{
static
void
mg_
scan_directory
(
struct
mg_connection
*
nc
,
const
char
*
dir
,
const
struct
mg_serve_http_opts
*
opts
,
void
(
*
func
)(
struct
mg_connection
*
,
const
char
*
,
cs_stat_t
*
))
{
char
path
[
MAX_PATH_SIZE
];
cs_stat_t
st
;
struct
dirent
*
dp
;
...
...
@@ -6100,7 +6148,7 @@ static void scan_directory(struct mg_connection *nc, const char *dir,
if
((
dirp
=
(
opendir
(
dir
)))
!=
NULL
)
{
while
((
dp
=
readdir
(
dirp
))
!=
NULL
)
{
/* Do not show current dir and hidden files */
if
(
is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
if
(
mg_
is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
continue
;
}
snprintf
(
path
,
sizeof
(
path
),
"%s/%s"
,
dir
,
dp
->
d_name
);
...
...
@@ -6114,9 +6162,9 @@ static void scan_directory(struct mg_connection *nc, const char *dir,
}
}
static
void
send_directory_listing
(
struct
mg_connection
*
nc
,
const
char
*
dir
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_
send_directory_listing
(
struct
mg_connection
*
nc
,
const
char
*
dir
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
const
char
*
sort_js_code
=
"<script>function srt(tb, col) {"
"var tr = Array.prototype.slice.call(tb.rows, 0),"
...
...
@@ -6149,7 +6197,7 @@ static void send_directory_listing(struct mg_connection *nc, const char *dir,
"<tr><td colspan=
\"
3
\"
><hr></td></tr></thead><tbody id=tb>"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
,
sort_js_code
,
sort_js_code2
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
scan_directory
(
nc
,
dir
,
opts
,
print_dir_entry
);
mg_scan_directory
(
nc
,
dir
,
opts
,
mg_
print_dir_entry
);
mg_printf_http_chunk
(
nc
,
"%s"
,
"</tbody></body></html>"
);
mg_send_http_chunk
(
nc
,
""
,
0
);
/* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
...
...
@@ -6158,11 +6206,11 @@ static void send_directory_listing(struct mg_connection *nc, const char *dir,
#endif
/* MG_DISABLE_DIRECTORY_LISTING */
#ifndef MG_DISABLE_DAV
static
void
print_props
(
struct
mg_connection
*
nc
,
const
char
*
name
,
cs_stat_t
*
stp
)
{
static
void
mg_
print_props
(
struct
mg_connection
*
nc
,
const
char
*
name
,
cs_stat_t
*
stp
)
{
char
mtime
[
64
],
buf
[
MAX_PATH_SIZE
*
3
];
time_t
t
=
stp
->
st_mtime
;
/* store in local variable for NDK compile */
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
t
);
mg_
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
t
);
mg_url_encode
(
name
,
strlen
(
name
),
buf
,
sizeof
(
buf
));
mg_printf
(
nc
,
"<d:response>"
...
...
@@ -6181,9 +6229,9 @@ static void print_props(struct mg_connection *nc, const char *name,
(
int64_t
)
stp
->
st_size
,
mtime
);
}
static
void
handle_propfind
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
stp
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
void
mg_
handle_propfind
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
stp
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
const
char
header
[]
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
...
...
@@ -6201,9 +6249,9 @@ static void handle_propfind(struct mg_connection *nc, const char *path,
char
uri
[
MAX_PATH_SIZE
];
mg_send
(
nc
,
header
,
sizeof
(
header
)
-
1
);
snprintf
(
uri
,
sizeof
(
uri
),
"%.*s"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
print_props
(
nc
,
uri
,
stp
);
mg_
print_props
(
nc
,
uri
,
stp
);
if
(
S_ISDIR
(
stp
->
st_mode
)
&&
(
depth
==
NULL
||
mg_vcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
nc
,
path
,
opts
,
print_props
);
mg_scan_directory
(
nc
,
path
,
opts
,
mg_
print_props
);
}
mg_send
(
nc
,
footer
,
sizeof
(
footer
)
-
1
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
...
...
@@ -6222,7 +6270,7 @@ static void handle_propfind(struct mg_connection *nc, const char *path,
* NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
* Windows native DAV client. This is why FAKE LOCK is not enabed by default
*/
static
void
handle_lock
(
struct
mg_connection
*
nc
,
const
char
*
path
)
{
static
void
mg_
handle_lock
(
struct
mg_connection
*
nc
,
const
char
*
path
)
{
static
const
char
*
reply
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
...
...
@@ -6244,8 +6292,8 @@ static void handle_lock(struct mg_connection *nc, const char *path) {
}
#endif
static
void
handle_mkcol
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
static
void
mg_
handle_mkcol
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
int
status_code
=
500
;
if
(
hm
->
body
.
len
!=
(
size_t
)
~
0
&&
hm
->
body
.
len
>
0
)
{
status_code
=
415
;
...
...
@@ -6260,11 +6308,11 @@ static void handle_mkcol(struct mg_connection *nc, const char *path,
}
else
{
status_code
=
500
;
}
send_http_error
(
nc
,
status_code
,
NULL
);
mg_http_
send_http_error
(
nc
,
status_code
,
NULL
);
}
static
int
remove_directory
(
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
dir
)
{
static
int
mg_
remove_directory
(
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
dir
)
{
char
path
[
MAX_PATH_SIZE
];
struct
dirent
*
dp
;
cs_stat_t
st
;
...
...
@@ -6273,13 +6321,13 @@ static int remove_directory(const struct mg_serve_http_opts *opts,
if
((
dirp
=
opendir
(
dir
))
==
NULL
)
return
0
;
while
((
dp
=
readdir
(
dirp
))
!=
NULL
)
{
if
(
is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
if
(
mg_
is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
continue
;
}
snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_stat
(
path
,
&
st
);
if
(
S_ISDIR
(
st
.
st_mode
))
{
remove_directory
(
opts
,
path
);
mg_
remove_directory
(
opts
,
path
);
}
else
{
remove
(
path
);
}
...
...
@@ -6290,12 +6338,12 @@ static int remove_directory(const struct mg_serve_http_opts *opts,
return
1
;
}
static
void
handle_move
(
struct
mg_connection
*
c
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
,
struct
http_message
*
hm
)
{
static
void
mg_
handle_move
(
struct
mg_connection
*
c
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
,
struct
http_message
*
hm
)
{
const
struct
mg_str
*
dest
=
mg_get_http_header
(
hm
,
"Destination"
);
if
(
dest
==
NULL
)
{
send_http_error
(
c
,
411
,
NULL
);
mg_http_
send_http_error
(
c
,
411
,
NULL
);
}
else
{
const
char
*
p
=
(
char
*
)
memchr
(
dest
->
p
,
'/'
,
dest
->
len
);
if
(
p
!=
NULL
&&
p
[
1
]
==
'/'
&&
...
...
@@ -6304,34 +6352,34 @@ static void handle_move(struct mg_connection *c,
snprintf
(
buf
,
sizeof
(
buf
),
"%s%.*s"
,
opts
->
dav_document_root
,
(
int
)
(
dest
->
p
+
dest
->
len
-
p
),
p
);
if
(
rename
(
path
,
buf
)
==
0
)
{
send_http_error
(
c
,
200
,
NULL
);
mg_http_
send_http_error
(
c
,
200
,
NULL
);
}
else
{
send_http_error
(
c
,
418
,
NULL
);
mg_http_
send_http_error
(
c
,
418
,
NULL
);
}
}
else
{
send_http_error
(
c
,
500
,
NULL
);
mg_http_
send_http_error
(
c
,
500
,
NULL
);
}
}
}
static
void
handle_delete
(
struct
mg_connection
*
nc
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
)
{
static
void
mg_
handle_delete
(
struct
mg_connection
*
nc
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
)
{
cs_stat_t
st
;
if
(
mg_stat
(
path
,
&
st
)
!=
0
)
{
send_http_error
(
nc
,
404
,
NULL
);
mg_http_
send_http_error
(
nc
,
404
,
NULL
);
}
else
if
(
S_ISDIR
(
st
.
st_mode
))
{
remove_directory
(
opts
,
path
);
send_http_error
(
nc
,
204
,
NULL
);
mg_
remove_directory
(
opts
,
path
);
mg_http_
send_http_error
(
nc
,
204
,
NULL
);
}
else
if
(
remove
(
path
)
==
0
)
{
send_http_error
(
nc
,
204
,
NULL
);
mg_http_
send_http_error
(
nc
,
204
,
NULL
);
}
else
{
send_http_error
(
nc
,
423
,
NULL
);
mg_http_
send_http_error
(
nc
,
423
,
NULL
);
}
}
/* Return -1 on error, 1 on success. */
static
int
create_itermediate_directories
(
const
char
*
path
)
{
static
int
mg_
create_itermediate_directories
(
const
char
*
path
)
{
const
char
*
s
;
/* Create intermediate directories if they do not exist */
...
...
@@ -6350,47 +6398,43 @@ static int create_itermediate_directories(const char *path) {
return
1
;
}
static
void
handle_put
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
static
void
mg_handle_put
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
cs_stat_t
st
;
const
struct
mg_str
*
cl_hdr
=
mg_get_http_header
(
hm
,
"Content-Length"
);
int
rc
,
status_code
=
mg_stat
(
path
,
&
st
)
==
0
?
200
:
201
;
struct
proto_data_http
*
dp
=
(
struct
proto_data_http
*
)
nc
->
proto_data
;
free_http_proto_data
(
nc
);
if
((
rc
=
create_itermediate_directories
(
path
))
==
0
)
{
mg_http_free_proto_data_file
(
&
pd
->
file
);
if
((
rc
=
mg_
create_itermediate_directories
(
path
))
==
0
)
{
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
}
else
if
(
rc
==
-
1
)
{
send_http_error
(
nc
,
500
,
NULL
);
mg_http_
send_http_error
(
nc
,
500
,
NULL
);
}
else
if
(
cl_hdr
==
NULL
)
{
send_http_error
(
nc
,
411
,
NULL
);
}
else
if
((
dp
=
(
struct
proto_data_http
*
)
MG_CALLOC
(
1
,
sizeof
(
*
dp
)))
==
NULL
)
{
send_http_error
(
nc
,
500
,
NULL
);
/* LCOV_EXCL_LINE */
}
else
if
((
dp
->
fp
=
fopen
(
path
,
"w+b"
))
==
NULL
)
{
send_http_error
(
nc
,
500
,
NULL
);
free_http_proto_data
(
nc
);
mg_http_send_http_error
(
nc
,
411
,
NULL
);
}
else
if
((
pd
->
file
.
fp
=
fopen
(
path
,
"w+b"
))
==
NULL
)
{
mg_http_send_http_error
(
nc
,
500
,
NULL
);
}
else
{
const
struct
mg_str
*
range_hdr
=
mg_get_http_header
(
hm
,
"Content-Range"
);
int64_t
r1
=
0
,
r2
=
0
;
dp
->
type
=
DATA_PUT
;
mg_set_close_on_exec
(
fileno
(
dp
->
fp
));
dp
->
cl
=
to64
(
cl_hdr
->
p
);
if
(
range_hdr
!=
NULL
&&
parse_range_header
(
range_hdr
,
&
r1
,
&
r2
)
>
0
)
{
pd
->
file
.
type
=
DATA_PUT
;
mg_set_close_on_exec
(
fileno
(
pd
->
file
.
fp
));
pd
->
file
.
cl
=
to64
(
cl_hdr
->
p
);
if
(
range_hdr
!=
NULL
&&
mg_http_parse_range_header
(
range_hdr
,
&
r1
,
&
r2
)
>
0
)
{
status_code
=
206
;
fseeko
(
dp
->
fp
,
r1
,
SEEK_SET
);
dp
->
cl
=
r2
>
r1
?
r2
-
r1
+
1
:
dp
->
cl
-
r1
;
fseeko
(
pd
->
file
.
fp
,
r1
,
SEEK_SET
);
pd
->
file
.
cl
=
r2
>
r1
?
r2
-
r1
+
1
:
pd
->
file
.
cl
-
r1
;
}
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
nc
->
proto_data
=
dp
;
/* Remove HTTP request from the mbuf, leave only payload */
mbuf_remove
(
&
nc
->
recv_mbuf
,
hm
->
message
.
len
-
hm
->
body
.
len
);
transfer_file_data
(
nc
);
mg_http_
transfer_file_data
(
nc
);
}
}
#endif
/* MG_DISABLE_DAV */
static
int
is_dav_request
(
const
struct
mg_str
*
s
)
{
static
int
mg_
is_dav_request
(
const
struct
mg_str
*
s
)
{
static
const
char
*
methods
[]
=
{
"PUT"
,
"DELETE"
,
"MKCOL"
,
"PROPFIND"
,
"MOVE"
#ifdef MG_ENABLE_FAKE_DAVLOCK
,
...
...
@@ -6415,8 +6459,8 @@ static int is_dav_request(const struct mg_str *s) {
* appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
* If index file is not found, then `path` and `stp` remain unchanged.
*/
MG_INTERNAL
void
find_index_file
(
const
char
*
path
,
const
char
*
list
,
char
**
index_file
,
cs_stat_t
*
stp
)
{
MG_INTERNAL
void
mg_
find_index_file
(
const
char
*
path
,
const
char
*
list
,
char
**
index_file
,
cs_stat_t
*
stp
)
{
struct
mg_str
vec
;
size_t
path_len
=
strlen
(
path
);
int
found
=
0
;
...
...
@@ -6446,9 +6490,9 @@ MG_INTERNAL void find_index_file(const char *path, const char *list,
DBG
((
"[%s] [%s]"
,
path
,
(
*
index_file
?
*
index_file
:
""
)));
}
static
int
send_port_based_redirect
(
struct
mg_connection
*
c
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
static
int
mg_http_send_port_based_redirect
(
struct
mg_connection
*
c
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
a
,
b
;
char
local_port
[
20
]
=
{
'%'
};
...
...
@@ -6521,7 +6565,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
/* If no rewrite rules matched, use DAV or regular document root. */
if
(
root
.
p
==
NULL
)
{
#ifndef MG_DISABLE_DAV
if
(
opts
->
dav_document_root
!=
NULL
&&
is_dav_request
(
&
hm
->
method
))
{
if
(
opts
->
dav_document_root
!=
NULL
&&
mg_
is_dav_request
(
&
hm
->
method
))
{
root
.
p
=
opts
->
dav_document_root
;
root
.
len
=
strlen
(
opts
->
dav_document_root
);
}
else
...
...
@@ -6627,25 +6671,25 @@ out:
#ifndef MG_DISABLE_CGI
#ifdef _WIN32
struct
threadparam
{
struct
mg_
threadparam
{
sock_t
s
;
HANDLE
hPipe
;
};
static
int
wait_until_ready
(
sock_t
sock
,
int
for_read
)
{
static
int
mg_
wait_until_ready
(
sock_t
sock
,
int
for_read
)
{
fd_set
set
;
FD_ZERO
(
&
set
);
FD_SET
(
sock
,
&
set
);
return
select
(
sock
+
1
,
for_read
?
&
set
:
0
,
for_read
?
0
:
&
set
,
0
,
0
)
==
1
;
}
static
void
*
push_to_stdin
(
void
*
arg
)
{
struct
threadparam
*
tp
=
(
struct
threadparam
*
)
arg
;
static
void
*
mg_
push_to_stdin
(
void
*
arg
)
{
struct
mg_threadparam
*
tp
=
(
struct
mg_
threadparam
*
)
arg
;
int
n
,
sent
,
stop
=
0
;
DWORD
k
;
char
buf
[
BUFSIZ
];
while
(
!
stop
&&
wait_until_ready
(
tp
->
s
,
1
)
&&
while
(
!
stop
&&
mg_
wait_until_ready
(
tp
->
s
,
1
)
&&
(
n
=
recv
(
tp
->
s
,
buf
,
sizeof
(
buf
),
0
))
>
0
)
{
if
(
n
==
-
1
&&
GetLastError
()
==
WSAEWOULDBLOCK
)
continue
;
for
(
sent
=
0
;
!
stop
&&
sent
<
n
;
sent
+=
k
)
{
...
...
@@ -6659,15 +6703,15 @@ static void *push_to_stdin(void *arg) {
return
NULL
;
}
static
void
*
pull_from_stdout
(
void
*
arg
)
{
struct
threadparam
*
tp
=
(
struct
threadparam
*
)
arg
;
static
void
*
mg_
pull_from_stdout
(
void
*
arg
)
{
struct
mg_threadparam
*
tp
=
(
struct
mg_
threadparam
*
)
arg
;
int
k
=
0
,
stop
=
0
;
DWORD
n
,
sent
;
char
buf
[
BUFSIZ
];
while
(
!
stop
&&
ReadFile
(
tp
->
hPipe
,
buf
,
sizeof
(
buf
),
&
n
,
NULL
))
{
for
(
sent
=
0
;
!
stop
&&
sent
<
n
;
sent
+=
k
)
{
if
(
wait_until_ready
(
tp
->
s
,
0
)
&&
if
(
mg_
wait_until_ready
(
tp
->
s
,
0
)
&&
(
k
=
send
(
tp
->
s
,
buf
+
sent
,
n
-
sent
,
0
))
<=
0
)
stop
=
1
;
}
...
...
@@ -6681,9 +6725,9 @@ static void *pull_from_stdout(void *arg) {
return
NULL
;
}
static
void
spawn_stdio_thread
(
sock_t
sock
,
HANDLE
hPipe
,
void
*
(
*
func
)(
void
*
))
{
struct
threadparam
*
tp
=
(
struct
threadparam
*
)
MG_MALLOC
(
sizeof
(
*
tp
));
static
void
mg_
spawn_stdio_thread
(
sock_t
sock
,
HANDLE
hPipe
,
void
*
(
*
func
)(
void
*
))
{
struct
mg_threadparam
*
tp
=
(
struct
mg_
threadparam
*
)
MG_MALLOC
(
sizeof
(
*
tp
));
if
(
tp
!=
NULL
)
{
tp
->
s
=
sock
;
tp
->
hPipe
=
hPipe
;
...
...
@@ -6691,15 +6735,16 @@ static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
}
}
static
void
abs_path
(
const
char
*
utf8_path
,
char
*
abs_path
,
size_t
len
)
{
static
void
mg_
abs_path
(
const
char
*
utf8_path
,
char
*
abs_path
,
size_t
len
)
{
wchar_t
buf
[
MAX_PATH_SIZE
],
buf2
[
MAX_PATH_SIZE
];
to_wchar
(
utf8_path
,
buf
,
ARRAY_SIZE
(
buf
));
GetFullPathNameW
(
buf
,
ARRAY_SIZE
(
buf2
),
buf2
,
NULL
);
WideCharToMultiByte
(
CP_UTF8
,
0
,
buf2
,
wcslen
(
buf2
)
+
1
,
abs_path
,
len
,
0
,
0
);
}
static
pid_t
start_process
(
const
char
*
interp
,
const
char
*
cmd
,
const
char
*
env
,
const
char
*
envp
[],
const
char
*
dir
,
sock_t
sock
)
{
static
pid_t
mg_start_process
(
const
char
*
interp
,
const
char
*
cmd
,
const
char
*
env
,
const
char
*
envp
[],
const
char
*
dir
,
sock_t
sock
)
{
STARTUPINFOW
si
;
PROCESS_INFORMATION
pi
;
HANDLE
a
[
2
],
b
[
2
],
me
=
GetCurrentProcess
();
...
...
@@ -6737,13 +6782,13 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
}
snprintf
(
buf
,
sizeof
(
buf
),
"%s/%s"
,
dir
,
cmd
);
abs_path
(
buf
,
buf2
,
ARRAY_SIZE
(
buf2
));
mg_
abs_path
(
buf
,
buf2
,
ARRAY_SIZE
(
buf2
));
abs_path
(
dir
,
buf5
,
ARRAY_SIZE
(
buf5
));
mg_
abs_path
(
dir
,
buf5
,
ARRAY_SIZE
(
buf5
));
to_wchar
(
dir
,
full_dir
,
ARRAY_SIZE
(
full_dir
));
if
(
interp
!=
NULL
)
{
abs_path
(
interp
,
buf4
,
ARRAY_SIZE
(
buf4
));
mg_
abs_path
(
interp
,
buf4
,
ARRAY_SIZE
(
buf4
));
snprintf
(
cmdline
,
sizeof
(
cmdline
),
"%s
\"
%s
\"
"
,
buf4
,
buf2
);
}
else
{
snprintf
(
cmdline
,
sizeof
(
cmdline
),
"
\"
%s
\"
"
,
buf2
);
...
...
@@ -6752,8 +6797,8 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
if
(
CreateProcessW
(
NULL
,
wcmd
,
NULL
,
NULL
,
TRUE
,
CREATE_NEW_PROCESS_GROUP
,
(
void
*
)
env
,
full_dir
,
&
si
,
&
pi
)
!=
0
)
{
spawn_stdio_thread
(
sock
,
a
[
1
],
push_to_stdin
);
spawn_stdio_thread
(
sock
,
b
[
0
],
pull_from_stdout
);
mg_spawn_stdio_thread
(
sock
,
a
[
1
],
mg_
push_to_stdin
);
mg_spawn_stdio_thread
(
sock
,
b
[
0
],
mg_
pull_from_stdout
);
}
else
{
CloseHandle
(
a
[
1
]);
CloseHandle
(
b
[
0
]);
...
...
@@ -6771,8 +6816,9 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
return
pi
.
hProcess
;
}
#else
static
pid_t
start_process
(
const
char
*
interp
,
const
char
*
cmd
,
const
char
*
env
,
const
char
*
envp
[],
const
char
*
dir
,
sock_t
sock
)
{
static
pid_t
mg_start_process
(
const
char
*
interp
,
const
char
*
cmd
,
const
char
*
env
,
const
char
*
envp
[],
const
char
*
dir
,
sock_t
sock
)
{
char
buf
[
500
];
pid_t
pid
=
fork
();
(
void
)
env
;
...
...
@@ -6818,7 +6864,7 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
* pointer into the vars array.
*/
static
char
*
addenv
(
struct
cgi_env_block
*
block
,
const
char
*
fmt
,
...)
{
static
char
*
mg_addenv
(
struct
mg_
cgi_env_block
*
block
,
const
char
*
fmt
,
...)
{
int
n
,
space
;
char
*
added
=
block
->
buf
+
block
->
len
;
va_list
ap
;
...
...
@@ -6844,16 +6890,17 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
return
added
;
}
static
void
addenv2
(
struct
cgi_env_block
*
blk
,
const
char
*
name
)
{
static
void
mg_addenv2
(
struct
mg_
cgi_env_block
*
blk
,
const
char
*
name
)
{
const
char
*
s
;
if
((
s
=
getenv
(
name
))
!=
NULL
)
addenv
(
blk
,
"%s=%s"
,
name
,
s
);
if
((
s
=
getenv
(
name
))
!=
NULL
)
mg_
addenv
(
blk
,
"%s=%s"
,
name
,
s
);
}
static
void
prepare_cgi_environment
(
struct
mg_connection
*
nc
,
const
char
*
prog
,
const
struct
mg_str
*
path_info
,
const
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
,
struct
cgi_env_block
*
blk
)
{
static
void
mg_prepare_cgi_environment
(
struct
mg_connection
*
nc
,
const
char
*
prog
,
const
struct
mg_str
*
path_info
,
const
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
,
struct
mg_cgi_env_block
*
blk
)
{
const
char
*
s
;
struct
mg_str
*
h
;
char
*
p
;
...
...
@@ -6863,89 +6910,89 @@ static void prepare_cgi_environment(struct mg_connection *nc, const char *prog,
blk
->
nc
=
nc
;
if
((
s
=
getenv
(
"SERVER_NAME"
))
!=
NULL
)
{
addenv
(
blk
,
"SERVER_NAME=%s"
,
s
);
mg_
addenv
(
blk
,
"SERVER_NAME=%s"
,
s
);
}
else
{
char
buf
[
100
];
mg_sock_to_str
(
nc
->
sock
,
buf
,
sizeof
(
buf
),
3
);
addenv
(
blk
,
"SERVER_NAME=%s"
,
buf
);
mg_
addenv
(
blk
,
"SERVER_NAME=%s"
,
buf
);
}
addenv
(
blk
,
"SERVER_ROOT=%s"
,
opts
->
document_root
);
addenv
(
blk
,
"DOCUMENT_ROOT=%s"
,
opts
->
document_root
);
addenv
(
blk
,
"SERVER_SOFTWARE=%s/%s"
,
"Mongoose"
,
MG_VERSION
);
mg_
addenv
(
blk
,
"SERVER_ROOT=%s"
,
opts
->
document_root
);
mg_
addenv
(
blk
,
"DOCUMENT_ROOT=%s"
,
opts
->
document_root
);
mg_
addenv
(
blk
,
"SERVER_SOFTWARE=%s/%s"
,
"Mongoose"
,
MG_VERSION
);
/* Prepare the environment block */
addenv
(
blk
,
"%s"
,
"GATEWAY_INTERFACE=CGI/1.1"
);
addenv
(
blk
,
"%s"
,
"SERVER_PROTOCOL=HTTP/1.1"
);
addenv
(
blk
,
"%s"
,
"REDIRECT_STATUS=200"
);
/* For PHP */
mg_
addenv
(
blk
,
"%s"
,
"GATEWAY_INTERFACE=CGI/1.1"
);
mg_
addenv
(
blk
,
"%s"
,
"SERVER_PROTOCOL=HTTP/1.1"
);
mg_
addenv
(
blk
,
"%s"
,
"REDIRECT_STATUS=200"
);
/* For PHP */
/* TODO(lsm): fix this for IPv6 case */
/*addenv(blk, "SERVER_PORT=%d", ri->remote_port); */
addenv
(
blk
,
"REQUEST_METHOD=%.*s"
,
(
int
)
hm
->
method
.
len
,
hm
->
method
.
p
);
mg_
addenv
(
blk
,
"REQUEST_METHOD=%.*s"
,
(
int
)
hm
->
method
.
len
,
hm
->
method
.
p
);
#if 0
addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
#endif
addenv
(
blk
,
"REQUEST_URI=%.*s%s%.*s"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
,
hm
->
query_string
.
len
==
0
?
""
:
"?"
,
(
int
)
hm
->
query_string
.
len
,
hm
->
query_string
.
p
);
mg_
addenv
(
blk
,
"REQUEST_URI=%.*s%s%.*s"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
,
hm
->
query_string
.
len
==
0
?
""
:
"?"
,
(
int
)
hm
->
query_string
.
len
,
hm
->
query_string
.
p
);
s
=
hm
->
uri
.
p
+
hm
->
uri
.
len
-
path_info
->
len
-
1
;
if
(
*
s
==
'/'
)
{
const
char
*
base_name
=
strrchr
(
prog
,
DIRSEP
);
addenv
(
blk
,
"SCRIPT_NAME=%.*s/%s"
,
(
int
)
(
s
-
hm
->
uri
.
p
),
hm
->
uri
.
p
,
(
base_name
!=
NULL
?
base_name
+
1
:
prog
));
mg_
addenv
(
blk
,
"SCRIPT_NAME=%.*s/%s"
,
(
int
)
(
s
-
hm
->
uri
.
p
),
hm
->
uri
.
p
,
(
base_name
!=
NULL
?
base_name
+
1
:
prog
));
}
else
{
addenv
(
blk
,
"SCRIPT_NAME=%.*s"
,
(
int
)
(
s
-
hm
->
uri
.
p
+
1
),
hm
->
uri
.
p
);
mg_
addenv
(
blk
,
"SCRIPT_NAME=%.*s"
,
(
int
)
(
s
-
hm
->
uri
.
p
+
1
),
hm
->
uri
.
p
);
}
addenv
(
blk
,
"SCRIPT_FILENAME=%s"
,
prog
);
mg_
addenv
(
blk
,
"SCRIPT_FILENAME=%s"
,
prog
);
if
(
path_info
!=
NULL
&&
path_info
->
len
>
0
)
{
addenv
(
blk
,
"PATH_INFO=%.*s"
,
(
int
)
path_info
->
len
,
path_info
->
p
);
mg_
addenv
(
blk
,
"PATH_INFO=%.*s"
,
(
int
)
path_info
->
len
,
path_info
->
p
);
/* Not really translated... */
addenv
(
blk
,
"PATH_TRANSLATED=%.*s"
,
(
int
)
path_info
->
len
,
path_info
->
p
);
mg_
addenv
(
blk
,
"PATH_TRANSLATED=%.*s"
,
(
int
)
path_info
->
len
,
path_info
->
p
);
}
addenv
(
blk
,
"HTTPS=%s"
,
nc
->
ssl
!=
NULL
?
"on"
:
"off"
);
mg_
addenv
(
blk
,
"HTTPS=%s"
,
nc
->
ssl
!=
NULL
?
"on"
:
"off"
);
if
((
h
=
mg_get_http_header
((
struct
http_message
*
)
hm
,
"Content-Type"
))
!=
NULL
)
{
addenv
(
blk
,
"CONTENT_TYPE=%.*s"
,
(
int
)
h
->
len
,
h
->
p
);
mg_
addenv
(
blk
,
"CONTENT_TYPE=%.*s"
,
(
int
)
h
->
len
,
h
->
p
);
}
if
(
hm
->
query_string
.
len
>
0
)
{
addenv
(
blk
,
"QUERY_STRING=%.*s"
,
(
int
)
hm
->
query_string
.
len
,
hm
->
query_string
.
p
);
mg_
addenv
(
blk
,
"QUERY_STRING=%.*s"
,
(
int
)
hm
->
query_string
.
len
,
hm
->
query_string
.
p
);
}
if
((
h
=
mg_get_http_header
((
struct
http_message
*
)
hm
,
"Content-Length"
))
!=
NULL
)
{
addenv
(
blk
,
"CONTENT_LENGTH=%.*s"
,
(
int
)
h
->
len
,
h
->
p
);
mg_
addenv
(
blk
,
"CONTENT_LENGTH=%.*s"
,
(
int
)
h
->
len
,
h
->
p
);
}
addenv2
(
blk
,
"PATH"
);
addenv2
(
blk
,
"TMP"
);
addenv2
(
blk
,
"TEMP"
);
addenv2
(
blk
,
"TMPDIR"
);
addenv2
(
blk
,
"PERLLIB"
);
addenv2
(
blk
,
MG_ENV_EXPORT_TO_CGI
);
mg_
addenv2
(
blk
,
"PATH"
);
mg_
addenv2
(
blk
,
"TMP"
);
mg_
addenv2
(
blk
,
"TEMP"
);
mg_
addenv2
(
blk
,
"TMPDIR"
);
mg_
addenv2
(
blk
,
"PERLLIB"
);
mg_
addenv2
(
blk
,
MG_ENV_EXPORT_TO_CGI
);
#if defined(_WIN32)
addenv2
(
blk
,
"COMSPEC"
);
addenv2
(
blk
,
"SYSTEMROOT"
);
addenv2
(
blk
,
"SystemDrive"
);
addenv2
(
blk
,
"ProgramFiles"
);
addenv2
(
blk
,
"ProgramFiles(x86)"
);
addenv2
(
blk
,
"CommonProgramFiles(x86)"
);
mg_
addenv2
(
blk
,
"COMSPEC"
);
mg_
addenv2
(
blk
,
"SYSTEMROOT"
);
mg_
addenv2
(
blk
,
"SystemDrive"
);
mg_
addenv2
(
blk
,
"ProgramFiles"
);
mg_
addenv2
(
blk
,
"ProgramFiles(x86)"
);
mg_
addenv2
(
blk
,
"CommonProgramFiles(x86)"
);
#else
addenv2
(
blk
,
"LD_LIBRARY_PATH"
);
mg_
addenv2
(
blk
,
"LD_LIBRARY_PATH"
);
#endif
/* _WIN32 */
/* Add all headers as HTTP_* variables */
for
(
i
=
0
;
hm
->
header_names
[
i
].
len
>
0
;
i
++
)
{
p
=
addenv
(
blk
,
"HTTP_%.*s=%.*s"
,
(
int
)
hm
->
header_names
[
i
].
len
,
hm
->
header_names
[
i
].
p
,
(
int
)
hm
->
header_values
[
i
].
len
,
hm
->
header_values
[
i
].
p
);
p
=
mg_
addenv
(
blk
,
"HTTP_%.*s=%.*s"
,
(
int
)
hm
->
header_names
[
i
].
len
,
hm
->
header_names
[
i
].
p
,
(
int
)
hm
->
header_values
[
i
].
len
,
hm
->
header_values
[
i
].
p
);
/* Convert variable name into uppercase, and change - to _ */
for
(;
*
p
!=
'='
&&
*
p
!=
'\0'
;
p
++
)
{
...
...
@@ -6958,8 +7005,8 @@ static void prepare_cgi_environment(struct mg_connection *nc, const char *prog,
blk
->
buf
[
blk
->
len
++
]
=
'\0'
;
}
static
void
cgi_ev_handler
(
struct
mg_connection
*
cgi_nc
,
int
ev
,
void
*
ev_data
)
{
static
void
mg_
cgi_ev_handler
(
struct
mg_connection
*
cgi_nc
,
int
ev
,
void
*
ev_data
)
{
struct
mg_connection
*
nc
=
(
struct
mg_connection
*
)
cgi_nc
->
user_data
;
(
void
)
ev_data
;
...
...
@@ -6982,16 +7029,16 @@ static void cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
*/
if
(
nc
->
flags
&
MG_F_USER_1
)
{
struct
mbuf
*
io
=
&
cgi_nc
->
recv_mbuf
;
int
len
=
get_request_len
(
io
->
buf
,
io
->
len
);
int
len
=
mg_http_
get_request_len
(
io
->
buf
,
io
->
len
);
if
(
len
==
0
)
break
;
if
(
len
<
0
||
io
->
len
>
MG_MAX_HTTP_REQUEST_SIZE
)
{
cgi_nc
->
flags
|=
MG_F_CLOSE_IMMEDIATELY
;
send_http_error
(
nc
,
500
,
"Bad headers"
);
mg_http_
send_http_error
(
nc
,
500
,
"Bad headers"
);
}
else
{
struct
http_message
hm
;
struct
mg_str
*
h
;
parse_http
_headers
(
io
->
buf
,
io
->
buf
+
io
->
len
,
io
->
len
,
&
hm
);
mg_http_parse
_headers
(
io
->
buf
,
io
->
buf
+
io
->
len
,
io
->
len
,
&
hm
);
if
(
mg_get_http_header
(
&
hm
,
"Location"
)
!=
NULL
)
{
mg_printf
(
nc
,
"%s"
,
"HTTP/1.1 302 Moved
\r\n
"
);
}
else
if
((
h
=
mg_get_http_header
(
&
hm
,
"Status"
))
!=
NULL
)
{
...
...
@@ -7007,25 +7054,23 @@ static void cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
}
break
;
case
MG_EV_CLOSE
:
free_http_proto_data
(
cgi_nc
);
mg_http_free_proto_data_cgi
(
&
mg_http_get_proto_data
(
cgi_nc
)
->
cgi
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
nc
->
user_data
=
NULL
;
break
;
}
}
static
void
handle_cgi
(
struct
mg_connection
*
nc
,
const
char
*
prog
,
const
struct
mg_str
*
path_info
,
const
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
struct
proto_data_http
*
dp
;
struct
cgi_env_block
blk
;
static
void
mg_handle_cgi
(
struct
mg_connection
*
nc
,
const
char
*
prog
,
const
struct
mg_str
*
path_info
,
const
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
struct
mg_cgi_env_block
blk
;
char
dir
[
MAX_PATH_SIZE
];
const
char
*
p
;
sock_t
fds
[
2
];
DBG
((
"%p [%s]"
,
nc
,
prog
));
prepare_cgi_environment
(
nc
,
prog
,
path_info
,
hm
,
opts
,
&
blk
);
mg_
prepare_cgi_environment
(
nc
,
prog
,
path_info
,
hm
,
opts
,
&
blk
);
/*
* CGI must be executed in its own directory. 'dir' must point to the
* directory containing executable program, 'p' must point to the
...
...
@@ -7047,25 +7092,23 @@ static void handle_cgi(struct mg_connection *nc, const char *prog,
mg_socketpair
(
fds
,
SOCK_STREAM
);
}
while
(
fds
[
0
]
==
INVALID_SOCKET
);
free_http_proto_data
(
nc
);
if
((
dp
=
(
struct
proto_data_http
*
)
MG_CALLOC
(
1
,
sizeof
(
*
dp
)))
==
NULL
)
{
send_http_error
(
nc
,
500
,
"OOM"
);
/* LCOV_EXCL_LINE */
}
else
if
(
start_process
(
opts
->
cgi_interpreter
,
prog
,
blk
.
buf
,
blk
.
vars
,
dir
,
fds
[
1
])
!=
0
)
{
if
(
mg_start_process
(
opts
->
cgi_interpreter
,
prog
,
blk
.
buf
,
blk
.
vars
,
dir
,
fds
[
1
])
!=
0
)
{
size_t
n
=
nc
->
recv_mbuf
.
len
-
(
hm
->
message
.
len
-
hm
->
body
.
len
);
dp
->
type
=
DATA_CGI
;
dp
->
cgi_nc
=
mg_add_sock
(
nc
->
mgr
,
fds
[
0
],
cgi_ev_handler
);
dp
->
cgi_nc
->
user_data
=
nc
;
dp
->
cgi_nc
->
proto_data
=
dp
;
struct
mg_connection
*
cgi_nc
=
mg_add_sock
(
nc
->
mgr
,
fds
[
0
],
mg_cgi_ev_handler
);
struct
mg_http_proto_data
*
cgi_pd
=
mg_http_get_proto_data
(
cgi_nc
);
cgi_pd
->
cgi
.
cgi_nc
=
cgi_nc
;
cgi_pd
->
cgi
.
cgi_nc
->
user_data
=
nc
;
nc
->
flags
|=
MG_F_USER_1
;
/* Push POST data to the CGI */
if
(
n
>
0
&&
n
<
nc
->
recv_mbuf
.
len
)
{
mg_send
(
dp
->
cgi_nc
,
hm
->
body
.
p
,
n
);
mg_send
(
cgi_pd
->
cgi
.
cgi_nc
,
hm
->
body
.
p
,
n
);
}
mbuf_remove
(
&
nc
->
recv_mbuf
,
nc
->
recv_mbuf
.
len
);
}
else
{
closesocket
(
fds
[
0
]);
send_http_error
(
nc
,
500
,
"CGI failure"
);
mg_http_
send_http_error
(
nc
,
500
,
"CGI failure"
);
}
#ifndef _WIN32
...
...
@@ -7119,7 +7162,7 @@ MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
struct
mg_str
*
hdr
;
if
((
hdr
=
mg_get_http_header
(
hm
,
"If-None-Match"
))
!=
NULL
)
{
char
etag
[
64
];
construct_etag
(
etag
,
sizeof
(
etag
),
st
);
mg_http_
construct_etag
(
etag
,
sizeof
(
etag
),
st
);
return
mg_vcasecmp
(
hdr
,
etag
)
==
0
;
}
else
if
((
hdr
=
mg_get_http_header
(
hm
,
"If-Modified-Since"
))
!=
NULL
)
{
return
st
->
st_mtime
<=
mg_parse_date_string
(
hdr
->
p
);
...
...
@@ -7128,8 +7171,8 @@ MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
}
}
static
void
mg_send_digest_auth_request
(
struct
mg_connection
*
c
,
const
char
*
domain
)
{
static
void
mg_
http_
send_digest_auth_request
(
struct
mg_connection
*
c
,
const
char
*
domain
)
{
mg_printf
(
c
,
"HTTP/1.1 401 Unauthorized
\r\n
"
"WWW-Authenticate: Digest qop=
\"
auth
\"
, "
...
...
@@ -7138,7 +7181,7 @@ static void mg_send_digest_auth_request(struct mg_connection *c,
domain
,
(
unsigned
long
)
time
(
NULL
));
}
static
void
send_options
(
struct
mg_connection
*
nc
)
{
static
void
mg_http_
send_options
(
struct
mg_connection
*
nc
)
{
mg_printf
(
nc
,
"%s"
,
"HTTP/1.1 200 OK
\r\n
Allow: GET, POST, HEAD, CONNECT, OPTIONS"
#ifndef MG_DISABLE_DAV
...
...
@@ -7148,7 +7191,7 @@ static void send_options(struct mg_connection *nc) {
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
static
int
is_creation_request
(
const
struct
http_message
*
hm
)
{
static
int
mg_
is_creation_request
(
const
struct
http_message
*
hm
)
{
return
mg_vcmp
(
&
hm
->
method
,
"MKCOL"
)
==
0
||
mg_vcmp
(
&
hm
->
method
,
"PUT"
)
==
0
;
}
...
...
@@ -7156,7 +7199,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
const
struct
mg_str
*
path_info
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
int
exists
,
is_directory
,
is_dav
=
is_dav_request
(
&
hm
->
method
);
int
exists
,
is_directory
,
is_dav
=
mg_
is_dav_request
(
&
hm
->
method
);
int
is_cgi
;
char
*
index_file
=
NULL
;
cs_stat_t
st
;
...
...
@@ -7164,7 +7207,8 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
exists
=
(
mg_stat
(
path
,
&
st
)
==
0
);
is_directory
=
exists
&&
S_ISDIR
(
st
.
st_mode
);
if
(
is_directory
)
find_index_file
(
path
,
opts
->
index_files
,
&
index_file
,
&
st
);
if
(
is_directory
)
mg_find_index_file
(
path
,
opts
->
index_files
,
&
index_file
,
&
st
);
is_cgi
=
(
mg_match_prefix
(
opts
->
cgi_file_pattern
,
strlen
(
opts
->
cgi_file_pattern
),
...
...
@@ -7185,68 +7229,69 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
/* If we have path_info, the only way to handle it is CGI. */
if
(
path_info
->
len
>
0
&&
!
is_cgi
)
{
send_http_error
(
nc
,
501
,
NULL
);
mg_http_
send_http_error
(
nc
,
501
,
NULL
);
return
;
}
else
if
(
is_cgi
)
{
#if !defined(MG_DISABLE_CGI)
handle_cgi
(
nc
,
index_file
?
index_file
:
path
,
path_info
,
hm
,
opts
);
mg_
handle_cgi
(
nc
,
index_file
?
index_file
:
path
,
path_info
,
hm
,
opts
);
#else
send_http_error
(
nc
,
501
,
NULL
);
mg_http_
send_http_error
(
nc
,
501
,
NULL
);
#endif
/* MG_DISABLE_CGI */
MG_FREE
(
index_file
);
return
;
}
if
(
is_dav
&&
opts
->
dav_document_root
==
NULL
)
{
send_http_error
(
nc
,
501
,
NULL
);
}
else
if
(
!
is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
global_auth_file
,
1
)
||
!
is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
per_directory_auth_file
,
0
))
{
mg_send_digest_auth_request
(
nc
,
opts
->
auth_domain
);
}
else
if
((
!
exists
||
is_file_hidden
(
path
,
opts
,
0
/* specials are ok */
))
&&
!
is_creation_request
(
hm
))
{
send_http_error
(
nc
,
404
,
NULL
);
mg_http_send_http_error
(
nc
,
501
,
NULL
);
}
else
if
(
!
mg_is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
global_auth_file
,
1
)
||
!
mg_is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
per_directory_auth_file
,
0
))
{
mg_http_send_digest_auth_request
(
nc
,
opts
->
auth_domain
);
}
else
if
((
!
exists
||
mg_is_file_hidden
(
path
,
opts
,
0
/* specials are ok */
))
&&
!
mg_is_creation_request
(
hm
))
{
mg_http_send_http_error
(
nc
,
404
,
NULL
);
#ifndef MG_DISABLE_DAV
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"PROPFIND"
))
{
handle_propfind
(
nc
,
path
,
&
st
,
hm
,
opts
);
mg_
handle_propfind
(
nc
,
path
,
&
st
,
hm
,
opts
);
#ifndef MG_DISABLE_DAV_AUTH
}
else
if
(
is_dav
&&
(
opts
->
dav_auth_file
==
NULL
||
(
strcmp
(
opts
->
dav_auth_file
,
"-"
)
!=
0
&&
!
is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
dav_auth_file
,
1
))))
{
mg_send_digest_auth_request
(
nc
,
opts
->
auth_domain
);
!
mg_
is_authorized
(
hm
,
path
,
is_directory
,
opts
->
auth_domain
,
opts
->
dav_auth_file
,
1
))))
{
mg_
http_
send_digest_auth_request
(
nc
,
opts
->
auth_domain
);
#endif
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"MKCOL"
))
{
handle_mkcol
(
nc
,
path
,
hm
);
mg_
handle_mkcol
(
nc
,
path
,
hm
);
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"DELETE"
))
{
handle_delete
(
nc
,
opts
,
path
);
mg_
handle_delete
(
nc
,
opts
,
path
);
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"PUT"
))
{
handle_put
(
nc
,
path
,
hm
);
mg_
handle_put
(
nc
,
path
,
hm
);
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"MOVE"
))
{
handle_move
(
nc
,
opts
,
path
,
hm
);
mg_
handle_move
(
nc
,
opts
,
path
,
hm
);
#ifdef MG_ENABLE_FAKE_DAVLOCK
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"LOCK"
))
{
handle_lock
(
nc
,
path
);
mg_
handle_lock
(
nc
,
path
);
#endif
#endif
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"OPTIONS"
))
{
send_options
(
nc
);
mg_http_
send_options
(
nc
);
}
else
if
(
is_directory
&&
index_file
==
NULL
)
{
#ifndef MG_DISABLE_DIRECTORY_LISTING
if
(
strcmp
(
opts
->
enable_directory_listing
,
"yes"
)
==
0
)
{
send_directory_listing
(
nc
,
path
,
hm
,
opts
);
mg_
send_directory_listing
(
nc
,
path
,
hm
,
opts
);
}
else
{
send_http_error
(
nc
,
403
,
NULL
);
mg_http_
send_http_error
(
nc
,
403
,
NULL
);
}
#else
send_http_error
(
nc
,
501
,
NULL
);
mg_http_
send_http_error
(
nc
,
501
,
NULL
);
#endif
}
else
if
(
mg_is_not_modified
(
hm
,
&
st
))
{
send_http_error
(
nc
,
304
,
"Not Modified"
);
mg_http_
send_http_error
(
nc
,
304
,
"Not Modified"
);
}
else
{
mg_
send_http
_file2
(
nc
,
index_file
?
index_file
:
path
,
&
st
,
hm
,
opts
);
mg_
http_send
_file2
(
nc
,
index_file
?
index_file
:
path
,
&
st
,
hm
,
opts
);
}
MG_FREE
(
index_file
);
}
...
...
@@ -7259,12 +7304,12 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
if
(
mg_check_ip_acl
(
opts
.
ip_acl
,
remote_ip
)
!=
1
)
{
/* Not allowed to connect */
send_http_error
(
nc
,
403
,
NULL
);
mg_http_
send_http_error
(
nc
,
403
,
NULL
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
return
;
}
if
(
send_port_based_redirect
(
nc
,
hm
,
&
opts
))
{
if
(
mg_http_
send_port_based_redirect
(
nc
,
hm
,
&
opts
))
{
return
;
}
...
...
@@ -7288,11 +7333,11 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
}
/* Normalize path - resolve "." and ".." (in-place). */
if
(
!
mg_normalize_uri_path
(
&
hm
->
uri
,
&
hm
->
uri
))
{
send_http_error
(
nc
,
400
,
NULL
);
mg_http_
send_http_error
(
nc
,
400
,
NULL
);
return
;
}
if
(
mg_uri_to_local_path
(
hm
,
&
opts
,
&
path
,
&
path_info
)
==
0
)
{
send_http_error
(
nc
,
404
,
NULL
);
mg_http_
send_http_error
(
nc
,
404
,
NULL
);
return
;
}
mg_send_http_file
(
nc
,
path
,
&
path_info
,
hm
,
&
opts
);
...
...
@@ -7382,7 +7427,7 @@ cleanup:
return
nc
;
}
static
size_t
get_line_len
(
const
char
*
buf
,
size_t
buf_len
)
{
static
size_t
mg_
get_line_len
(
const
char
*
buf
,
size_t
buf_len
)
{
size_t
len
=
0
;
while
(
len
<
buf_len
&&
buf
[
len
]
!=
'\n'
)
len
++
;
return
buf
[
len
]
==
'\n'
?
len
+
1
:
0
;
...
...
@@ -7396,15 +7441,15 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
size_t
hl
,
bl
,
n
,
ll
,
pos
,
cdl
=
sizeof
(
cd
)
-
1
;
if
(
buf
==
NULL
||
buf_len
<=
0
)
return
0
;
if
((
hl
=
get_request_len
(
buf
,
buf_len
))
<=
0
)
return
0
;
if
((
hl
=
mg_http_
get_request_len
(
buf
,
buf_len
))
<=
0
)
return
0
;
if
(
buf
[
0
]
!=
'-'
||
buf
[
1
]
!=
'-'
||
buf
[
2
]
==
'\n'
)
return
0
;
/* Get boundary length */
bl
=
get_line_len
(
buf
,
buf_len
);
bl
=
mg_
get_line_len
(
buf
,
buf_len
);
/* Loop through headers, fetch variable name and file name */
var_name
[
0
]
=
file_name
[
0
]
=
'\0'
;
for
(
n
=
bl
;
(
ll
=
get_line_len
(
buf
+
n
,
hl
-
n
))
>
0
;
n
+=
ll
)
{
for
(
n
=
bl
;
(
ll
=
mg_
get_line_len
(
buf
+
n
,
hl
-
n
))
>
0
;
n
+=
ll
)
{
if
(
mg_ncasecmp
(
cd
,
buf
+
n
,
cdl
)
==
0
)
{
struct
mg_str
header
;
header
.
p
=
buf
+
n
+
cdl
;
...
...
mongoose.h
View file @
dbb38fff
...
...
@@ -1075,8 +1075,9 @@ struct mg_connection {
double
ev_timer_time
;
/* Timestamp of the future MG_EV_TIMER */
mg_event_handler_t
proto_handler
;
/* Protocol-specific event handler */
void
*
proto_data
;
/* Protocol-specific data */
mg_event_handler_t
handler
;
/* Event handler function */
void
*
user_data
;
/* User-specific data */
void
(
*
proto_data_destructor
)(
void
*
proto_data
);
mg_event_handler_t
handler
;
/* Event handler function */
void
*
user_data
;
/* User-specific data */
union
{
void
*
v
;
/*
...
...
@@ -1088,9 +1089,6 @@ struct mg_connection {
void
*
priv_2
;
/* Used by mg_enable_multithreading() */
struct
mbuf
endpoints
;
/* Used by mg_register_http_endpoint */
void
*
mgr_data
;
/* Implementation-specific event manager's data. */
#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
struct
mbuf
strm_state
;
/* Used by multi-part streaming */
#endif
unsigned
long
flags
;
/* Flags set by Mongoose */
#define MG_F_LISTENING (1 << 0)
/* This connection is listening */
...
...
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