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
1f471e1c
Commit
1f471e1c
authored
Sep 30, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved string functions to src/string.c
parent
ef28c375
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
540 additions
and
547 deletions
+540
-547
Makefile
build/Makefile
+3
-3
mongoose.c
build/src/mongoose.c
+24
-272
string.c
build/src/string.c
+245
-0
mongoose.c
mongoose.c
+268
-272
No files found.
build/Makefile
View file @
1f471e1c
...
...
@@ -24,7 +24,7 @@ EXE_SUFFIX =
CFLAGS
=
-std
=
c99
-O2
-W
-Wall
-pedantic
-pthread
-pipe
-I
..
$(CFLAGS_EXTRA)
VERSION
=
$(
shell
perl
-lne
\
'print $$1 if /define\s+MONGOOSE_VERSION\s+"(\S+
)
"/'
../mongoose.c
)
SOURCES
=
src/mongoose.c
SOURCES
=
src/
internal.h src/string.c src/
mongoose.c
TINY_SOURCES
=
../mongoose.c main.c
LUA_SOURCES
=
$(TINY_SOURCES)
sqlite3.c lsqlite3.c lua_5.2.1.c
...
...
@@ -57,8 +57,8 @@ endif
all
:
@
echo
"make (unix|windows|macos)"
../mongoose.c
:
mod_lua.c ../mongoose.h Makefile
src/internal.h
$(SOURCES)
cat
src/internal.h src/mongoose.c
|
sed
'/#include "internal.h"/d'
>
$@
../mongoose.c
:
mod_lua.c ../mongoose.h Makefile $(SOURCES)
cat
$(SOURCES)
|
sed
'/#include "internal.h"/d'
>
$@
unix_unit_test
:
$(LUA_SOURCES) Makefile ../test/unit_test.c
$(CC)
../test/unit_test.c lua_5.2.1.c
$(CFLAGS)
-g
-O0
-o
t
&&
./t
...
...
build/src/mongoose.c
View file @
1f471e1c
...
...
@@ -159,254 +159,6 @@ const char *mg_version(void) {
return
MONGOOSE_VERSION
;
}
static
void
mg_strlcpy
(
register
char
*
dst
,
register
const
char
*
src
,
size_t
n
)
{
for
(;
*
src
!=
'\0'
&&
n
>
1
;
n
--
)
{
*
dst
++
=
*
src
++
;
}
*
dst
=
'\0'
;
}
static
int
lowercase
(
const
char
*
s
)
{
return
tolower
(
*
(
const
unsigned
char
*
)
s
);
}
static
int
mg_strncasecmp
(
const
char
*
s1
,
const
char
*
s2
,
size_t
len
)
{
int
diff
=
0
;
if
(
len
>
0
)
do
{
diff
=
lowercase
(
s1
++
)
-
lowercase
(
s2
++
);
}
while
(
diff
==
0
&&
s1
[
-
1
]
!=
'\0'
&&
--
len
>
0
);
return
diff
;
}
static
int
mg_strcasecmp
(
const
char
*
s1
,
const
char
*
s2
)
{
int
diff
;
do
{
diff
=
lowercase
(
s1
++
)
-
lowercase
(
s2
++
);
}
while
(
diff
==
0
&&
s1
[
-
1
]
!=
'\0'
);
return
diff
;
}
static
char
*
mg_strndup
(
const
char
*
ptr
,
size_t
len
)
{
char
*
p
;
if
((
p
=
(
char
*
)
malloc
(
len
+
1
))
!=
NULL
)
{
mg_strlcpy
(
p
,
ptr
,
len
+
1
);
}
return
p
;
}
static
char
*
mg_strdup
(
const
char
*
str
)
{
return
mg_strndup
(
str
,
strlen
(
str
));
}
static
const
char
*
mg_strcasestr
(
const
char
*
big_str
,
const
char
*
small_str
)
{
int
i
,
big_len
=
strlen
(
big_str
),
small_len
=
strlen
(
small_str
);
for
(
i
=
0
;
i
<=
big_len
-
small_len
;
i
++
)
{
if
(
mg_strncasecmp
(
big_str
+
i
,
small_str
,
small_len
)
==
0
)
{
return
big_str
+
i
;
}
}
return
NULL
;
}
// Like snprintf(), but never returns negative value, or a value
// that is larger than a supplied buffer.
// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
// in his audit report.
static
int
mg_vsnprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
va_list
ap
)
{
int
n
;
if
(
buflen
==
0
)
return
0
;
n
=
vsnprintf
(
buf
,
buflen
,
fmt
,
ap
);
if
(
n
<
0
)
{
cry
(
conn
,
"vsnprintf error"
);
n
=
0
;
}
else
if
(
n
>=
(
int
)
buflen
)
{
cry
(
conn
,
"truncating vsnprintf buffer: [%.*s]"
,
n
>
200
?
200
:
n
,
buf
);
n
=
(
int
)
buflen
-
1
;
}
buf
[
n
]
=
'\0'
;
return
n
;
}
static
int
mg_snprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
4
,
5
);
static
int
mg_snprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
...)
{
va_list
ap
;
int
n
;
va_start
(
ap
,
fmt
);
n
=
mg_vsnprintf
(
conn
,
buf
,
buflen
,
fmt
,
ap
);
va_end
(
ap
);
return
n
;
}
// Skip the characters until one of the delimiters characters found.
// 0-terminate resulting word. Skip the delimiter and following whitespaces.
// Advance pointer to buffer to the next word. Return found 0-terminated word.
// Delimiters can be quoted with quotechar.
static
char
*
skip_quoted
(
char
**
buf
,
const
char
*
delimiters
,
const
char
*
whitespace
,
char
quotechar
)
{
char
*
p
,
*
begin_word
,
*
end_word
,
*
end_whitespace
;
begin_word
=
*
buf
;
end_word
=
begin_word
+
strcspn
(
begin_word
,
delimiters
);
// Check for quotechar
if
(
end_word
>
begin_word
)
{
p
=
end_word
-
1
;
while
(
*
p
==
quotechar
)
{
// If there is anything beyond end_word, copy it
if
(
*
end_word
==
'\0'
)
{
*
p
=
'\0'
;
break
;
}
else
{
size_t
end_off
=
strcspn
(
end_word
+
1
,
delimiters
);
memmove
(
p
,
end_word
,
end_off
+
1
);
p
+=
end_off
;
// p must correspond to end_word - 1
end_word
+=
end_off
+
1
;
}
}
for
(
p
++
;
p
<
end_word
;
p
++
)
{
*
p
=
'\0'
;
}
}
if
(
*
end_word
==
'\0'
)
{
*
buf
=
end_word
;
}
else
{
end_whitespace
=
end_word
+
1
+
strspn
(
end_word
+
1
,
whitespace
);
for
(
p
=
end_word
;
p
<
end_whitespace
;
p
++
)
{
*
p
=
'\0'
;
}
*
buf
=
end_whitespace
;
}
return
begin_word
;
}
// Simplified version of skip_quoted without quote char
// and whitespace == delimiters
static
char
*
skip
(
char
**
buf
,
const
char
*
delimiters
)
{
return
skip_quoted
(
buf
,
delimiters
,
delimiters
,
0
);
}
// Return HTTP header value, or NULL if not found.
static
const
char
*
get_header
(
const
struct
mg_request_info
*
ri
,
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
ri
->
num_headers
;
i
++
)
if
(
!
mg_strcasecmp
(
name
,
ri
->
http_headers
[
i
].
name
))
return
ri
->
http_headers
[
i
].
value
;
return
NULL
;
}
const
char
*
mg_get_header
(
const
struct
mg_connection
*
conn
,
const
char
*
name
)
{
return
get_header
(
&
conn
->
request_info
,
name
);
}
// A helper function for traversing a comma separated list of values.
// It returns a list pointer shifted to the next value, or NULL if the end
// of the list found.
// Value is stored in val vector. If value has form "x=y", then eq_val
// vector is initialized to point to the "y" part, and val vector length
// is adjusted to point only to "x".
static
const
char
*
next_option
(
const
char
*
list
,
struct
vec
*
val
,
struct
vec
*
eq_val
)
{
if
(
list
==
NULL
||
*
list
==
'\0'
)
{
// End of the list
list
=
NULL
;
}
else
{
val
->
ptr
=
list
;
if
((
list
=
strchr
(
val
->
ptr
,
','
))
!=
NULL
)
{
// Comma found. Store length and shift the list ptr
val
->
len
=
list
-
val
->
ptr
;
list
++
;
}
else
{
// This value is the last one
list
=
val
->
ptr
+
strlen
(
val
->
ptr
);
val
->
len
=
list
-
val
->
ptr
;
}
if
(
eq_val
!=
NULL
)
{
// Value has form "x=y", adjust pointers and lengths
// so that val points to "x", and eq_val points to "y".
eq_val
->
len
=
0
;
eq_val
->
ptr
=
(
const
char
*
)
memchr
(
val
->
ptr
,
'='
,
val
->
len
);
if
(
eq_val
->
ptr
!=
NULL
)
{
eq_val
->
ptr
++
;
// Skip over '=' character
eq_val
->
len
=
val
->
ptr
+
val
->
len
-
eq_val
->
ptr
;
val
->
len
=
(
eq_val
->
ptr
-
val
->
ptr
)
-
1
;
}
}
}
return
list
;
}
// Perform case-insensitive match of string against pattern
static
int
match_prefix
(
const
char
*
pattern
,
int
pattern_len
,
const
char
*
str
)
{
const
char
*
or_str
;
int
i
,
j
,
len
,
res
;
if
((
or_str
=
(
const
char
*
)
memchr
(
pattern
,
'|'
,
pattern_len
))
!=
NULL
)
{
res
=
match_prefix
(
pattern
,
or_str
-
pattern
,
str
);
return
res
>
0
?
res
:
match_prefix
(
or_str
+
1
,
(
pattern
+
pattern_len
)
-
(
or_str
+
1
),
str
);
}
i
=
j
=
0
;
res
=
-
1
;
for
(;
i
<
pattern_len
;
i
++
,
j
++
)
{
if
(
pattern
[
i
]
==
'?'
&&
str
[
j
]
!=
'\0'
)
{
continue
;
}
else
if
(
pattern
[
i
]
==
'$'
)
{
return
str
[
j
]
==
'\0'
?
j
:
-
1
;
}
else
if
(
pattern
[
i
]
==
'*'
)
{
i
++
;
if
(
pattern
[
i
]
==
'*'
)
{
i
++
;
len
=
(
int
)
strlen
(
str
+
j
);
}
else
{
len
=
(
int
)
strcspn
(
str
+
j
,
"/"
);
}
if
(
i
==
pattern_len
)
{
return
j
+
len
;
}
do
{
res
=
match_prefix
(
pattern
+
i
,
pattern_len
-
i
,
str
+
j
+
len
);
}
while
(
res
==
-
1
&&
len
--
>
0
);
return
res
==
-
1
?
-
1
:
j
+
res
+
len
;
}
else
if
(
lowercase
(
&
pattern
[
i
])
!=
lowercase
(
&
str
[
j
]))
{
return
-
1
;
}
}
return
j
;
}
// HTTP 1.1 assumes keep alive if "Connection:" header is not set
// This function must tolerate situations when connection info is not
// set up, for example if request parsing failed.
...
...
@@ -443,11 +195,11 @@ static void send_http_error(struct mg_connection *conn, int status,
// Errors 1xx, 204 and 304 MUST NOT send a body
if
(
status
>
199
&&
status
!=
204
&&
status
!=
304
)
{
len
=
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
len
=
mg_snprintf
(
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
buf
[
len
++
]
=
'\n'
;
va_start
(
ap
,
fmt
);
len
+=
mg_vsnprintf
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
len
+=
mg_vsnprintf
(
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
va_end
(
ap
);
}
DEBUG_TRACE
((
"[%s]"
,
buf
));
...
...
@@ -834,7 +586,7 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
}
GetFullPathNameA
(
dir
,
sizeof
(
full_dir
),
full_dir
,
NULL
);
mg_snprintf
(
c
onn
,
c
mdline
,
sizeof
(
cmdline
),
"%s%s
\"
%s
\\
%s
\"
"
,
mg_snprintf
(
cmdline
,
sizeof
(
cmdline
),
"%s%s
\"
%s
\\
%s
\"
"
,
interp
,
interp
[
0
]
==
'\0'
?
""
:
" "
,
full_dir
,
prog
);
DEBUG_TRACE
((
"Running [%s]"
,
cmdline
));
...
...
@@ -1311,12 +1063,12 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
// Using buf_len - 1 because memmove() for PATH_INFO may shift part
// of the path one byte on the right.
// If document_root is NULL, leave the file empty.
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%s%s"
,
root
,
uri
);
mg_snprintf
(
buf
,
buf_len
-
1
,
"%s%s"
,
root
,
uri
);
rewrite
=
conn
->
ctx
->
config
[
REWRITE
];
while
((
rewrite
=
next_option
(
rewrite
,
&
a
,
&
b
))
!=
NULL
)
{
if
((
match_len
=
match_prefix
(
a
.
ptr
,
a
.
len
,
uri
))
>
0
)
{
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
mg_snprintf
(
buf
,
buf_len
-
1
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
uri
+
match_len
);
break
;
}
...
...
@@ -1827,7 +1579,7 @@ static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
// Important: using local struct file to test path for is_directory flag.
// If filep is used, mg_stat() makes it appear as if auth file was opened.
}
else
if
(
mg_stat
(
path
,
&
file
)
&&
file
.
is_directory
)
{
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
mg_snprintf
(
name
,
sizeof
(
name
),
"%s%c%s"
,
path
,
'/'
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
}
else
{
...
...
@@ -1835,7 +1587,7 @@ static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
for
(
p
=
path
,
e
=
p
+
strlen
(
p
)
-
1
;
e
>
p
;
e
--
)
if
(
e
[
0
]
==
'/'
)
break
;
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%.*s%c%s"
,
mg_snprintf
(
name
,
sizeof
(
name
),
"%.*s%c%s"
,
(
int
)
(
e
-
p
),
p
,
'/'
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
}
...
...
@@ -1947,7 +1699,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
list
=
conn
->
ctx
->
config
[
PROTECT_URI
];
while
((
list
=
next_option
(
list
,
&
uri_vec
,
&
filename_vec
))
!=
NULL
)
{
if
(
!
memcmp
(
conn
->
request_info
.
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
))
{
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
mg_snprintf
(
fname
,
sizeof
(
fname
),
"%.*s"
,
(
int
)
filename_vec
.
len
,
filename_vec
.
ptr
);
if
((
fp
=
mg_fopen
(
fname
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"%s: cannot open %s: %s"
,
__func__
,
fname
,
strerror
(
errno
));
...
...
@@ -2112,20 +1864,20 @@ static void print_dir_entry(const struct de *de) {
const
char
*
slash
=
de
->
file
.
is_directory
?
"/"
:
""
;
if
(
de
->
file
.
is_directory
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
mg_snprintf
(
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
}
else
{
// We use (signed) cast below because MSVC 6 compiler cannot
// convert unsigned __int64 to double. Sigh.
if
(
de
->
file
.
size
<
1024
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%d"
,
(
int
)
de
->
file
.
size
);
mg_snprintf
(
size
,
sizeof
(
size
),
"%d"
,
(
int
)
de
->
file
.
size
);
}
else
if
(
de
->
file
.
size
<
0x100000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fk"
,
(
double
)
de
->
file
.
size
/
1024
.
0
);
}
else
if
(
de
->
file
.
size
<
0x40000000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fM"
,
(
double
)
de
->
file
.
size
/
1048576
);
}
else
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fG"
,
(
double
)
de
->
file
.
size
/
1073741824
);
}
}
...
...
@@ -2195,7 +1947,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
continue
;
}
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
...
...
@@ -2231,7 +1983,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) {
continue
;
}
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
...
...
@@ -2447,7 +2199,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
}
conn
->
status_code
=
206
;
cl
=
n
==
2
?
(
r2
>
cl
?
cl
:
r2
)
-
r1
+
1
:
cl
-
r1
;
mg_snprintf
(
conn
,
range
,
sizeof
(
range
),
mg_snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes "
"%"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
...
...
@@ -2724,7 +2476,7 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
// Copy VARIABLE=VALUE\0 string into the free space
va_start
(
ap
,
fmt
);
n
=
mg_vsnprintf
(
block
->
conn
,
added
,
(
size_t
)
space
,
fmt
,
ap
);
n
=
mg_vsnprintf
(
added
,
(
size_t
)
space
,
fmt
,
ap
);
va_end
(
ap
);
// Make sure we do not overflow buffer and the envp array
...
...
@@ -2877,7 +2629,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
// CGI must be executed in its own directory. 'dir' must point to the
// directory containing executable program, 'p' must point to the
// executable program name relative to 'dir'.
(
void
)
mg_snprintf
(
conn
,
dir
,
sizeof
(
dir
),
"%s"
,
prog
);
(
void
)
mg_snprintf
(
dir
,
sizeof
(
dir
),
"%s"
,
prog
);
if
((
p
=
strrchr
(
dir
,
'/'
))
!=
NULL
)
{
*
p
++
=
'\0'
;
}
else
{
...
...
@@ -3130,20 +2882,20 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
// of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
if
(
sscanf
(
tag
,
" virtual=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the webserver root
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
conn
->
ctx
->
config
[
DOCUMENT_ROOT
],
'/'
,
file_name
);
}
else
if
(
sscanf
(
tag
,
" abspath=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the webserver working directory
// or it is absolute system path
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s"
,
file_name
);
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s"
,
file_name
);
}
else
if
(
sscanf
(
tag
,
" file=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
||
sscanf
(
tag
,
"
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the currect document
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s"
,
ssi
);
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s"
,
ssi
);
if
((
p
=
strrchr
(
path
,
'/'
))
!=
NULL
)
{
p
[
1
]
=
'\0'
;
}
(
void
)
mg_snprintf
(
conn
,
path
+
strlen
(
path
),
(
void
)
mg_snprintf
(
path
+
strlen
(
path
),
sizeof
(
path
)
-
strlen
(
path
),
"%s"
,
file_name
);
}
else
{
cry
(
conn
,
"Bad SSI #include: [%s]"
,
tag
);
...
...
@@ -3301,7 +3053,7 @@ static void print_dav_dir_entry(struct de *de, void *data) {
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
conn
,
href
,
sizeof
(
href
),
"%s%s"
,
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
...
...
@@ -3493,7 +3245,7 @@ void mg_websocket_handshake(struct mg_connection *conn) {
char
buf
[
100
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
SHA1_CTX
sha_ctx
;
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"%s%s"
,
mg_snprintf
(
buf
,
sizeof
(
buf
),
"%s%s"
,
mg_get_header
(
conn
,
"Sec-WebSocket-Key"
),
magic
);
SHA1Init
(
&
sha_ctx
);
SHA1Update
(
&
sha_ctx
,
(
unsigned
char
*
)
buf
,
strlen
(
buf
));
...
...
build/src/string.c
0 → 100644
View file @
1f471e1c
#include "internal.h"
static
void
mg_strlcpy
(
register
char
*
dst
,
register
const
char
*
src
,
size_t
n
)
{
for
(;
*
src
!=
'\0'
&&
n
>
1
;
n
--
)
{
*
dst
++
=
*
src
++
;
}
*
dst
=
'\0'
;
}
static
int
lowercase
(
const
char
*
s
)
{
return
tolower
(
*
(
const
unsigned
char
*
)
s
);
}
static
int
mg_strncasecmp
(
const
char
*
s1
,
const
char
*
s2
,
size_t
len
)
{
int
diff
=
0
;
if
(
len
>
0
)
do
{
diff
=
lowercase
(
s1
++
)
-
lowercase
(
s2
++
);
}
while
(
diff
==
0
&&
s1
[
-
1
]
!=
'\0'
&&
--
len
>
0
);
return
diff
;
}
static
int
mg_strcasecmp
(
const
char
*
s1
,
const
char
*
s2
)
{
int
diff
;
do
{
diff
=
lowercase
(
s1
++
)
-
lowercase
(
s2
++
);
}
while
(
diff
==
0
&&
s1
[
-
1
]
!=
'\0'
);
return
diff
;
}
static
char
*
mg_strndup
(
const
char
*
ptr
,
size_t
len
)
{
char
*
p
;
if
((
p
=
(
char
*
)
malloc
(
len
+
1
))
!=
NULL
)
{
mg_strlcpy
(
p
,
ptr
,
len
+
1
);
}
return
p
;
}
static
char
*
mg_strdup
(
const
char
*
str
)
{
return
mg_strndup
(
str
,
strlen
(
str
));
}
static
const
char
*
mg_strcasestr
(
const
char
*
big_str
,
const
char
*
small_str
)
{
int
i
,
big_len
=
strlen
(
big_str
),
small_len
=
strlen
(
small_str
);
for
(
i
=
0
;
i
<=
big_len
-
small_len
;
i
++
)
{
if
(
mg_strncasecmp
(
big_str
+
i
,
small_str
,
small_len
)
==
0
)
{
return
big_str
+
i
;
}
}
return
NULL
;
}
// Like snprintf(), but never returns negative value, or a value
// that is larger than a supplied buffer.
// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
// in his audit report.
static
int
mg_vsnprintf
(
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
va_list
ap
)
{
int
n
;
if
(
buflen
==
0
)
{
return
0
;
}
n
=
vsnprintf
(
buf
,
buflen
,
fmt
,
ap
);
if
(
n
<
0
)
{
n
=
0
;
}
else
if
(
n
>=
(
int
)
buflen
)
{
n
=
(
int
)
buflen
-
1
;
}
buf
[
n
]
=
'\0'
;
return
n
;
}
static
int
mg_snprintf
(
char
*
buf
,
size_t
buflen
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
3
,
4
);
static
int
mg_snprintf
(
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
...)
{
va_list
ap
;
int
n
;
va_start
(
ap
,
fmt
);
n
=
mg_vsnprintf
(
buf
,
buflen
,
fmt
,
ap
);
va_end
(
ap
);
return
n
;
}
// Skip the characters until one of the delimiters characters found.
// 0-terminate resulting word. Skip the delimiter and following whitespaces.
// Advance pointer to buffer to the next word. Return found 0-terminated word.
// Delimiters can be quoted with quotechar.
static
char
*
skip_quoted
(
char
**
buf
,
const
char
*
delimiters
,
const
char
*
whitespace
,
char
quotechar
)
{
char
*
p
,
*
begin_word
,
*
end_word
,
*
end_whitespace
;
begin_word
=
*
buf
;
end_word
=
begin_word
+
strcspn
(
begin_word
,
delimiters
);
// Check for quotechar
if
(
end_word
>
begin_word
)
{
p
=
end_word
-
1
;
while
(
*
p
==
quotechar
)
{
// If there is anything beyond end_word, copy it
if
(
*
end_word
==
'\0'
)
{
*
p
=
'\0'
;
break
;
}
else
{
size_t
end_off
=
strcspn
(
end_word
+
1
,
delimiters
);
memmove
(
p
,
end_word
,
end_off
+
1
);
p
+=
end_off
;
// p must correspond to end_word - 1
end_word
+=
end_off
+
1
;
}
}
for
(
p
++
;
p
<
end_word
;
p
++
)
{
*
p
=
'\0'
;
}
}
if
(
*
end_word
==
'\0'
)
{
*
buf
=
end_word
;
}
else
{
end_whitespace
=
end_word
+
1
+
strspn
(
end_word
+
1
,
whitespace
);
for
(
p
=
end_word
;
p
<
end_whitespace
;
p
++
)
{
*
p
=
'\0'
;
}
*
buf
=
end_whitespace
;
}
return
begin_word
;
}
// Simplified version of skip_quoted without quote char
// and whitespace == delimiters
static
char
*
skip
(
char
**
buf
,
const
char
*
delimiters
)
{
return
skip_quoted
(
buf
,
delimiters
,
delimiters
,
0
);
}
// Return HTTP header value, or NULL if not found.
static
const
char
*
get_header
(
const
struct
mg_request_info
*
ri
,
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
ri
->
num_headers
;
i
++
)
if
(
!
mg_strcasecmp
(
name
,
ri
->
http_headers
[
i
].
name
))
return
ri
->
http_headers
[
i
].
value
;
return
NULL
;
}
const
char
*
mg_get_header
(
const
struct
mg_connection
*
conn
,
const
char
*
name
)
{
return
get_header
(
&
conn
->
request_info
,
name
);
}
// A helper function for traversing a comma separated list of values.
// It returns a list pointer shifted to the next value, or NULL if the end
// of the list found.
// Value is stored in val vector. If value has form "x=y", then eq_val
// vector is initialized to point to the "y" part, and val vector length
// is adjusted to point only to "x".
static
const
char
*
next_option
(
const
char
*
list
,
struct
vec
*
val
,
struct
vec
*
eq_val
)
{
if
(
list
==
NULL
||
*
list
==
'\0'
)
{
// End of the list
list
=
NULL
;
}
else
{
val
->
ptr
=
list
;
if
((
list
=
strchr
(
val
->
ptr
,
','
))
!=
NULL
)
{
// Comma found. Store length and shift the list ptr
val
->
len
=
list
-
val
->
ptr
;
list
++
;
}
else
{
// This value is the last one
list
=
val
->
ptr
+
strlen
(
val
->
ptr
);
val
->
len
=
list
-
val
->
ptr
;
}
if
(
eq_val
!=
NULL
)
{
// Value has form "x=y", adjust pointers and lengths
// so that val points to "x", and eq_val points to "y".
eq_val
->
len
=
0
;
eq_val
->
ptr
=
(
const
char
*
)
memchr
(
val
->
ptr
,
'='
,
val
->
len
);
if
(
eq_val
->
ptr
!=
NULL
)
{
eq_val
->
ptr
++
;
// Skip over '=' character
eq_val
->
len
=
val
->
ptr
+
val
->
len
-
eq_val
->
ptr
;
val
->
len
=
(
eq_val
->
ptr
-
val
->
ptr
)
-
1
;
}
}
}
return
list
;
}
// Perform case-insensitive match of string against pattern
static
int
match_prefix
(
const
char
*
pattern
,
int
pattern_len
,
const
char
*
str
)
{
const
char
*
or_str
;
int
i
,
j
,
len
,
res
;
if
((
or_str
=
(
const
char
*
)
memchr
(
pattern
,
'|'
,
pattern_len
))
!=
NULL
)
{
res
=
match_prefix
(
pattern
,
or_str
-
pattern
,
str
);
return
res
>
0
?
res
:
match_prefix
(
or_str
+
1
,
(
pattern
+
pattern_len
)
-
(
or_str
+
1
),
str
);
}
i
=
j
=
0
;
res
=
-
1
;
for
(;
i
<
pattern_len
;
i
++
,
j
++
)
{
if
(
pattern
[
i
]
==
'?'
&&
str
[
j
]
!=
'\0'
)
{
continue
;
}
else
if
(
pattern
[
i
]
==
'$'
)
{
return
str
[
j
]
==
'\0'
?
j
:
-
1
;
}
else
if
(
pattern
[
i
]
==
'*'
)
{
i
++
;
if
(
pattern
[
i
]
==
'*'
)
{
i
++
;
len
=
(
int
)
strlen
(
str
+
j
);
}
else
{
len
=
(
int
)
strcspn
(
str
+
j
,
"/"
);
}
if
(
i
==
pattern_len
)
{
return
j
+
len
;
}
do
{
res
=
match_prefix
(
pattern
+
i
,
pattern_len
-
i
,
str
+
j
+
len
);
}
while
(
res
==
-
1
&&
len
--
>
0
);
return
res
==
-
1
?
-
1
:
j
+
res
+
len
;
}
else
if
(
lowercase
(
&
pattern
[
i
])
!=
lowercase
(
&
str
[
j
]))
{
return
-
1
;
}
}
return
j
;
}
mongoose.c
View file @
1f471e1c
...
...
@@ -459,165 +459,6 @@ struct de {
};
static
const
char
*
month_names
[]
=
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sep"
,
"Oct"
,
"Nov"
,
"Dec"
};
static
const
char
*
config_options
[]
=
{
"cgi_pattern"
,
"**.cgi$|**.pl$|**.php$"
,
"cgi_environment"
,
NULL
,
"put_delete_auth_file"
,
NULL
,
"cgi_interpreter"
,
NULL
,
"protect_uri"
,
NULL
,
"authentication_domain"
,
"mydomain.com"
,
"ssi_pattern"
,
"**.shtml$|**.shtm$"
,
"throttle"
,
NULL
,
"access_log_file"
,
NULL
,
"enable_directory_listing"
,
"yes"
,
"error_log_file"
,
NULL
,
"global_auth_file"
,
NULL
,
"index_files"
,
"index.html,index.htm,index.cgi,index.shtml,index.php,index.lp"
,
"enable_keep_alive"
,
"no"
,
"access_control_list"
,
NULL
,
"extra_mime_types"
,
NULL
,
"listening_ports"
,
"8080"
,
"document_root"
,
NULL
,
"ssl_certificate"
,
NULL
,
"num_threads"
,
"50"
,
"run_as_user"
,
NULL
,
"url_rewrite_patterns"
,
NULL
,
"hide_files_patterns"
,
NULL
,
"request_timeout_ms"
,
"30000"
,
NULL
};
// Return number of bytes left to read for this connection
static
int64_t
left_to_read
(
const
struct
mg_connection
*
conn
)
{
return
conn
->
content_len
+
conn
->
request_len
-
conn
->
num_bytes_read
;
}
const
char
**
mg_get_valid_option_names
(
void
)
{
return
config_options
;
}
static
int
call_user
(
int
type
,
struct
mg_connection
*
conn
,
void
*
p
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
conn
->
event
.
user_data
=
conn
->
ctx
->
user_data
;
conn
->
event
.
type
=
type
;
conn
->
event
.
event_param
=
p
;
conn
->
event
.
request_info
=
&
conn
->
request_info
;
conn
->
event
.
conn
=
conn
;
}
return
conn
==
NULL
||
conn
->
ctx
==
NULL
||
conn
->
ctx
->
event_handler
==
NULL
?
0
:
conn
->
ctx
->
event_handler
(
&
conn
->
event
);
}
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
)
{
#ifdef _WIN32
wchar_t
wbuf
[
PATH_MAX
],
wmode
[
20
];
to_unicode
(
path
,
wbuf
,
ARRAY_SIZE
(
wbuf
));
MultiByteToWideChar
(
CP_UTF8
,
0
,
mode
,
-
1
,
wmode
,
ARRAY_SIZE
(
wmode
));
return
_wfopen
(
wbuf
,
wmode
);
#else
return
fopen
(
path
,
mode
);
#endif
}
static
int
get_option_index
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
config_options
[
i
*
2
]
!=
NULL
;
i
++
)
{
if
(
strcmp
(
config_options
[
i
*
2
],
name
)
==
0
)
{
return
i
;
}
}
return
-
1
;
}
const
char
*
mg_get_option
(
const
struct
mg_context
*
ctx
,
const
char
*
name
)
{
int
i
;
if
((
i
=
get_option_index
(
name
))
==
-
1
)
{
return
NULL
;
}
else
if
(
ctx
->
config
[
i
]
==
NULL
)
{
return
""
;
}
else
{
return
ctx
->
config
[
i
];
}
}
static
void
sockaddr_to_string
(
char
*
buf
,
size_t
len
,
const
union
usa
*
usa
)
{
buf
[
0
]
=
'\0'
;
#if defined(USE_IPV6)
inet_ntop
(
usa
->
sa
.
sa_family
,
usa
->
sa
.
sa_family
==
AF_INET
?
(
void
*
)
&
usa
->
sin
.
sin_addr
:
(
void
*
)
&
usa
->
sin6
.
sin6_addr
,
buf
,
len
);
#elif defined(_WIN32)
// Only Windoze Vista (and newer) have inet_ntop()
strncpy
(
buf
,
inet_ntoa
(
usa
->
sin
.
sin_addr
),
len
);
#else
inet_ntop
(
usa
->
sa
.
sa_family
,
(
void
*
)
&
usa
->
sin
.
sin_addr
,
buf
,
len
);
#endif
}
static
void
cry
(
struct
mg_connection
*
conn
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
2
,
3
);
// Print error message to the opened error log stream.
static
void
cry
(
struct
mg_connection
*
conn
,
const
char
*
fmt
,
...)
{
char
buf
[
MG_BUF_LEN
],
src_addr
[
IP_ADDR_STR_LEN
];
va_list
ap
;
FILE
*
fp
;
time_t
timestamp
;
va_start
(
ap
,
fmt
);
(
void
)
vsnprintf
(
buf
,
sizeof
(
buf
),
fmt
,
ap
);
va_end
(
ap
);
// Do not lock when getting the callback value, here and below.
// I suppose this is fine, since function cannot disappear in the
// same way string option can.
if
(
call_user
(
MG_EVENT_LOG
,
conn
,
buf
)
==
0
)
{
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
if
(
fp
!=
NULL
)
{
flockfile
(
fp
);
timestamp
=
time
(
NULL
);
sockaddr_to_string
(
src_addr
,
sizeof
(
src_addr
),
&
conn
->
client
.
rsa
);
fprintf
(
fp
,
"[%010lu] [error] [client %s] "
,
(
unsigned
long
)
timestamp
,
src_addr
);
if
(
conn
->
request_info
.
request_method
!=
NULL
)
{
fprintf
(
fp
,
"%s %s: "
,
conn
->
request_info
.
request_method
,
conn
->
request_info
.
uri
);
}
fprintf
(
fp
,
"%s"
,
buf
);
fputc
(
'\n'
,
fp
);
funlockfile
(
fp
);
fclose
(
fp
);
}
}
}
// Return fake connection structure. Used for logging, if connection
// is not applicable at the moment of logging.
static
struct
mg_connection
*
fc
(
struct
mg_context
*
ctx
)
{
static
struct
mg_connection
fake_connection
;
fake_connection
.
ctx
=
ctx
;
// See https://github.com/cesanta/mongoose/issues/236
fake_connection
.
event
.
user_data
=
ctx
->
user_data
;
return
&
fake_connection
;
}
const
char
*
mg_version
(
void
)
{
return
MONGOOSE_VERSION
;
}
static
void
mg_strlcpy
(
register
char
*
dst
,
register
const
char
*
src
,
size_t
n
)
{
for
(;
*
src
!=
'\0'
&&
n
>
1
;
n
--
)
{
*
dst
++
=
*
src
++
;
...
...
@@ -680,21 +521,18 @@ static const char *mg_strcasestr(const char *big_str, const char *small_str) {
// that is larger than a supplied buffer.
// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
// in his audit report.
static
int
mg_vsnprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
va_list
ap
)
{
static
int
mg_vsnprintf
(
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
va_list
ap
)
{
int
n
;
if
(
buflen
==
0
)
if
(
buflen
==
0
)
{
return
0
;
}
n
=
vsnprintf
(
buf
,
buflen
,
fmt
,
ap
);
if
(
n
<
0
)
{
cry
(
conn
,
"vsnprintf error"
);
n
=
0
;
}
else
if
(
n
>=
(
int
)
buflen
)
{
cry
(
conn
,
"truncating vsnprintf buffer: [%.*s]"
,
n
>
200
?
200
:
n
,
buf
);
n
=
(
int
)
buflen
-
1
;
}
buf
[
n
]
=
'\0'
;
...
...
@@ -702,17 +540,15 @@ static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
return
n
;
}
static
int
mg_snprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
4
,
5
);
static
int
mg_snprintf
(
char
*
buf
,
size_t
buflen
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
3
,
4
);
static
int
mg_snprintf
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
...)
{
static
int
mg_snprintf
(
char
*
buf
,
size_t
buflen
,
const
char
*
fmt
,
...)
{
va_list
ap
;
int
n
;
va_start
(
ap
,
fmt
);
n
=
mg_vsnprintf
(
conn
,
buf
,
buflen
,
fmt
,
ap
);
n
=
mg_vsnprintf
(
buf
,
buflen
,
fmt
,
ap
);
va_end
(
ap
);
return
n
;
...
...
@@ -866,6 +702,166 @@ static int match_prefix(const char *pattern, int pattern_len, const char *str) {
return
j
;
}
static
const
char
*
month_names
[]
=
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sep"
,
"Oct"
,
"Nov"
,
"Dec"
};
static
const
char
*
config_options
[]
=
{
"cgi_pattern"
,
"**.cgi$|**.pl$|**.php$"
,
"cgi_environment"
,
NULL
,
"put_delete_auth_file"
,
NULL
,
"cgi_interpreter"
,
NULL
,
"protect_uri"
,
NULL
,
"authentication_domain"
,
"mydomain.com"
,
"ssi_pattern"
,
"**.shtml$|**.shtm$"
,
"throttle"
,
NULL
,
"access_log_file"
,
NULL
,
"enable_directory_listing"
,
"yes"
,
"error_log_file"
,
NULL
,
"global_auth_file"
,
NULL
,
"index_files"
,
"index.html,index.htm,index.cgi,index.shtml,index.php,index.lp"
,
"enable_keep_alive"
,
"no"
,
"access_control_list"
,
NULL
,
"extra_mime_types"
,
NULL
,
"listening_ports"
,
"8080"
,
"document_root"
,
NULL
,
"ssl_certificate"
,
NULL
,
"num_threads"
,
"50"
,
"run_as_user"
,
NULL
,
"url_rewrite_patterns"
,
NULL
,
"hide_files_patterns"
,
NULL
,
"request_timeout_ms"
,
"30000"
,
NULL
};
// Return number of bytes left to read for this connection
static
int64_t
left_to_read
(
const
struct
mg_connection
*
conn
)
{
return
conn
->
content_len
+
conn
->
request_len
-
conn
->
num_bytes_read
;
}
const
char
**
mg_get_valid_option_names
(
void
)
{
return
config_options
;
}
static
int
call_user
(
int
type
,
struct
mg_connection
*
conn
,
void
*
p
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
conn
->
event
.
user_data
=
conn
->
ctx
->
user_data
;
conn
->
event
.
type
=
type
;
conn
->
event
.
event_param
=
p
;
conn
->
event
.
request_info
=
&
conn
->
request_info
;
conn
->
event
.
conn
=
conn
;
}
return
conn
==
NULL
||
conn
->
ctx
==
NULL
||
conn
->
ctx
->
event_handler
==
NULL
?
0
:
conn
->
ctx
->
event_handler
(
&
conn
->
event
);
}
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
)
{
#ifdef _WIN32
wchar_t
wbuf
[
PATH_MAX
],
wmode
[
20
];
to_unicode
(
path
,
wbuf
,
ARRAY_SIZE
(
wbuf
));
MultiByteToWideChar
(
CP_UTF8
,
0
,
mode
,
-
1
,
wmode
,
ARRAY_SIZE
(
wmode
));
return
_wfopen
(
wbuf
,
wmode
);
#else
return
fopen
(
path
,
mode
);
#endif
}
static
int
get_option_index
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
config_options
[
i
*
2
]
!=
NULL
;
i
++
)
{
if
(
strcmp
(
config_options
[
i
*
2
],
name
)
==
0
)
{
return
i
;
}
}
return
-
1
;
}
const
char
*
mg_get_option
(
const
struct
mg_context
*
ctx
,
const
char
*
name
)
{
int
i
;
if
((
i
=
get_option_index
(
name
))
==
-
1
)
{
return
NULL
;
}
else
if
(
ctx
->
config
[
i
]
==
NULL
)
{
return
""
;
}
else
{
return
ctx
->
config
[
i
];
}
}
static
void
sockaddr_to_string
(
char
*
buf
,
size_t
len
,
const
union
usa
*
usa
)
{
buf
[
0
]
=
'\0'
;
#if defined(USE_IPV6)
inet_ntop
(
usa
->
sa
.
sa_family
,
usa
->
sa
.
sa_family
==
AF_INET
?
(
void
*
)
&
usa
->
sin
.
sin_addr
:
(
void
*
)
&
usa
->
sin6
.
sin6_addr
,
buf
,
len
);
#elif defined(_WIN32)
// Only Windoze Vista (and newer) have inet_ntop()
strncpy
(
buf
,
inet_ntoa
(
usa
->
sin
.
sin_addr
),
len
);
#else
inet_ntop
(
usa
->
sa
.
sa_family
,
(
void
*
)
&
usa
->
sin
.
sin_addr
,
buf
,
len
);
#endif
}
static
void
cry
(
struct
mg_connection
*
conn
,
PRINTF_FORMAT_STRING
(
const
char
*
fmt
),
...)
PRINTF_ARGS
(
2
,
3
);
// Print error message to the opened error log stream.
static
void
cry
(
struct
mg_connection
*
conn
,
const
char
*
fmt
,
...)
{
char
buf
[
MG_BUF_LEN
],
src_addr
[
IP_ADDR_STR_LEN
];
va_list
ap
;
FILE
*
fp
;
time_t
timestamp
;
va_start
(
ap
,
fmt
);
(
void
)
vsnprintf
(
buf
,
sizeof
(
buf
),
fmt
,
ap
);
va_end
(
ap
);
// Do not lock when getting the callback value, here and below.
// I suppose this is fine, since function cannot disappear in the
// same way string option can.
if
(
call_user
(
MG_EVENT_LOG
,
conn
,
buf
)
==
0
)
{
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
if
(
fp
!=
NULL
)
{
flockfile
(
fp
);
timestamp
=
time
(
NULL
);
sockaddr_to_string
(
src_addr
,
sizeof
(
src_addr
),
&
conn
->
client
.
rsa
);
fprintf
(
fp
,
"[%010lu] [error] [client %s] "
,
(
unsigned
long
)
timestamp
,
src_addr
);
if
(
conn
->
request_info
.
request_method
!=
NULL
)
{
fprintf
(
fp
,
"%s %s: "
,
conn
->
request_info
.
request_method
,
conn
->
request_info
.
uri
);
}
fprintf
(
fp
,
"%s"
,
buf
);
fputc
(
'\n'
,
fp
);
funlockfile
(
fp
);
fclose
(
fp
);
}
}
}
// Return fake connection structure. Used for logging, if connection
// is not applicable at the moment of logging.
static
struct
mg_connection
*
fc
(
struct
mg_context
*
ctx
)
{
static
struct
mg_connection
fake_connection
;
fake_connection
.
ctx
=
ctx
;
// See https://github.com/cesanta/mongoose/issues/236
fake_connection
.
event
.
user_data
=
ctx
->
user_data
;
return
&
fake_connection
;
}
const
char
*
mg_version
(
void
)
{
return
MONGOOSE_VERSION
;
}
// HTTP 1.1 assumes keep alive if "Connection:" header is not set
// This function must tolerate situations when connection info is not
// set up, for example if request parsing failed.
...
...
@@ -902,11 +898,11 @@ static void send_http_error(struct mg_connection *conn, int status,
// Errors 1xx, 204 and 304 MUST NOT send a body
if
(
status
>
199
&&
status
!=
204
&&
status
!=
304
)
{
len
=
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
len
=
mg_snprintf
(
buf
,
sizeof
(
buf
),
"Error %d: %s"
,
status
,
reason
);
buf
[
len
++
]
=
'\n'
;
va_start
(
ap
,
fmt
);
len
+=
mg_vsnprintf
(
conn
,
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
len
+=
mg_vsnprintf
(
buf
+
len
,
sizeof
(
buf
)
-
len
,
fmt
,
ap
);
va_end
(
ap
);
}
DEBUG_TRACE
((
"[%s]"
,
buf
));
...
...
@@ -1293,7 +1289,7 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
}
GetFullPathNameA
(
dir
,
sizeof
(
full_dir
),
full_dir
,
NULL
);
mg_snprintf
(
c
onn
,
c
mdline
,
sizeof
(
cmdline
),
"%s%s
\"
%s
\\
%s
\"
"
,
mg_snprintf
(
cmdline
,
sizeof
(
cmdline
),
"%s%s
\"
%s
\\
%s
\"
"
,
interp
,
interp
[
0
]
==
'\0'
?
""
:
" "
,
full_dir
,
prog
);
DEBUG_TRACE
((
"Running [%s]"
,
cmdline
));
...
...
@@ -1770,12 +1766,12 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
// Using buf_len - 1 because memmove() for PATH_INFO may shift part
// of the path one byte on the right.
// If document_root is NULL, leave the file empty.
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%s%s"
,
root
,
uri
);
mg_snprintf
(
buf
,
buf_len
-
1
,
"%s%s"
,
root
,
uri
);
rewrite
=
conn
->
ctx
->
config
[
REWRITE
];
while
((
rewrite
=
next_option
(
rewrite
,
&
a
,
&
b
))
!=
NULL
)
{
if
((
match_len
=
match_prefix
(
a
.
ptr
,
a
.
len
,
uri
))
>
0
)
{
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
mg_snprintf
(
buf
,
buf_len
-
1
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
uri
+
match_len
);
break
;
}
...
...
@@ -2286,7 +2282,7 @@ static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
// Important: using local struct file to test path for is_directory flag.
// If filep is used, mg_stat() makes it appear as if auth file was opened.
}
else
if
(
mg_stat
(
path
,
&
file
)
&&
file
.
is_directory
)
{
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
mg_snprintf
(
name
,
sizeof
(
name
),
"%s%c%s"
,
path
,
'/'
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
}
else
{
...
...
@@ -2294,7 +2290,7 @@ static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
for
(
p
=
path
,
e
=
p
+
strlen
(
p
)
-
1
;
e
>
p
;
e
--
)
if
(
e
[
0
]
==
'/'
)
break
;
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%.*s%c%s"
,
mg_snprintf
(
name
,
sizeof
(
name
),
"%.*s%c%s"
,
(
int
)
(
e
-
p
),
p
,
'/'
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
}
...
...
@@ -2406,7 +2402,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
list
=
conn
->
ctx
->
config
[
PROTECT_URI
];
while
((
list
=
next_option
(
list
,
&
uri_vec
,
&
filename_vec
))
!=
NULL
)
{
if
(
!
memcmp
(
conn
->
request_info
.
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
))
{
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
mg_snprintf
(
fname
,
sizeof
(
fname
),
"%.*s"
,
(
int
)
filename_vec
.
len
,
filename_vec
.
ptr
);
if
((
fp
=
mg_fopen
(
fname
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"%s: cannot open %s: %s"
,
__func__
,
fname
,
strerror
(
errno
));
...
...
@@ -2571,20 +2567,20 @@ static void print_dir_entry(const struct de *de) {
const
char
*
slash
=
de
->
file
.
is_directory
?
"/"
:
""
;
if
(
de
->
file
.
is_directory
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
mg_snprintf
(
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
}
else
{
// We use (signed) cast below because MSVC 6 compiler cannot
// convert unsigned __int64 to double. Sigh.
if
(
de
->
file
.
size
<
1024
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%d"
,
(
int
)
de
->
file
.
size
);
mg_snprintf
(
size
,
sizeof
(
size
),
"%d"
,
(
int
)
de
->
file
.
size
);
}
else
if
(
de
->
file
.
size
<
0x100000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fk"
,
(
double
)
de
->
file
.
size
/
1024
.
0
);
}
else
if
(
de
->
file
.
size
<
0x40000000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fM"
,
(
double
)
de
->
file
.
size
/
1048576
);
}
else
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
size
,
sizeof
(
size
),
"%.1fG"
,
(
double
)
de
->
file
.
size
/
1073741824
);
}
}
...
...
@@ -2654,7 +2650,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
continue
;
}
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
...
...
@@ -2690,7 +2686,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) {
continue
;
}
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
...
...
@@ -2906,7 +2902,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
}
conn
->
status_code
=
206
;
cl
=
n
==
2
?
(
r2
>
cl
?
cl
:
r2
)
-
r1
+
1
:
cl
-
r1
;
mg_snprintf
(
conn
,
range
,
sizeof
(
range
),
mg_snprintf
(
range
,
sizeof
(
range
),
"Content-Range: bytes "
"%"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
...
...
@@ -3183,7 +3179,7 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
// Copy VARIABLE=VALUE\0 string into the free space
va_start
(
ap
,
fmt
);
n
=
mg_vsnprintf
(
block
->
conn
,
added
,
(
size_t
)
space
,
fmt
,
ap
);
n
=
mg_vsnprintf
(
added
,
(
size_t
)
space
,
fmt
,
ap
);
va_end
(
ap
);
// Make sure we do not overflow buffer and the envp array
...
...
@@ -3336,7 +3332,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
// CGI must be executed in its own directory. 'dir' must point to the
// directory containing executable program, 'p' must point to the
// executable program name relative to 'dir'.
(
void
)
mg_snprintf
(
conn
,
dir
,
sizeof
(
dir
),
"%s"
,
prog
);
(
void
)
mg_snprintf
(
dir
,
sizeof
(
dir
),
"%s"
,
prog
);
if
((
p
=
strrchr
(
dir
,
'/'
))
!=
NULL
)
{
*
p
++
=
'\0'
;
}
else
{
...
...
@@ -3589,20 +3585,20 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
// of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
if
(
sscanf
(
tag
,
" virtual=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the webserver root
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
conn
->
ctx
->
config
[
DOCUMENT_ROOT
],
'/'
,
file_name
);
}
else
if
(
sscanf
(
tag
,
" abspath=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the webserver working directory
// or it is absolute system path
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s"
,
file_name
);
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s"
,
file_name
);
}
else
if
(
sscanf
(
tag
,
" file=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
||
sscanf
(
tag
,
"
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
// File name is relative to the currect document
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s"
,
ssi
);
(
void
)
mg_snprintf
(
path
,
sizeof
(
path
),
"%s"
,
ssi
);
if
((
p
=
strrchr
(
path
,
'/'
))
!=
NULL
)
{
p
[
1
]
=
'\0'
;
}
(
void
)
mg_snprintf
(
conn
,
path
+
strlen
(
path
),
(
void
)
mg_snprintf
(
path
+
strlen
(
path
),
sizeof
(
path
)
-
strlen
(
path
),
"%s"
,
file_name
);
}
else
{
cry
(
conn
,
"Bad SSI #include: [%s]"
,
tag
);
...
...
@@ -3760,7 +3756,7 @@ static void print_dav_dir_entry(struct de *de, void *data) {
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
conn
,
href
,
sizeof
(
href
),
"%s%s"
,
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
...
...
@@ -3952,7 +3948,7 @@ void mg_websocket_handshake(struct mg_connection *conn) {
char
buf
[
100
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
SHA1_CTX
sha_ctx
;
mg_snprintf
(
conn
,
buf
,
sizeof
(
buf
),
"%s%s"
,
mg_snprintf
(
buf
,
sizeof
(
buf
),
"%s%s"
,
mg_get_header
(
conn
,
"Sec-WebSocket-Key"
),
magic
);
SHA1Init
(
&
sha_ctx
);
SHA1Update
(
&
sha_ctx
,
(
unsigned
char
*
)
buf
,
strlen
(
buf
));
...
...
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