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
557d1f4c
Commit
557d1f4c
authored
Sep 29, 2012
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added MG_OPEN_FILE message
parent
2539a473
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
379 additions
and
279 deletions
+379
-279
main.c
main.c
+6
-0
mongoose.c
mongoose.c
+317
-268
mongoose.h
mongoose.h
+15
-0
unit_test.c
test/unit_test.c
+41
-11
No files found.
main.c
View file @
557d1f4c
...
@@ -224,6 +224,12 @@ static void *mongoose_callback(enum mg_event ev, struct mg_connection *conn) {
...
@@ -224,6 +224,12 @@ static void *mongoose_callback(enum mg_event ev, struct mg_connection *conn) {
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
}
}
if
(
ev
==
MG_OPEN_FILE
&&
!
memcmp
(
mg_get_request_info
(
conn
)
->
ev_data
,
"./x"
,
3
))
{
mg_get_request_info
(
conn
)
->
ev_data
=
(
void
*
)
(
int
)
5
;
return
"hello"
;
}
// Returning NULL marks request as not handled, signalling mongoose to
// Returning NULL marks request as not handled, signalling mongoose to
// proceed with handling it.
// proceed with handling it.
return
NULL
;
return
NULL
;
...
...
mongoose.c
View file @
557d1f4c
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#else
#else
#ifdef __linux__
#ifdef __linux__
#define _XOPEN_SOURCE 600 // For flockfile() on Linux
#define _XOPEN_SOURCE 600 // For flockfile() on Linux
#endif
#endif
...
@@ -144,7 +144,6 @@ typedef DWORD pthread_t;
...
@@ -144,7 +144,6 @@ typedef DWORD pthread_t;
static
int
pthread_mutex_lock
(
pthread_mutex_t
*
);
static
int
pthread_mutex_lock
(
pthread_mutex_t
*
);
static
int
pthread_mutex_unlock
(
pthread_mutex_t
*
);
static
int
pthread_mutex_unlock
(
pthread_mutex_t
*
);
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
);
#if defined(HAVE_STDINT)
#if defined(HAVE_STDINT)
#include <stdint.h>
#include <stdint.h>
...
@@ -203,7 +202,6 @@ typedef struct DIR {
...
@@ -203,7 +202,6 @@ typedef struct DIR {
#define O_BINARY 0
#define O_BINARY 0
#endif // O_BINARY
#endif // O_BINARY
#define closesocket(a) close(a)
#define closesocket(a) close(a)
#define mg_fopen(x, y) fopen(x, y)
#define mg_mkdir(x, y) mkdir(x, y)
#define mg_mkdir(x, y) mkdir(x, y)
#define mg_remove(x) remove(x)
#define mg_remove(x) remove(x)
#define mg_rename(x, y) rename(x, y)
#define mg_rename(x, y) rename(x, y)
...
@@ -412,12 +410,14 @@ struct vec {
...
@@ -412,12 +410,14 @@ struct vec {
size_t
len
;
size_t
len
;
};
};
// Structure used by mg_stat() function. Uses 64 bit file length.
struct
file
{
struct
mgstat
{
int
is_directory
;
int
is_directory
;
// Directory marker
time_t
modification_time
;
int64_t
size
;
// File size
int64_t
size
;
time_t
mtime
;
// Modification time
FILE
*
fp
;
const
char
*
membuf
;
// Non-NULL if file data is in memory
};
};
#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL}
// Describes listening socket, or socket which was accept()-ed by the master
// Describes listening socket, or socket which was accept()-ed by the master
// thread and queued for future handling by the worker thread.
// thread and queued for future handling by the worker thread.
...
@@ -519,6 +519,41 @@ static void *call_user(struct mg_connection *conn, enum mg_event event) {
...
@@ -519,6 +519,41 @@ static void *call_user(struct mg_connection *conn, enum mg_event event) {
NULL
:
conn
->
ctx
->
user_callback
(
event
,
conn
);
NULL
:
conn
->
ctx
->
user_callback
(
event
,
conn
);
}
}
static
int
is_file_in_memory
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
conn
->
request_info
.
ev_data
=
(
void
*
)
path
;
if
((
filep
->
membuf
=
call_user
(
conn
,
MG_OPEN_FILE
))
!=
NULL
)
{
filep
->
size
=
(
int
)
conn
->
request_info
.
ev_data
;
}
return
filep
->
membuf
!=
NULL
;
}
static
int
is_file_opened
(
const
struct
file
*
filep
)
{
return
filep
->
membuf
!=
NULL
||
filep
->
fp
!=
NULL
;
}
static
int
mg_fopen
(
struct
mg_connection
*
conn
,
const
char
*
path
,
const
char
*
mode
,
struct
file
*
filep
)
{
if
(
!
is_file_in_memory
(
conn
,
path
,
filep
))
{
#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
));
filep
->
fp
=
_wfopen
(
wbuf
,
wmode
);
#else
filep
->
fp
=
fopen
(
path
,
mode
);
#endif
}
return
is_file_opened
(
filep
);
}
static
void
mg_fclose
(
struct
file
*
filep
)
{
if
(
filep
!=
NULL
&&
filep
->
fp
!=
NULL
)
{
fclose
(
filep
->
fp
);
}
}
static
int
get_option_index
(
const
char
*
name
)
{
static
int
get_option_index
(
const
char
*
name
)
{
int
i
;
int
i
;
...
@@ -577,7 +612,7 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
...
@@ -577,7 +612,7 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
conn
->
request_info
.
ev_data
=
buf
;
conn
->
request_info
.
ev_data
=
buf
;
if
(
call_user
(
conn
,
MG_EVENT_LOG
)
==
NULL
)
{
if
(
call_user
(
conn
,
MG_EVENT_LOG
)
==
NULL
)
{
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
fp
=
conn
->
ctx
==
NULL
||
conn
->
ctx
->
config
[
ERROR_LOG_FILE
]
==
NULL
?
NULL
:
mg_
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
fopen
(
conn
->
ctx
->
config
[
ERROR_LOG_FILE
],
"a+"
);
if
(
fp
!=
NULL
)
{
if
(
fp
!=
NULL
)
{
flockfile
(
fp
);
flockfile
(
fp
);
...
@@ -592,12 +627,10 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
...
@@ -592,12 +627,10 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
conn
->
request_info
.
uri
);
conn
->
request_info
.
uri
);
}
}
(
void
)
fprintf
(
fp
,
"%s"
,
buf
);
fprintf
(
fp
,
"%s"
,
buf
);
fputc
(
'\n'
,
fp
);
fputc
(
'\n'
,
fp
);
funlockfile
(
fp
);
funlockfile
(
fp
);
if
(
fp
!=
stderr
)
{
fclose
(
fp
);
fclose
(
fp
);
}
}
}
}
}
conn
->
request_info
.
ev_data
=
NULL
;
conn
->
request_info
.
ev_data
=
NULL
;
...
@@ -1077,33 +1110,23 @@ static int mg_rename(const char* oldname, const char* newname) {
...
@@ -1077,33 +1110,23 @@ static int mg_rename(const char* oldname, const char* newname) {
return
MoveFileW
(
woldbuf
,
wnewbuf
)
?
0
:
-
1
;
return
MoveFileW
(
woldbuf
,
wnewbuf
)
?
0
:
-
1
;
}
}
static
int
mg_stat
(
struct
mg_connection
*
conn
,
const
char
*
path
,
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
)
{
struct
file
*
filep
)
{
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
);
}
static
int
mg_stat
(
const
char
*
path
,
struct
mgstat
*
stp
)
{
int
ok
=
-
1
;
// Error
wchar_t
wbuf
[
PATH_MAX
];
wchar_t
wbuf
[
PATH_MAX
];
WIN32_FILE_ATTRIBUTE_DATA
info
;
WIN32_FILE_ATTRIBUTE_DATA
info
;
to_unicode
(
path
,
wbuf
,
ARRAY_SIZE
(
wbuf
));
if
(
!
is_file_in_memory
(
conn
,
path
,
filep
))
{
to_unicode
(
path
,
wbuf
,
ARRAY_SIZE
(
wbuf
));
if
(
GetFileAttributesExW
(
wbuf
,
GetFileExInfoStandard
,
&
info
)
!=
0
)
{
if
(
GetFileAttributesExW
(
wbuf
,
GetFileExInfoStandard
,
&
info
)
!=
0
)
{
st
p
->
size
=
MAKEUQUAD
(
info
.
nFileSizeLow
,
info
.
nFileSizeHigh
);
file
p
->
size
=
MAKEUQUAD
(
info
.
nFileSizeLow
,
info
.
nFileSizeHigh
);
stp
->
mtime
=
SYS2UNIX_TIME
(
info
.
ftLastWriteTime
.
dwLowDateTime
,
filep
->
modification_time
=
SYS2UNIX_TIME
(
info
.
ftLastWriteTime
.
dwHighDateTime
);
info
.
ftLastWriteTime
.
dwLowDateTime
,
stp
->
is_directory
=
info
.
ftLastWriteTime
.
dwHighDateTime
);
info
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
filep
->
is_directory
=
info
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
ok
=
0
;
// Success
}
}
}
return
ok
;
return
filep
->
membuf
!=
NULL
||
filep
->
modification_time
!=
0
;
}
}
static
int
mg_remove
(
const
char
*
path
)
{
static
int
mg_remove
(
const
char
*
path
)
{
...
@@ -1193,7 +1216,7 @@ static struct dirent *readdir(DIR *dir) {
...
@@ -1193,7 +1216,7 @@ static struct dirent *readdir(DIR *dir) {
return
result
;
return
result
;
}
}
#define set_close_on_exec(
fd
) // No FD_CLOEXEC on Windows
#define set_close_on_exec(
x
) // No FD_CLOEXEC on Windows
int
mg_start_thread
(
mg_thread_func_t
f
,
void
*
p
)
{
int
mg_start_thread
(
mg_thread_func_t
f
,
void
*
p
)
{
return
_beginthread
((
void
(
__cdecl
*
)(
void
*
))
f
,
0
,
p
)
==
-
1L
?
-
1
:
0
;
return
_beginthread
((
void
(
__cdecl
*
)(
void
*
))
f
,
0
,
p
)
==
-
1L
?
-
1
:
0
;
...
@@ -1293,24 +1316,21 @@ static int set_non_blocking_mode(SOCKET sock) {
...
@@ -1293,24 +1316,21 @@ static int set_non_blocking_mode(SOCKET sock) {
}
}
#else
#else
static
int
mg_stat
(
const
char
*
path
,
struct
mgstat
*
stp
)
{
static
int
mg_stat
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
struct
stat
st
;
struct
stat
st
;
int
ok
;
if
(
stat
(
path
,
&
st
)
==
0
)
{
if
(
!
is_file_in_memory
(
conn
,
path
,
filep
)
&&
!
stat
(
path
,
&
st
))
{
ok
=
0
;
filep
->
size
=
st
.
st_size
;
stp
->
size
=
st
.
st_size
;
filep
->
modification_time
=
st
.
st_mtime
;
stp
->
mtime
=
st
.
st_mtime
;
filep
->
is_directory
=
S_ISDIR
(
st
.
st_mode
);
stp
->
is_directory
=
S_ISDIR
(
st
.
st_mode
);
}
else
{
ok
=
-
1
;
}
}
return
ok
;
return
filep
->
membuf
!=
NULL
||
filep
->
modification_time
!=
(
time_t
)
0
;
}
}
static
void
set_close_on_exec
(
int
fd
)
{
static
void
set_close_on_exec
(
int
fd
)
{
(
void
)
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
);
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
);
}
}
int
mg_start_thread
(
mg_thread_func_t
func
,
void
*
param
)
{
int
mg_start_thread
(
mg_thread_func_t
func
,
void
*
param
)
{
...
@@ -1691,35 +1711,35 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
...
@@ -1691,35 +1711,35 @@ int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
return
len
;
return
len
;
}
}
static
int
convert_uri_to_file_name
(
struct
mg_connection
*
conn
,
char
*
buf
,
static
void
convert_uri_to_file_name
(
struct
mg_connection
*
conn
,
char
*
buf
,
size_t
buf_len
,
struct
mgstat
*
st
)
{
size_t
buf_len
,
struct
file
*
filep
)
{
struct
vec
a
,
b
;
struct
vec
a
,
b
;
const
char
*
rewrite
,
*
uri
=
conn
->
request_info
.
uri
;
const
char
*
rewrite
,
*
uri
=
conn
->
request_info
.
uri
;
char
*
p
;
char
*
p
;
int
match_len
,
stat_result
;
int
match_len
;
buf_len
--
;
// This is
because memmove() for PATH_INFO may shift part
// Using buf_len - 1
because memmove() for PATH_INFO may shift part
// of the path one byte on the right.
// of the path one byte on the right.
mg_snprintf
(
conn
,
buf
,
buf_len
,
"%s%s"
,
conn
->
ctx
->
config
[
DOCUMENT_ROOT
],
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%s%s"
,
conn
->
ctx
->
config
[
DOCUMENT_ROOT
],
uri
);
uri
);
rewrite
=
conn
->
ctx
->
config
[
REWRITE
];
rewrite
=
conn
->
ctx
->
config
[
REWRITE
];
while
((
rewrite
=
next_option
(
rewrite
,
&
a
,
&
b
))
!=
NULL
)
{
while
((
rewrite
=
next_option
(
rewrite
,
&
a
,
&
b
))
!=
NULL
)
{
if
((
match_len
=
match_prefix
(
a
.
ptr
,
a
.
len
,
uri
))
>
0
)
{
if
((
match_len
=
match_prefix
(
a
.
ptr
,
a
.
len
,
uri
))
>
0
)
{
mg_snprintf
(
conn
,
buf
,
buf_len
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
mg_snprintf
(
conn
,
buf
,
buf_len
-
1
,
"%.*s%s"
,
(
int
)
b
.
len
,
b
.
ptr
,
uri
+
match_len
);
uri
+
match_len
);
break
;
break
;
}
}
}
}
if
(
(
stat_result
=
mg_stat
(
buf
,
st
))
!=
0
)
{
if
(
!
mg_stat
(
conn
,
buf
,
filep
)
)
{
// Support PATH_INFO for CGI scripts.
// Support PATH_INFO for CGI scripts.
for
(
p
=
buf
+
strlen
(
buf
);
p
>
buf
+
1
;
p
--
)
{
for
(
p
=
buf
+
strlen
(
buf
);
p
>
buf
+
1
;
p
--
)
{
if
(
*
p
==
'/'
)
{
if
(
*
p
==
'/'
)
{
*
p
=
'\0'
;
*
p
=
'\0'
;
if
(
match_prefix
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
],
if
(
match_prefix
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
],
strlen
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
]),
buf
)
>
0
&&
strlen
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
]),
buf
)
>
0
&&
(
stat_result
=
mg_stat
(
buf
,
st
))
==
0
)
{
mg_stat
(
conn
,
buf
,
filep
)
)
{
// Shift PATH_INFO block one character right, e.g.
// Shift PATH_INFO block one character right, e.g.
// "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
// "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
// conn->path_info is pointing to the local variable "path" declared
// conn->path_info is pointing to the local variable "path" declared
...
@@ -1731,13 +1751,10 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
...
@@ -1731,13 +1751,10 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
break
;
break
;
}
else
{
}
else
{
*
p
=
'/'
;
*
p
=
'/'
;
stat_result
=
-
1
;
}
}
}
}
}
}
}
}
return
stat_result
;
}
}
static
int
sslize
(
struct
mg_connection
*
conn
,
SSL_CTX
*
s
,
int
(
*
func
)(
SSL
*
))
{
static
int
sslize
(
struct
mg_connection
*
conn
,
SSL_CTX
*
s
,
int
(
*
func
)(
SSL
*
))
{
...
@@ -2179,34 +2196,29 @@ static int check_password(const char *method, const char *ha1, const char *uri,
...
@@ -2179,34 +2196,29 @@ static int check_password(const char *method, const char *ha1, const char *uri,
// Use the global passwords file, if specified by auth_gpass option,
// Use the global passwords file, if specified by auth_gpass option,
// or search for .htpasswd in the requested directory.
// or search for .htpasswd in the requested directory.
static
FILE
*
open_auth_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
static
void
open_auth_file
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
mg_context
*
ctx
=
conn
->
ctx
;
struct
file
*
filep
)
{
char
name
[
PATH_MAX
];
char
name
[
PATH_MAX
];
const
char
*
p
,
*
e
;
const
char
*
p
,
*
e
,
*
gpass
=
conn
->
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
];
struct
mgstat
st
;
FILE
*
fp
;
if
(
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
]
!=
NULL
)
{
if
(
gpass
!=
NULL
)
{
// Use global passwords file
// Use global passwords file
fp
=
mg_fopen
(
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
],
"r"
);
if
(
!
mg_fopen
(
conn
,
gpass
,
"r"
,
filep
))
{
if
(
fp
==
NULL
)
cry
(
conn
,
"fopen(%s): %s"
,
gpass
,
strerror
(
ERRNO
));
cry
(
fc
(
ctx
),
"fopen(%s): %s"
,
}
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
],
strerror
(
ERRNO
));
}
else
if
(
mg_stat
(
conn
,
path
,
filep
)
&&
filep
->
is_directory
)
{
}
else
if
(
!
mg_stat
(
path
,
&
st
)
&&
st
.
is_directory
)
{
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
(
void
)
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
path
,
'/'
,
PASSWORDS_FILE_NAME
);
path
,
'/'
,
PASSWORDS_FILE_NAME
);
mg_fopen
(
conn
,
name
,
"r"
,
filep
);
fp
=
mg_fopen
(
name
,
"r"
);
}
else
{
}
else
{
// Try to find .htpasswd in requested directory.
// Try to find .htpasswd in requested directory.
for
(
p
=
path
,
e
=
p
+
strlen
(
p
)
-
1
;
e
>
p
;
e
--
)
for
(
p
=
path
,
e
=
p
+
strlen
(
p
)
-
1
;
e
>
p
;
e
--
)
if
(
e
[
0
]
==
'/'
)
if
(
e
[
0
]
==
'/'
)
break
;
break
;
(
void
)
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%.*s%c%s"
,
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%.*s%c%s"
,
(
int
)
(
e
-
p
),
p
,
'/'
,
PASSWORDS_FILE_NAME
);
(
int
)
(
e
-
p
),
p
,
'/'
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
mg_fopen
(
conn
,
name
,
"r"
,
filep
);
}
}
return
fp
;
}
}
// Parsed Authorization header
// Parsed Authorization header
...
@@ -2278,17 +2290,36 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
...
@@ -2278,17 +2290,36 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
return
1
;
return
1
;
}
}
static
char
*
mg_fgets
(
char
*
buf
,
size_t
size
,
struct
file
*
filep
,
char
**
p
)
{
char
*
eof
;
size_t
len
;
if
(
filep
->
membuf
!=
NULL
&&
*
p
!=
NULL
)
{
eof
=
memchr
(
*
p
,
'\n'
,
&
filep
->
membuf
[
filep
->
size
]
-
*
p
);
len
=
(
size_t
)
(
eof
-
*
p
)
>
size
-
1
?
size
-
1
:
(
size_t
)
(
eof
-
*
p
);
memcpy
(
buf
,
*
p
,
len
);
buf
[
len
]
=
'\0'
;
*
p
=
eof
;
return
eof
;
}
else
if
(
filep
->
fp
!=
NULL
)
{
return
fgets
(
buf
,
size
,
filep
->
fp
);
}
else
{
return
NULL
;
}
}
// Authorize against the opened passwords file. Return 1 if authorized.
// Authorize against the opened passwords file. Return 1 if authorized.
static
int
authorize
(
struct
mg_connection
*
conn
,
FILE
*
f
p
)
{
static
int
authorize
(
struct
mg_connection
*
conn
,
struct
file
*
file
p
)
{
struct
ah
ah
;
struct
ah
ah
;
char
line
[
256
],
f_user
[
256
],
ha1
[
256
],
f_domain
[
256
],
buf
[
MG_BUF_LEN
];
char
line
[
256
],
f_user
[
256
],
ha1
[
256
],
f_domain
[
256
],
buf
[
MG_BUF_LEN
]
,
*
p
;
if
(
!
parse_auth_header
(
conn
,
buf
,
sizeof
(
buf
),
&
ah
))
{
if
(
!
parse_auth_header
(
conn
,
buf
,
sizeof
(
buf
),
&
ah
))
{
return
0
;
return
0
;
}
}
// Loop over passwords file
// Loop over passwords file
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
p
=
(
char
*
)
filep
->
membuf
;
while
(
mg_fgets
(
line
,
sizeof
(
line
),
filep
,
&
p
)
!=
NULL
)
{
if
(
sscanf
(
line
,
"%[^:]:%[^:]:%s"
,
f_user
,
f_domain
,
ha1
)
!=
3
)
{
if
(
sscanf
(
line
,
"%[^:]:%[^:]:%s"
,
f_user
,
f_domain
,
ha1
)
!=
3
)
{
continue
;
continue
;
}
}
...
@@ -2304,34 +2335,31 @@ static int authorize(struct mg_connection *conn, FILE *fp) {
...
@@ -2304,34 +2335,31 @@ static int authorize(struct mg_connection *conn, FILE *fp) {
// Return 1 if request is authorised, 0 otherwise.
// Return 1 if request is authorised, 0 otherwise.
static
int
check_authorization
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
static
int
check_authorization
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
FILE
*
fp
;
char
fname
[
PATH_MAX
];
char
fname
[
PATH_MAX
];
struct
vec
uri_vec
,
filename_vec
;
struct
vec
uri_vec
,
filename_vec
;
const
char
*
list
;
const
char
*
list
;
int
authorized
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
int
authorized
=
1
;
fp
=
NULL
;
authorized
=
1
;
list
=
conn
->
ctx
->
config
[
PROTECT_URI
];
list
=
conn
->
ctx
->
config
[
PROTECT_URI
];
while
((
list
=
next_option
(
list
,
&
uri_vec
,
&
filename_vec
))
!=
NULL
)
{
while
((
list
=
next_option
(
list
,
&
uri_vec
,
&
filename_vec
))
!=
NULL
)
{
if
(
!
memcmp
(
conn
->
request_info
.
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
))
{
if
(
!
memcmp
(
conn
->
request_info
.
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
))
{
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
(
int
)
filename_vec
.
len
,
filename_vec
.
ptr
);
(
int
)
filename_vec
.
len
,
filename_vec
.
ptr
);
if
(
(
fp
=
mg_fopen
(
fname
,
"r"
))
==
NULL
)
{
if
(
!
mg_fopen
(
conn
,
fname
,
"r"
,
&
file
)
)
{
cry
(
conn
,
"%s: cannot open %s: %s"
,
__func__
,
fname
,
strerror
(
errno
));
cry
(
conn
,
"%s: cannot open %s: %s"
,
__func__
,
fname
,
strerror
(
errno
));
}
}
break
;
break
;
}
}
}
}
if
(
fp
==
NULL
)
{
if
(
!
is_file_opened
(
&
file
)
)
{
fp
=
open_auth_file
(
conn
,
path
);
open_auth_file
(
conn
,
path
,
&
file
);
}
}
if
(
fp
!=
NULL
)
{
if
(
is_file_opened
(
&
file
)
)
{
authorized
=
authorize
(
conn
,
fp
);
authorized
=
authorize
(
conn
,
&
file
);
(
void
)
fclose
(
fp
);
mg_fclose
(
&
file
);
}
}
return
authorized
;
return
authorized
;
...
@@ -2339,25 +2367,23 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
...
@@ -2339,25 +2367,23 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
static
void
send_authorization_request
(
struct
mg_connection
*
conn
)
{
static
void
send_authorization_request
(
struct
mg_connection
*
conn
)
{
conn
->
status_code
=
401
;
conn
->
status_code
=
401
;
(
void
)
mg_printf
(
conn
,
mg_printf
(
conn
,
"HTTP/1.1 401 Unauthorized
\r\n
"
"HTTP/1.1 401 Unauthorized
\r\n
"
"Content-Length: 0
\r\n
"
"Content-Length: 0
\r\n
"
"WWW-Authenticate: Digest qop=
\"
auth
\"
, "
"WWW-Authenticate: Digest qop=
\"
auth
\"
, "
"realm=
\"
%s
\"
, nonce=
\"
%lu
\"\r\n\r\n
"
,
"realm=
\"
%s
\"
, nonce=
\"
%lu
\"\r\n\r\n
"
,
conn
->
ctx
->
config
[
AUTHENTICATION_DOMAIN
],
conn
->
ctx
->
config
[
AUTHENTICATION_DOMAIN
],
(
unsigned
long
)
time
(
NULL
));
(
unsigned
long
)
time
(
NULL
));
}
}
static
int
is_authorized_for_put
(
struct
mg_connection
*
conn
)
{
static
int
is_authorized_for_put
(
struct
mg_connection
*
conn
)
{
FILE
*
fp
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
const
char
*
passfile
=
conn
->
ctx
->
config
[
PUT_DELETE_PASSWORDS_FILE
];
int
ret
=
0
;
int
ret
=
0
;
fp
=
conn
->
ctx
->
config
[
PUT_DELETE_PASSWORDS_FILE
]
==
NULL
?
NULL
:
if
(
passfile
!=
NULL
&&
mg_fopen
(
conn
,
passfile
,
"r"
,
&
file
))
{
mg_fopen
(
conn
->
ctx
->
config
[
PUT_DELETE_PASSWORDS_FILE
],
"r"
);
ret
=
authorize
(
conn
,
&
file
);
mg_fclose
(
&
file
);
if
(
fp
!=
NULL
)
{
ret
=
authorize
(
conn
,
fp
);
(
void
)
fclose
(
fp
);
}
}
return
ret
;
return
ret
;
...
@@ -2380,14 +2406,14 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
...
@@ -2380,14 +2406,14 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
(
void
)
snprintf
(
tmp
,
sizeof
(
tmp
),
"%s.tmp"
,
fname
);
(
void
)
snprintf
(
tmp
,
sizeof
(
tmp
),
"%s.tmp"
,
fname
);
// Create the file if does not exist
// Create the file if does not exist
if
((
fp
=
mg_
fopen
(
fname
,
"a+"
))
!=
NULL
)
{
if
((
fp
=
fopen
(
fname
,
"a+"
))
!=
NULL
)
{
(
void
)
fclose
(
fp
);
(
void
)
fclose
(
fp
);
}
}
// Open the given file and temporary file
// Open the given file and temporary file
if
((
fp
=
mg_
fopen
(
fname
,
"r"
))
==
NULL
)
{
if
((
fp
=
fopen
(
fname
,
"r"
))
==
NULL
)
{
return
0
;
return
0
;
}
else
if
((
fp2
=
mg_
fopen
(
tmp
,
"w+"
))
==
NULL
)
{
}
else
if
((
fp2
=
fopen
(
tmp
,
"w+"
))
==
NULL
)
{
fclose
(
fp
);
fclose
(
fp
);
return
0
;
return
0
;
}
}
...
@@ -2405,23 +2431,23 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
...
@@ -2405,23 +2431,23 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
fprintf
(
fp2
,
"%s:%s:%s
\n
"
,
user
,
domain
,
ha1
);
fprintf
(
fp2
,
"%s:%s:%s
\n
"
,
user
,
domain
,
ha1
);
}
}
}
else
{
}
else
{
(
void
)
fprintf
(
fp2
,
"%s"
,
line
);
fprintf
(
fp2
,
"%s"
,
line
);
}
}
}
}
// If new user, just add it
// If new user, just add it
if
(
!
found
&&
pass
!=
NULL
)
{
if
(
!
found
&&
pass
!=
NULL
)
{
mg_md5
(
ha1
,
user
,
":"
,
domain
,
":"
,
pass
,
NULL
);
mg_md5
(
ha1
,
user
,
":"
,
domain
,
":"
,
pass
,
NULL
);
(
void
)
fprintf
(
fp2
,
"%s:%s:%s
\n
"
,
user
,
domain
,
ha1
);
fprintf
(
fp2
,
"%s:%s:%s
\n
"
,
user
,
domain
,
ha1
);
}
}
// Close files
// Close files
(
void
)
fclose
(
fp
);
fclose
(
fp
);
(
void
)
fclose
(
fp2
);
fclose
(
fp2
);
// Put the temp file in place of real file
// Put the temp file in place of real file
(
void
)
mg_
remove
(
fname
);
remove
(
fname
);
(
void
)
mg_
rename
(
tmp
,
fname
);
rename
(
tmp
,
fname
);
return
1
;
return
1
;
}
}
...
@@ -2429,7 +2455,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
...
@@ -2429,7 +2455,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
struct
de
{
struct
de
{
struct
mg_connection
*
conn
;
struct
mg_connection
*
conn
;
char
*
file_name
;
char
*
file_name
;
struct
mgstat
st
;
struct
file
file
;
};
};
static
void
url_encode
(
const
char
*
src
,
char
*
dst
,
size_t
dst_len
)
{
static
void
url_encode
(
const
char
*
src
,
char
*
dst
,
size_t
dst_len
)
{
...
@@ -2455,32 +2481,32 @@ static void url_encode(const char *src, char *dst, size_t dst_len) {
...
@@ -2455,32 +2481,32 @@ static void url_encode(const char *src, char *dst, size_t dst_len) {
static
void
print_dir_entry
(
struct
de
*
de
)
{
static
void
print_dir_entry
(
struct
de
*
de
)
{
char
size
[
64
],
mod
[
64
],
href
[
PATH_MAX
];
char
size
[
64
],
mod
[
64
],
href
[
PATH_MAX
];
if
(
de
->
st
.
is_directory
)
{
if
(
de
->
file
.
is_directory
)
{
(
void
)
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%s"
,
"[DIRECTORY]"
);
}
else
{
}
else
{
// We use (signed) cast below because MSVC 6 compiler cannot
// We use (signed) cast below because MSVC 6 compiler cannot
// convert unsigned __int64 to double. Sigh.
// convert unsigned __int64 to double. Sigh.
if
(
de
->
st
.
size
<
1024
)
{
if
(
de
->
file
.
size
<
1024
)
{
(
void
)
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%d"
,
(
int
)
de
->
file
.
size
);
"%lu"
,
(
unsigned
long
)
de
->
st
.
size
);
}
else
if
(
de
->
file
.
size
<
0x100000
)
{
}
else
if
(
de
->
st
.
size
<
0x100000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
(
void
)
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%.1fk"
,
(
double
)
de
->
file
.
size
/
1024
.
0
);
"%.1fk"
,
(
double
)
de
->
st
.
size
/
1024
.
0
);
}
else
if
(
de
->
file
.
size
<
0x40000000
)
{
}
else
if
(
de
->
st
.
size
<
0x40000000
)
{
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
(
void
)
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%.1fM"
,
(
double
)
de
->
file
.
size
/
1048576
);
"%.1fM"
,
(
double
)
de
->
st
.
size
/
1048576
);
}
else
{
}
else
{
(
void
)
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
mg_snprintf
(
de
->
conn
,
size
,
sizeof
(
size
),
"%.1fG"
,
(
double
)
de
->
st
.
size
/
1073741824
);
"%.1fG"
,
(
double
)
de
->
file
.
size
/
1073741824
);
}
}
}
}
(
void
)
strftime
(
mod
,
sizeof
(
mod
),
"%d-%b-%Y %H:%M"
,
localtime
(
&
de
->
st
.
mtime
));
strftime
(
mod
,
sizeof
(
mod
),
"%d-%b-%Y %H:%M"
,
localtime
(
&
de
->
file
.
modification_time
));
url_encode
(
de
->
file_name
,
href
,
sizeof
(
href
));
url_encode
(
de
->
file_name
,
href
,
sizeof
(
href
));
de
->
conn
->
num_bytes_sent
+=
mg_printf
(
de
->
conn
,
de
->
conn
->
num_bytes_sent
+=
mg_printf
(
de
->
conn
,
"<tr><td><a href=
\"
%s%s%s
\"
>%s%s</a></td>"
"<tr><td><a href=
\"
%s%s%s
\"
>%s%s</a></td>"
"<td> %s</td><td> %s</td></tr>
\n
"
,
"<td> %s</td><td> %s</td></tr>
\n
"
,
de
->
conn
->
request_info
.
uri
,
href
,
de
->
st
.
is_directory
?
"/"
:
""
,
de
->
conn
->
request_info
.
uri
,
href
,
de
->
file
.
is_directory
?
"/"
:
""
,
de
->
file_name
,
de
->
st
.
is_directory
?
"/"
:
""
,
mod
,
size
);
de
->
file_name
,
de
->
file
.
is_directory
?
"/"
:
""
,
mod
,
size
);
}
}
// This function is called from send_directory() and used for
// This function is called from send_directory() and used for
...
@@ -2496,18 +2522,18 @@ static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
...
@@ -2496,18 +2522,18 @@ static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
query_string
=
"na"
;
query_string
=
"na"
;
}
}
if
(
a
->
st
.
is_directory
&&
!
b
->
st
.
is_directory
)
{
if
(
a
->
file
.
is_directory
&&
!
b
->
file
.
is_directory
)
{
return
-
1
;
// Always put directories on top
return
-
1
;
// Always put directories on top
}
else
if
(
!
a
->
st
.
is_directory
&&
b
->
st
.
is_directory
)
{
}
else
if
(
!
a
->
file
.
is_directory
&&
b
->
file
.
is_directory
)
{
return
1
;
// Always put directories on top
return
1
;
// Always put directories on top
}
else
if
(
*
query_string
==
'n'
)
{
}
else
if
(
*
query_string
==
'n'
)
{
cmp_result
=
strcmp
(
a
->
file_name
,
b
->
file_name
);
cmp_result
=
strcmp
(
a
->
file_name
,
b
->
file_name
);
}
else
if
(
*
query_string
==
's'
)
{
}
else
if
(
*
query_string
==
's'
)
{
cmp_result
=
a
->
st
.
size
==
b
->
st
.
size
?
0
:
cmp_result
=
a
->
file
.
size
==
b
->
file
.
size
?
0
:
a
->
st
.
size
>
b
->
st
.
size
?
1
:
-
1
;
a
->
file
.
size
>
b
->
file
.
size
?
1
:
-
1
;
}
else
if
(
*
query_string
==
'd'
)
{
}
else
if
(
*
query_string
==
'd'
)
{
cmp_result
=
a
->
st
.
mtime
==
b
->
st
.
m
time
?
0
:
cmp_result
=
a
->
file
.
modification_time
==
b
->
file
.
modification_
time
?
0
:
a
->
st
.
mtime
>
b
->
st
.
m
time
?
1
:
-
1
;
a
->
file
.
modification_time
>
b
->
file
.
modification_
time
?
1
:
-
1
;
}
}
return
query_string
[
1
]
==
'd'
?
-
cmp_result
:
cmp_result
;
return
query_string
[
1
]
==
'd'
?
-
cmp_result
:
cmp_result
;
...
@@ -2547,11 +2573,10 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
...
@@ -2547,11 +2573,10 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
// print_dir_entry(). memset is required only if mg_stat()
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
// http://code.google.com/p/mongoose/issues/detail?id=79
if
(
mg_stat
(
path
,
&
de
.
st
)
!=
0
)
{
// mg_stat will memset the whole struct file with zeroes.
memset
(
&
de
.
st
,
0
,
sizeof
(
de
.
st
));
mg_stat
(
conn
,
path
,
&
de
.
file
);
}
de
.
file_name
=
dp
->
d_name
;
de
.
file_name
=
dp
->
d_name
;
cb
(
&
de
,
data
);
cb
(
&
de
,
data
);
}
}
(
void
)
closedir
(
dirp
);
(
void
)
closedir
(
dirp
);
...
@@ -2578,7 +2603,7 @@ static void dir_scan_callback(struct de *de, void *data) {
...
@@ -2578,7 +2603,7 @@ static void dir_scan_callback(struct de *de, void *data) {
dsd
->
num_entries
=
0
;
dsd
->
num_entries
=
0
;
}
else
{
}
else
{
dsd
->
entries
[
dsd
->
num_entries
].
file_name
=
mg_strdup
(
de
->
file_name
);
dsd
->
entries
[
dsd
->
num_entries
].
file_name
=
mg_strdup
(
de
->
file_name
);
dsd
->
entries
[
dsd
->
num_entries
].
st
=
de
->
st
;
dsd
->
entries
[
dsd
->
num_entries
].
file
=
de
->
file
;
dsd
->
entries
[
dsd
->
num_entries
].
conn
=
de
->
conn
;
dsd
->
entries
[
dsd
->
num_entries
].
conn
=
de
->
conn
;
dsd
->
num_entries
++
;
dsd
->
num_entries
++
;
}
}
...
@@ -2635,30 +2660,39 @@ static void handle_directory_request(struct mg_connection *conn,
...
@@ -2635,30 +2660,39 @@ static void handle_directory_request(struct mg_connection *conn,
}
}
// Send len bytes from the opened file to the client.
// Send len bytes from the opened file to the client.
static
void
send_file_data
(
struct
mg_connection
*
conn
,
FILE
*
fp
,
int64_t
len
)
{
static
void
send_file_data
(
struct
mg_connection
*
conn
,
struct
file
*
filep
,
int64_t
offset
,
int64_t
len
)
{
char
buf
[
MG_BUF_LEN
];
char
buf
[
MG_BUF_LEN
];
int
to_read
,
num_read
,
num_written
;
int
to_read
,
num_read
,
num_written
;
while
(
len
>
0
)
{
if
(
len
>
0
&&
filep
->
membuf
!=
NULL
&&
filep
->
size
>
0
)
{
// Calculate how much to read from the file in the buffer
if
(
len
>
filep
->
size
-
offset
)
{
to_read
=
sizeof
(
buf
);
len
=
filep
->
size
-
offset
;
if
((
int64_t
)
to_read
>
len
)
{
to_read
=
(
int
)
len
;
}
}
mg_write
(
conn
,
filep
->
membuf
+
offset
,
len
);
}
else
if
(
len
>
0
&&
filep
->
fp
!=
NULL
)
{
fseeko
(
filep
->
fp
,
offset
,
SEEK_SET
);
while
(
len
>
0
)
{
// Calculate how much to read from the file in the buffer
to_read
=
sizeof
(
buf
);
if
((
int64_t
)
to_read
>
len
)
{
to_read
=
(
int
)
len
;
}
// Read from file, exit the loop on error
// Read from file, exit the loop on error
if
((
num_read
=
fread
(
buf
,
1
,
(
size_t
)
to_read
,
fp
))
<=
0
)
{
if
((
num_read
=
fread
(
buf
,
1
,
(
size_t
)
to_read
,
filep
->
fp
))
<=
0
)
{
break
;
break
;
}
}
// Send read bytes to the client, exit the loop on error
// Send read bytes to the client, exit the loop on error
if
((
num_written
=
mg_write
(
conn
,
buf
,
(
size_t
)
num_read
))
!=
num_read
)
{
if
((
num_written
=
mg_write
(
conn
,
buf
,
(
size_t
)
num_read
))
!=
num_read
)
{
break
;
break
;
}
}
// Both read and were successful, adjust counters
// Both read and were successful, adjust counters
conn
->
num_bytes_sent
+=
num_written
;
conn
->
num_bytes_sent
+=
num_written
;
len
-=
num_written
;
len
-=
num_written
;
}
}
}
}
}
...
@@ -2671,53 +2705,58 @@ static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
...
@@ -2671,53 +2705,58 @@ static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
}
}
static
void
construct_etag
(
char
*
buf
,
size_t
buf_len
,
static
void
construct_etag
(
char
*
buf
,
size_t
buf_len
,
const
struct
mgstat
*
st
p
)
{
const
struct
file
*
file
p
)
{
snprintf
(
buf
,
buf_len
,
"
\"
%lx.%"
INT64_FMT
"
\"
"
,
snprintf
(
buf
,
buf_len
,
"
\"
%lx.%"
INT64_FMT
"
\"
"
,
(
unsigned
long
)
stp
->
mtime
,
stp
->
size
);
(
unsigned
long
)
filep
->
modification_time
,
filep
->
size
);
}
static
void
fclose_on_exec
(
struct
file
*
filep
)
{
if
(
filep
!=
NULL
&&
filep
->
fp
!=
NULL
)
{
fcntl
(
fileno
(
filep
->
fp
),
F_SETFD
,
FD_CLOEXEC
);
}
}
}
static
void
handle_file_request
(
struct
mg_connection
*
conn
,
const
char
*
path
,
static
void
handle_file_request
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
mgstat
*
st
p
)
{
struct
file
*
file
p
)
{
char
date
[
64
],
lm
[
64
],
etag
[
64
],
range
[
64
];
char
date
[
64
],
lm
[
64
],
etag
[
64
],
range
[
64
];
const
char
*
msg
=
"OK"
,
*
hdr
;
const
char
*
msg
=
"OK"
,
*
hdr
;
time_t
curtime
=
time
(
NULL
);
time_t
curtime
=
time
(
NULL
);
int64_t
cl
,
r1
,
r2
;
int64_t
cl
,
r1
,
r2
;
struct
vec
mime_vec
;
struct
vec
mime_vec
;
FILE
*
fp
;
int
n
;
int
n
;
get_mime_type
(
conn
->
ctx
,
path
,
&
mime_vec
);
get_mime_type
(
conn
->
ctx
,
path
,
&
mime_vec
);
cl
=
st
p
->
size
;
cl
=
file
p
->
size
;
conn
->
status_code
=
200
;
conn
->
status_code
=
200
;
range
[
0
]
=
'\0'
;
range
[
0
]
=
'\0'
;
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
filep
)
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
return
;
return
;
}
}
set_close_on_exec
(
fileno
(
fp
)
);
fclose_on_exec
(
filep
);
// If Range: header specified, act accordingly
// If Range: header specified, act accordingly
r1
=
r2
=
0
;
r1
=
r2
=
0
;
hdr
=
mg_get_header
(
conn
,
"Range"
);
hdr
=
mg_get_header
(
conn
,
"Range"
);
if
(
hdr
!=
NULL
&&
(
n
=
parse_range_header
(
hdr
,
&
r1
,
&
r2
))
>
0
)
{
if
(
hdr
!=
NULL
&&
(
n
=
parse_range_header
(
hdr
,
&
r1
,
&
r2
))
>
0
&&
r1
>=
0
&&
r2
>
0
)
{
conn
->
status_code
=
206
;
conn
->
status_code
=
206
;
(
void
)
fseeko
(
fp
,
r1
,
SEEK_SET
);
cl
=
n
==
2
?
(
r2
>
cl
?
cl
:
r2
)
-
r1
+
1
:
cl
-
r1
;
cl
=
n
==
2
?
r2
-
r1
+
1
:
cl
-
r1
;
mg_snprintf
(
conn
,
range
,
sizeof
(
range
),
(
void
)
mg_snprintf
(
conn
,
range
,
sizeof
(
range
),
"Content-Range: bytes "
"Content-Range: bytes "
"%"
INT64_FMT
"-%"
"%"
INT64_FMT
"-%"
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
INT64_FMT
"/%"
INT64_FMT
"
\r\n
"
,
r1
,
r1
+
cl
-
1
,
filep
->
size
);
r1
,
r1
+
cl
-
1
,
stp
->
size
);
msg
=
"Partial Content"
;
msg
=
"Partial Content"
;
}
}
// Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
// Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
gmt_time_string
(
date
,
sizeof
(
date
),
&
curtime
);
gmt_time_string
(
date
,
sizeof
(
date
),
&
curtime
);
gmt_time_string
(
lm
,
sizeof
(
lm
),
&
stp
->
m
time
);
gmt_time_string
(
lm
,
sizeof
(
lm
),
&
filep
->
modification_
time
);
construct_etag
(
etag
,
sizeof
(
etag
),
st
p
);
construct_etag
(
etag
,
sizeof
(
etag
),
file
p
);
(
void
)
mg_printf
(
conn
,
(
void
)
mg_printf
(
conn
,
"HTTP/1.1 %d %s
\r\n
"
"HTTP/1.1 %d %s
\r\n
"
...
@@ -2733,15 +2772,15 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
...
@@ -2733,15 +2772,15 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
mime_vec
.
ptr
,
cl
,
suggest_connection_header
(
conn
),
range
);
mime_vec
.
ptr
,
cl
,
suggest_connection_header
(
conn
),
range
);
if
(
strcmp
(
conn
->
request_info
.
request_method
,
"HEAD"
)
!=
0
)
{
if
(
strcmp
(
conn
->
request_info
.
request_method
,
"HEAD"
)
!=
0
)
{
send_file_data
(
conn
,
f
p
,
cl
);
send_file_data
(
conn
,
f
ilep
,
r1
,
cl
);
}
}
(
void
)
fclose
(
f
p
);
mg_fclose
(
file
p
);
}
}
void
mg_send_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
void
mg_send_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
struct
mgstat
st
;
struct
file
file
;
if
(
mg_stat
(
path
,
&
st
)
==
0
)
{
if
(
mg_stat
(
conn
,
path
,
&
file
)
)
{
handle_file_request
(
conn
,
path
,
&
st
);
handle_file_request
(
conn
,
path
,
&
file
);
}
else
{
}
else
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
}
}
...
@@ -2839,9 +2878,9 @@ static int read_request(FILE *fp, struct mg_connection *conn,
...
@@ -2839,9 +2878,9 @@ static int read_request(FILE *fp, struct mg_connection *conn,
// Return 0 if index file has been found, -1 if not found.
// Return 0 if index file has been found, -1 if not found.
// If the file is found, it's stats is returned in stp.
// If the file is found, it's stats is returned in stp.
static
int
substitute_index_file
(
struct
mg_connection
*
conn
,
char
*
path
,
static
int
substitute_index_file
(
struct
mg_connection
*
conn
,
char
*
path
,
size_t
path_len
,
struct
mgstat
*
st
p
)
{
size_t
path_len
,
struct
file
*
file
p
)
{
const
char
*
list
=
conn
->
ctx
->
config
[
INDEX_FILES
];
const
char
*
list
=
conn
->
ctx
->
config
[
INDEX_FILES
];
struct
mgstat
st
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
struct
vec
filename_vec
;
struct
vec
filename_vec
;
size_t
n
=
strlen
(
path
);
size_t
n
=
strlen
(
path
);
int
found
=
0
;
int
found
=
0
;
...
@@ -2863,12 +2902,12 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
...
@@ -2863,12 +2902,12 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
continue
;
continue
;
// Prepare full path to the index file
// Prepare full path to the index file
(
void
)
mg_strlcpy
(
path
+
n
+
1
,
filename_vec
.
ptr
,
filename_vec
.
len
+
1
);
mg_strlcpy
(
path
+
n
+
1
,
filename_vec
.
ptr
,
filename_vec
.
len
+
1
);
// Does it exist?
// Does it exist?
if
(
mg_stat
(
path
,
&
st
)
==
0
)
{
if
(
mg_stat
(
conn
,
path
,
&
file
)
)
{
// Yes it does, break the loop
// Yes it does, break the loop
*
stp
=
st
;
*
filep
=
file
;
found
=
1
;
found
=
1
;
break
;
break
;
}
}
...
@@ -2884,13 +2923,13 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
...
@@ -2884,13 +2923,13 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
// Return True if we should reply 304 Not Modified.
// Return True if we should reply 304 Not Modified.
static
int
is_not_modified
(
const
struct
mg_connection
*
conn
,
static
int
is_not_modified
(
const
struct
mg_connection
*
conn
,
const
struct
mgstat
*
st
p
)
{
const
struct
file
*
file
p
)
{
char
etag
[
64
];
char
etag
[
64
];
const
char
*
ims
=
mg_get_header
(
conn
,
"If-Modified-Since"
);
const
char
*
ims
=
mg_get_header
(
conn
,
"If-Modified-Since"
);
const
char
*
inm
=
mg_get_header
(
conn
,
"If-None-Match"
);
const
char
*
inm
=
mg_get_header
(
conn
,
"If-None-Match"
);
construct_etag
(
etag
,
sizeof
(
etag
),
st
p
);
construct_etag
(
etag
,
sizeof
(
etag
),
file
p
);
return
(
inm
!=
NULL
&&
!
mg_strcasecmp
(
etag
,
inm
))
||
return
(
inm
!=
NULL
&&
!
mg_strcasecmp
(
etag
,
inm
))
||
(
ims
!=
NULL
&&
stp
->
m
time
<=
parse_date_string
(
ims
));
(
ims
!=
NULL
&&
filep
->
modification_
time
<=
parse_date_string
(
ims
));
}
}
static
int
forward_body_data
(
struct
mg_connection
*
conn
,
FILE
*
fp
,
static
int
forward_body_data
(
struct
mg_connection
*
conn
,
FILE
*
fp
,
...
@@ -3119,6 +3158,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
...
@@ -3119,6 +3158,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
struct
mg_request_info
ri
;
struct
mg_request_info
ri
;
struct
cgi_env_block
blk
;
struct
cgi_env_block
blk
;
FILE
*
in
,
*
out
;
FILE
*
in
,
*
out
;
struct
file
fout
=
STRUCT_FILE_INITIALIZER
;
pid_t
pid
;
pid_t
pid
;
prepare_cgi_environment
(
conn
,
prog
,
&
blk
);
prepare_cgi_environment
(
conn
,
prog
,
&
blk
);
...
@@ -3164,6 +3204,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
...
@@ -3164,6 +3204,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
setbuf
(
in
,
NULL
);
setbuf
(
in
,
NULL
);
setbuf
(
out
,
NULL
);
setbuf
(
out
,
NULL
);
fout
.
fp
=
out
;
// Send POST data to the CGI process if needed
// Send POST data to the CGI process if needed
if
(
!
strcmp
(
conn
->
request_info
.
request_method
,
"POST"
)
&&
if
(
!
strcmp
(
conn
->
request_info
.
request_method
,
"POST"
)
&&
...
@@ -3218,36 +3259,36 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
...
@@ -3218,36 +3259,36 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
mg_printf
(
conn
,
"%s: %s
\r\n
"
,
mg_printf
(
conn
,
"%s: %s
\r\n
"
,
ri
.
http_headers
[
i
].
name
,
ri
.
http_headers
[
i
].
value
);
ri
.
http_headers
[
i
].
name
,
ri
.
http_headers
[
i
].
value
);
}
}
(
void
)
mg_write
(
conn
,
"
\r\n
"
,
2
);
mg_write
(
conn
,
"
\r\n
"
,
2
);
// Send chunk of data that may have been read after the headers
// Send chunk of data that may have been read after the headers
conn
->
num_bytes_sent
+=
mg_write
(
conn
,
buf
+
headers_len
,
conn
->
num_bytes_sent
+=
mg_write
(
conn
,
buf
+
headers_len
,
(
size_t
)(
data_len
-
headers_len
));
(
size_t
)(
data_len
-
headers_len
));
// Read the rest of CGI output and send to the client
// Read the rest of CGI output and send to the client
send_file_data
(
conn
,
out
,
INT64_MAX
);
send_file_data
(
conn
,
&
fout
,
0
,
INT64_MAX
);
done:
done:
if
(
pid
!=
(
pid_t
)
-
1
)
{
if
(
pid
!=
(
pid_t
)
-
1
)
{
kill
(
pid
,
SIGKILL
);
kill
(
pid
,
SIGKILL
);
}
}
if
(
fd_stdin
[
0
]
!=
-
1
)
{
if
(
fd_stdin
[
0
]
!=
-
1
)
{
(
void
)
close
(
fd_stdin
[
0
]);
close
(
fd_stdin
[
0
]);
}
}
if
(
fd_stdout
[
1
]
!=
-
1
)
{
if
(
fd_stdout
[
1
]
!=
-
1
)
{
(
void
)
close
(
fd_stdout
[
1
]);
close
(
fd_stdout
[
1
]);
}
}
if
(
in
!=
NULL
)
{
if
(
in
!=
NULL
)
{
(
void
)
fclose
(
in
);
fclose
(
in
);
}
else
if
(
fd_stdin
[
1
]
!=
-
1
)
{
}
else
if
(
fd_stdin
[
1
]
!=
-
1
)
{
(
void
)
close
(
fd_stdin
[
1
]);
close
(
fd_stdin
[
1
]);
}
}
if
(
out
!=
NULL
)
{
if
(
out
!=
NULL
)
{
(
void
)
fclose
(
out
);
fclose
(
out
);
}
else
if
(
fd_stdout
[
0
]
!=
-
1
)
{
}
else
if
(
fd_stdout
[
0
]
!=
-
1
)
{
(
void
)
close
(
fd_stdout
[
0
]);
close
(
fd_stdout
[
0
]);
}
}
}
}
#endif // !NO_CGI
#endif // !NO_CGI
...
@@ -3255,10 +3296,10 @@ done:
...
@@ -3255,10 +3296,10 @@ done:
// For a given PUT path, create all intermediate subdirectories
// For a given PUT path, create all intermediate subdirectories
// for given path. Return 0 if the path itself is a directory,
// for given path. Return 0 if the path itself is a directory,
// or -1 on error, 1 if OK.
// or -1 on error, 1 if OK.
static
int
put_dir
(
const
char
*
path
)
{
static
int
put_dir
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
char
buf
[
PATH_MAX
];
char
buf
[
PATH_MAX
];
const
char
*
s
,
*
p
;
const
char
*
s
,
*
p
;
struct
mgstat
st
;
struct
file
file
;
int
len
,
res
=
1
;
int
len
,
res
=
1
;
for
(
s
=
p
=
path
+
2
;
(
p
=
strchr
(
s
,
'/'
))
!=
NULL
;
s
=
++
p
)
{
for
(
s
=
p
=
path
+
2
;
(
p
=
strchr
(
s
,
'/'
))
!=
NULL
;
s
=
++
p
)
{
...
@@ -3272,7 +3313,7 @@ static int put_dir(const char *path) {
...
@@ -3272,7 +3313,7 @@ static int put_dir(const char *path) {
// Try to create intermediate directory
// Try to create intermediate directory
DEBUG_TRACE
((
"mkdir(%s)"
,
buf
));
DEBUG_TRACE
((
"mkdir(%s)"
,
buf
));
if
(
mg_stat
(
buf
,
&
st
)
==
-
1
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
if
(
!
mg_stat
(
conn
,
buf
,
&
file
)
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
res
=
-
1
;
res
=
-
1
;
break
;
break
;
}
}
...
@@ -3287,44 +3328,44 @@ static int put_dir(const char *path) {
...
@@ -3287,44 +3328,44 @@ static int put_dir(const char *path) {
}
}
static
void
put_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
static
void
put_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
struct
mgstat
st
;
struct
file
file
;
const
char
*
range
;
const
char
*
range
;
int64_t
r1
,
r2
;
int64_t
r1
,
r2
;
FILE
*
fp
;
int
rc
;
int
rc
;
conn
->
status_code
=
mg_stat
(
path
,
&
st
)
==
0
?
200
:
201
;
conn
->
status_code
=
mg_stat
(
conn
,
path
,
&
file
)
?
200
:
201
;
if
((
rc
=
put_dir
(
path
))
==
0
)
{
if
((
rc
=
put_dir
(
conn
,
path
))
==
0
)
{
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n\r\n
"
,
conn
->
status_code
);
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n\r\n
"
,
conn
->
status_code
);
}
else
if
(
rc
==
-
1
)
{
}
else
if
(
rc
==
-
1
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
send_http_error
(
conn
,
500
,
http_500_error
,
"put_dir(%s): %s"
,
path
,
strerror
(
ERRNO
));
"put_dir(%s): %s"
,
path
,
strerror
(
ERRNO
));
}
else
if
((
fp
=
mg_fopen
(
path
,
"wb+"
))
==
NULL
)
{
}
else
if
(
!
mg_fopen
(
conn
,
path
,
"wb+"
,
&
file
)
||
file
.
fp
==
NULL
)
{
mg_fclose
(
&
file
);
send_http_error
(
conn
,
500
,
http_500_error
,
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
}
else
{
}
else
{
set_close_on_exec
(
fileno
(
fp
)
);
fclose_on_exec
(
&
file
);
range
=
mg_get_header
(
conn
,
"Content-Range"
);
range
=
mg_get_header
(
conn
,
"Content-Range"
);
r1
=
r2
=
0
;
r1
=
r2
=
0
;
if
(
range
!=
NULL
&&
parse_range_header
(
range
,
&
r1
,
&
r2
)
>
0
)
{
if
(
range
!=
NULL
&&
parse_range_header
(
range
,
&
r1
,
&
r2
)
>
0
)
{
conn
->
status_code
=
206
;
conn
->
status_code
=
206
;
// TODO(lsm): handle seek error
fseeko
(
file
.
fp
,
r1
,
SEEK_SET
);
(
void
)
fseeko
(
fp
,
r1
,
SEEK_SET
);
}
}
if
(
forward_body_data
(
conn
,
fp
,
INVALID_SOCKET
,
NULL
))
{
if
(
forward_body_data
(
conn
,
f
ile
.
f
p
,
INVALID_SOCKET
,
NULL
))
{
(
void
)
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n\r\n
"
,
conn
->
status_code
);
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n\r\n
"
,
conn
->
status_code
);
}
}
(
void
)
fclose
(
fp
);
mg_fclose
(
&
file
);
}
}
}
}
static
void
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
FILE
*
,
int
);
static
void
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
struct
file
*
,
int
);
static
void
do_ssi_include
(
struct
mg_connection
*
conn
,
const
char
*
ssi
,
static
void
do_ssi_include
(
struct
mg_connection
*
conn
,
const
char
*
ssi
,
char
*
tag
,
int
include_level
)
{
char
*
tag
,
int
include_level
)
{
char
file_name
[
MG_BUF_LEN
],
path
[
PATH_MAX
],
*
p
;
char
file_name
[
MG_BUF_LEN
],
path
[
PATH_MAX
],
*
p
;
FILE
*
fp
;
struct
file
file
;
// sscanf() is safe here, since send_ssi_file() also uses buffer
// sscanf() is safe here, since send_ssi_file() also uses buffer
// of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
// of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
...
@@ -3349,51 +3390,59 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
...
@@ -3349,51 +3390,59 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
return
;
return
;
}
}
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
&
file
)
)
{
cry
(
conn
,
"Cannot open SSI #include: [%s]: fopen(%s): %s"
,
cry
(
conn
,
"Cannot open SSI #include: [%s]: fopen(%s): %s"
,
tag
,
path
,
strerror
(
ERRNO
));
tag
,
path
,
strerror
(
ERRNO
));
}
else
{
}
else
{
set_close_on_exec
(
fileno
(
fp
)
);
fclose_on_exec
(
&
file
);
if
(
match_prefix
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
],
if
(
match_prefix
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
],
strlen
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
]),
path
)
>
0
)
{
strlen
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
]),
path
)
>
0
)
{
send_ssi_file
(
conn
,
path
,
fp
,
include_level
+
1
);
send_ssi_file
(
conn
,
path
,
&
file
,
include_level
+
1
);
}
else
{
}
else
{
send_file_data
(
conn
,
fp
,
INT64_MAX
);
send_file_data
(
conn
,
&
file
,
0
,
INT64_MAX
);
}
}
(
void
)
fclose
(
fp
);
mg_fclose
(
&
file
);
}
}
}
}
#if !defined(NO_POPEN)
#if !defined(NO_POPEN)
static
void
do_ssi_exec
(
struct
mg_connection
*
conn
,
char
*
tag
)
{
static
void
do_ssi_exec
(
struct
mg_connection
*
conn
,
char
*
tag
)
{
char
cmd
[
MG_BUF_LEN
];
char
cmd
[
MG_BUF_LEN
];
FILE
*
fp
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
if
(
sscanf
(
tag
,
"
\"
%[^
\"
]
\"
"
,
cmd
)
!=
1
)
{
if
(
sscanf
(
tag
,
"
\"
%[^
\"
]
\"
"
,
cmd
)
!=
1
)
{
cry
(
conn
,
"Bad SSI #exec: [%s]"
,
tag
);
cry
(
conn
,
"Bad SSI #exec: [%s]"
,
tag
);
}
else
if
((
fp
=
popen
(
cmd
,
"r"
))
==
NULL
)
{
}
else
if
((
f
ile
.
f
p
=
popen
(
cmd
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"Cannot SSI #exec: [%s]: %s"
,
cmd
,
strerror
(
ERRNO
));
cry
(
conn
,
"Cannot SSI #exec: [%s]: %s"
,
cmd
,
strerror
(
ERRNO
));
}
else
{
}
else
{
send_file_data
(
conn
,
fp
,
INT64_MAX
);
send_file_data
(
conn
,
&
file
,
0
,
INT64_MAX
);
(
void
)
pclose
(
fp
);
pclose
(
file
.
fp
);
}
}
}
}
#endif // !NO_POPEN
#endif // !NO_POPEN
static
int
mg_fgetc
(
struct
file
*
filep
,
int
offset
)
{
if
(
filep
->
membuf
!=
NULL
&&
offset
>=
0
&&
offset
<
filep
->
size
)
{
return
((
unsigned
char
*
)
filep
->
membuf
)[
offset
];
}
else
if
(
filep
->
fp
!=
NULL
)
{
return
fgetc
(
filep
->
fp
);
}
else
{
return
EOF
;
}
}
static
void
send_ssi_file
(
struct
mg_connection
*
conn
,
const
char
*
path
,
static
void
send_ssi_file
(
struct
mg_connection
*
conn
,
const
char
*
path
,
FILE
*
f
p
,
int
include_level
)
{
struct
file
*
file
p
,
int
include_level
)
{
char
buf
[
MG_BUF_LEN
];
char
buf
[
MG_BUF_LEN
];
int
ch
,
len
,
in_ssi_tag
;
int
ch
,
offset
,
len
,
in_ssi_tag
;
if
(
include_level
>
10
)
{
if
(
include_level
>
10
)
{
cry
(
conn
,
"SSI #include level is too deep (%s)"
,
path
);
cry
(
conn
,
"SSI #include level is too deep (%s)"
,
path
);
return
;
return
;
}
}
in_ssi_tag
=
0
;
in_ssi_tag
=
len
=
offset
=
0
;
len
=
0
;
while
((
ch
=
mg_fgetc
(
filep
,
offset
))
!=
EOF
)
{
while
((
ch
=
fgetc
(
fp
))
!=
EOF
)
{
if
(
in_ssi_tag
&&
ch
==
'>'
)
{
if
(
in_ssi_tag
&&
ch
==
'>'
)
{
in_ssi_tag
=
0
;
in_ssi_tag
=
0
;
buf
[
len
++
]
=
(
char
)
ch
;
buf
[
len
++
]
=
(
char
)
ch
;
...
@@ -3401,7 +3450,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
...
@@ -3401,7 +3450,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
assert
(
len
<=
(
int
)
sizeof
(
buf
));
assert
(
len
<=
(
int
)
sizeof
(
buf
));
if
(
len
<
6
||
memcmp
(
buf
,
"<!--#"
,
5
)
!=
0
)
{
if
(
len
<
6
||
memcmp
(
buf
,
"<!--#"
,
5
)
!=
0
)
{
// Not an SSI tag, pass it
// Not an SSI tag, pass it
(
void
)
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
(
void
)
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
}
else
{
}
else
{
if
(
!
memcmp
(
buf
+
5
,
"include"
,
7
))
{
if
(
!
memcmp
(
buf
+
5
,
"include"
,
7
))
{
do_ssi_include
(
conn
,
path
,
buf
+
12
,
include_level
);
do_ssi_include
(
conn
,
path
,
buf
+
12
,
include_level
);
...
@@ -3426,14 +3475,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
...
@@ -3426,14 +3475,14 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
}
else
if
(
ch
==
'<'
)
{
}
else
if
(
ch
==
'<'
)
{
in_ssi_tag
=
1
;
in_ssi_tag
=
1
;
if
(
len
>
0
)
{
if
(
len
>
0
)
{
(
void
)
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
}
}
len
=
0
;
len
=
0
;
buf
[
len
++
]
=
ch
&
0xff
;
buf
[
len
++
]
=
ch
&
0xff
;
}
else
{
}
else
{
buf
[
len
++
]
=
ch
&
0xff
;
buf
[
len
++
]
=
ch
&
0xff
;
if
(
len
==
(
int
)
sizeof
(
buf
))
{
if
(
len
==
(
int
)
sizeof
(
buf
))
{
(
void
)
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
len
=
0
;
len
=
0
;
}
}
}
}
...
@@ -3441,42 +3490,41 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
...
@@ -3441,42 +3490,41 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
// Send the rest of buffered data
// Send the rest of buffered data
if
(
len
>
0
)
{
if
(
len
>
0
)
{
(
void
)
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
mg_write
(
conn
,
buf
,
(
size_t
)
len
);
}
}
}
}
static
void
handle_ssi_file_request
(
struct
mg_connection
*
conn
,
static
void
handle_ssi_file_request
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
const
char
*
path
)
{
FILE
*
fp
;
struct
file
file
;
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
&
file
)
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
strerror
(
ERRNO
));
}
else
{
}
else
{
conn
->
must_close
=
1
;
conn
->
must_close
=
1
;
set_close_on_exec
(
fileno
(
fp
)
);
fclose_on_exec
(
&
file
);
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: text/html
\r\n
Connection: %s
\r\n\r\n
"
,
"Content-Type: text/html
\r\n
Connection: %s
\r\n\r\n
"
,
suggest_connection_header
(
conn
));
suggest_connection_header
(
conn
));
send_ssi_file
(
conn
,
path
,
fp
,
0
);
send_ssi_file
(
conn
,
path
,
&
file
,
0
);
(
void
)
fclose
(
fp
);
mg_fclose
(
&
file
);
}
}
}
}
static
void
send_options
(
struct
mg_connection
*
conn
)
{
static
void
send_options
(
struct
mg_connection
*
conn
)
{
conn
->
status_code
=
200
;
conn
->
status_code
=
200
;
(
void
)
mg_printf
(
conn
,
mg_printf
(
conn
,
"%s"
,
"HTTP/1.1 200 OK
\r\n
"
"HTTP/1.1 200 OK
\r\n
"
"Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS
\r\n
"
"Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS
\r\n
"
"DAV: 1
\r\n\r\n
"
);
"DAV: 1
\r\n\r\n
"
);
}
}
// Writes PROPFIND properties for a collection element
// Writes PROPFIND properties for a collection element
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
struct
mgstat
*
st
)
{
struct
file
*
filep
)
{
char
mtime
[
64
];
char
mtime
[
64
];
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
st
->
m
time
);
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
filep
->
modification_
time
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<d:response>"
"<d:response>"
"<d:href>%s</d:href>"
"<d:href>%s</d:href>"
...
@@ -3490,8 +3538,8 @@ static void print_props(struct mg_connection *conn, const char* uri,
...
@@ -3490,8 +3538,8 @@ static void print_props(struct mg_connection *conn, const char* uri,
"</d:propstat>"
"</d:propstat>"
"</d:response>
\n
"
,
"</d:response>
\n
"
,
uri
,
uri
,
st
->
is_directory
?
"<d:collection/>"
:
""
,
filep
->
is_directory
?
"<d:collection/>"
:
""
,
st
->
size
,
filep
->
size
,
mtime
);
mtime
);
}
}
...
@@ -3500,11 +3548,11 @@ static void print_dav_dir_entry(struct de *de, void *data) {
...
@@ -3500,11 +3548,11 @@ static void print_dav_dir_entry(struct de *de, void *data) {
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
conn
,
href
,
sizeof
(
href
),
"%s%s"
,
mg_snprintf
(
conn
,
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
conn
->
request_info
.
uri
,
de
->
file_name
);
print_props
(
conn
,
href
,
&
de
->
st
);
print_props
(
conn
,
href
,
&
de
->
file
);
}
}
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
mgstat
*
st
)
{
struct
file
*
filep
)
{
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
conn
->
must_close
=
1
;
conn
->
must_close
=
1
;
...
@@ -3518,10 +3566,10 @@ static void handle_propfind(struct mg_connection *conn, const char* path,
...
@@ -3518,10 +3566,10 @@ static void handle_propfind(struct mg_connection *conn, const char* path,
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
// Print properties for the requested resource itself
// Print properties for the requested resource itself
print_props
(
conn
,
conn
->
request_info
.
uri
,
st
);
print_props
(
conn
,
conn
->
request_info
.
uri
,
filep
);
// If it is a directory, print directory entries too if Depth is not 0
// If it is a directory, print directory entries too if Depth is not 0
if
(
st
->
is_directory
&&
if
(
filep
->
is_directory
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
...
@@ -3977,8 +4025,8 @@ static void handle_lsp_request(struct mg_connection *conn, const char *path,
...
@@ -3977,8 +4025,8 @@ static void handle_lsp_request(struct mg_connection *conn, const char *path,
static
void
handle_request
(
struct
mg_connection
*
conn
)
{
static
void
handle_request
(
struct
mg_connection
*
conn
)
{
struct
mg_request_info
*
ri
=
&
conn
->
request_info
;
struct
mg_request_info
*
ri
=
&
conn
->
request_info
;
char
path
[
PATH_MAX
];
char
path
[
PATH_MAX
];
int
stat_result
,
uri_len
;
int
uri_len
;
struct
mgstat
st
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
if
((
conn
->
request_info
.
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
{
if
((
conn
->
request_info
.
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
{
*
((
char
*
)
conn
->
request_info
.
query_string
++
)
=
'\0'
;
*
((
char
*
)
conn
->
request_info
.
query_string
++
)
=
'\0'
;
...
@@ -3987,7 +4035,7 @@ static void handle_request(struct mg_connection *conn) {
...
@@ -3987,7 +4035,7 @@ static void handle_request(struct mg_connection *conn) {
url_decode
(
ri
->
uri
,
(
size_t
)
uri_len
,
(
char
*
)
ri
->
uri
,
url_decode
(
ri
->
uri
,
(
size_t
)
uri_len
,
(
char
*
)
ri
->
uri
,
(
size_t
)
(
uri_len
+
1
),
0
);
(
size_t
)
(
uri_len
+
1
),
0
);
remove_double_dots_and_double_slashes
((
char
*
)
ri
->
uri
);
remove_double_dots_and_double_slashes
((
char
*
)
ri
->
uri
);
stat_result
=
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
st
);
convert_uri_to_file_name
(
conn
,
path
,
sizeof
(
path
),
&
file
);
conn
->
throttle
=
set_throttle
(
conn
->
ctx
->
config
[
THROTTLE
],
conn
->
throttle
=
set_throttle
(
conn
->
ctx
->
config
[
THROTTLE
],
get_remote_ip
(
conn
),
ri
->
uri
);
get_remote_ip
(
conn
),
ri
->
uri
);
...
@@ -4018,15 +4066,16 @@ static void handle_request(struct mg_connection *conn) {
...
@@ -4018,15 +4066,16 @@ static void handle_request(struct mg_connection *conn) {
send_http_error
(
conn
,
500
,
http_500_error
,
"remove(%s): %s"
,
path
,
send_http_error
(
conn
,
500
,
http_500_error
,
"remove(%s): %s"
,
path
,
strerror
(
ERRNO
));
strerror
(
ERRNO
));
}
}
}
else
if
(
stat_result
!=
0
||
must_hide_file
(
conn
,
path
))
{
}
else
if
((
file
.
membuf
==
NULL
&&
file
.
modification_time
==
(
time_t
)
0
)
||
must_hide_file
(
conn
,
path
))
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
}
else
if
(
st
.
is_directory
&&
ri
->
uri
[
uri_len
-
1
]
!=
'/'
)
{
}
else
if
(
file
.
is_directory
&&
ri
->
uri
[
uri_len
-
1
]
!=
'/'
)
{
(
void
)
mg_printf
(
conn
,
"HTTP/1.1 301 Moved Permanently
\r\n
"
mg_printf
(
conn
,
"HTTP/1.1 301 Moved Permanently
\r\n
"
"Location: %s/
\r\n\r\n
"
,
ri
->
uri
);
"Location: %s/
\r\n\r\n
"
,
ri
->
uri
);
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"PROPFIND"
))
{
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"PROPFIND"
))
{
handle_propfind
(
conn
,
path
,
&
st
);
handle_propfind
(
conn
,
path
,
&
file
);
}
else
if
(
st
.
is_directory
&&
}
else
if
(
file
.
is_directory
&&
!
substitute_index_file
(
conn
,
path
,
sizeof
(
path
),
&
st
))
{
!
substitute_index_file
(
conn
,
path
,
sizeof
(
path
),
&
file
))
{
if
(
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
))
{
if
(
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
))
{
handle_directory_request
(
conn
,
path
);
handle_directory_request
(
conn
,
path
);
}
else
{
}
else
{
...
@@ -4053,10 +4102,10 @@ static void handle_request(struct mg_connection *conn) {
...
@@ -4053,10 +4102,10 @@ static void handle_request(struct mg_connection *conn) {
strlen
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
]),
strlen
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
]),
path
)
>
0
)
{
path
)
>
0
)
{
handle_ssi_file_request
(
conn
,
path
);
handle_ssi_file_request
(
conn
,
path
);
}
else
if
(
is_not_modified
(
conn
,
&
st
))
{
}
else
if
(
is_not_modified
(
conn
,
&
file
))
{
send_http_error
(
conn
,
304
,
"Not Modified"
,
"%s"
,
""
);
send_http_error
(
conn
,
304
,
"Not Modified"
,
"%s"
,
""
);
}
else
{
}
else
{
handle_file_request
(
conn
,
path
,
&
st
);
handle_file_request
(
conn
,
path
,
&
file
);
}
}
}
}
...
@@ -4179,7 +4228,7 @@ static void log_access(const struct mg_connection *conn) {
...
@@ -4179,7 +4228,7 @@ static void log_access(const struct mg_connection *conn) {
char
date
[
64
],
src_addr
[
20
];
char
date
[
64
],
src_addr
[
20
];
fp
=
conn
->
ctx
->
config
[
ACCESS_LOG_FILE
]
==
NULL
?
NULL
:
fp
=
conn
->
ctx
->
config
[
ACCESS_LOG_FILE
]
==
NULL
?
NULL
:
mg_
fopen
(
conn
->
ctx
->
config
[
ACCESS_LOG_FILE
],
"a+"
);
fopen
(
conn
->
ctx
->
config
[
ACCESS_LOG_FILE
],
"a+"
);
if
(
fp
==
NULL
)
if
(
fp
==
NULL
)
return
;
return
;
...
@@ -4400,9 +4449,9 @@ static void uninitialize_ssl(struct mg_context *ctx) {
...
@@ -4400,9 +4449,9 @@ static void uninitialize_ssl(struct mg_context *ctx) {
#endif // !NO_SSL
#endif // !NO_SSL
static
int
set_gpass_option
(
struct
mg_context
*
ctx
)
{
static
int
set_gpass_option
(
struct
mg_context
*
ctx
)
{
struct
mgstat
mgstat
;
struct
file
file
;
const
char
*
path
=
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
];
const
char
*
path
=
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
];
return
path
==
NULL
||
mg_stat
(
path
,
&
mgstat
)
==
0
;
return
path
==
NULL
||
!
mg_stat
(
fc
(
ctx
),
path
,
&
file
)
;
}
}
static
int
set_acl_option
(
struct
mg_context
*
ctx
)
{
static
int
set_acl_option
(
struct
mg_context
*
ctx
)
{
...
...
mongoose.h
View file @
557d1f4c
...
@@ -82,6 +82,21 @@ enum mg_event {
...
@@ -82,6 +82,21 @@ enum mg_event {
// SSL_CTX *ssl_context = request_info->ev_data;
// SSL_CTX *ssl_context = request_info->ev_data;
MG_INIT_SSL
,
MG_INIT_SSL
,
// Mongoose tries to open file.
// If callback returns non-NULL, Mongoose will not try to open it, but
// will use the returned value as a pointer to the file data. This allows
// for example to serve files from memory.
// ev_data contains file path, including document root path.
// Upon return, ev_data should return file size, which should be an int.
//
// const char *file_name = request_info->ev_data;
// if (strcmp(file_name, "foo.txt") == 0) {
// request_info->ev_data = (void *) (int) 4;
// return "data";
// }
// return NULL;
MG_OPEN_FILE
,
// Sent on HTTP connect, before websocket handshake.
// Sent on HTTP connect, before websocket handshake.
// If user callback returns NULL, then mongoose proceeds
// If user callback returns NULL, then mongoose proceeds
// with handshake, otherwise it closes the connection.
// with handshake, otherwise it closes the connection.
...
...
test/unit_test.c
View file @
557d1f4c
...
@@ -7,6 +7,8 @@
...
@@ -7,6 +7,8 @@
} while (0)
} while (0)
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
#define UNUSED_PORT "33796"
static
void
test_parse_http_request
()
{
static
void
test_parse_http_request
()
{
struct
mg_request_info
ri
;
struct
mg_request_info
ri
;
char
req1
[]
=
"GET / HTTP/1.1
\r\n\r\n
"
;
char
req1
[]
=
"GET / HTTP/1.1
\r\n\r\n
"
;
...
@@ -126,15 +128,24 @@ static void test_remove_double_dots() {
...
@@ -126,15 +128,24 @@ static void test_remove_double_dots() {
}
}
static
const
char
*
fetch_data
=
"hello world!
\n
"
;
static
const
char
*
fetch_data
=
"hello world!
\n
"
;
static
void
*
event_handler
(
enum
mg_event
event
,
static
const
char
*
inmemory_file_data
=
"hi there"
;
struct
mg_connection
*
conn
)
{
static
void
*
event_handler
(
enum
mg_event
event
,
struct
mg_connection
*
conn
)
{
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
const
struct
mg_request_info
*
request_info
=
mg_get_request_info
(
conn
);
if
(
event
==
MG_NEW_REQUEST
&&
!
strcmp
(
request_info
->
uri
,
"/data"
))
{
if
(
event
==
MG_NEW_REQUEST
&&
!
strcmp
(
request_info
->
uri
,
"/data"
))
{
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Length: %d
\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"Content-Type: text/plain
\r\n\r\n
"
"%s"
,
(
int
)
strlen
(
fetch_data
),
fetch_data
);
"%s"
,
(
int
)
strlen
(
fetch_data
),
fetch_data
);
return
""
;
return
""
;
}
else
if
(
event
==
MG_OPEN_FILE
)
{
const
char
*
path
=
request_info
->
ev_data
;
printf
(
"%s: [%s]
\n
"
,
__func__
,
path
);
if
(
strcmp
(
path
,
"./blah"
)
==
0
)
{
mg_get_request_info
(
conn
)
->
ev_data
=
(
void
*
)
(
int
)
strlen
(
inmemory_file_data
);
return
(
void
*
)
inmemory_file_data
;
}
}
else
if
(
event
==
MG_EVENT_LOG
)
{
}
else
if
(
event
==
MG_EVENT_LOG
)
{
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
printf
(
"%s
\n
"
,
(
const
char
*
)
mg_get_request_info
(
conn
)
->
ev_data
);
}
}
...
@@ -145,33 +156,33 @@ static void *event_handler(enum mg_event event,
...
@@ -145,33 +156,33 @@ static void *event_handler(enum mg_event event,
static
void
test_mg_fetch
(
void
)
{
static
void
test_mg_fetch
(
void
)
{
static
const
char
*
options
[]
=
{
static
const
char
*
options
[]
=
{
"document_root"
,
"."
,
"document_root"
,
"."
,
"listening_ports"
,
"33796"
,
"listening_ports"
,
UNUSED_PORT
,
NULL
,
NULL
,
};
};
char
buf
[
2000
],
buf2
[
2000
];
char
buf
[
2000
],
buf2
[
2000
];
int
length
;
int
n
,
length
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
struct
mg_request_info
ri
;
struct
mg_request_info
ri
;
const
char
*
tmp_file
=
"temporary_file_name_for_unit_test.txt"
;
const
char
*
tmp_file
=
"temporary_file_name_for_unit_test.txt"
;
struct
mgstat
st
;
struct
file
file
;
FILE
*
fp
;
FILE
*
fp
;
ASSERT
((
ctx
=
mg_start
(
event_handler
,
NULL
,
options
))
!=
NULL
);
ASSERT
((
ctx
=
mg_start
(
event_handler
,
NULL
,
options
))
!=
NULL
);
// Failed fetch, pass invalid URL
// Failed fetch, pass invalid URL
ASSERT
(
mg_fetch
(
ctx
,
"localhost"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
ASSERT
(
mg_fetch
(
ctx
,
"localhost"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
ASSERT
(
mg_fetch
(
ctx
,
"localhost:
33796"
,
tmp_file
,
ASSERT
(
mg_fetch
(
ctx
,
"localhost:
"
UNUSED_PORT
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
ASSERT
(
mg_fetch
(
ctx
,
"http://$$$.$$$"
,
tmp_file
,
ASSERT
(
mg_fetch
(
ctx
,
"http://$$$.$$$"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
// Failed fetch, pass invalid file name
// Failed fetch, pass invalid file name
ASSERT
(
mg_fetch
(
ctx
,
"http://localhost:
33796
/data"
,
ASSERT
(
mg_fetch
(
ctx
,
"http://localhost:
"
UNUSED_PORT
"
/data"
,
"/this/file/must/not/exist/ever"
,
"/this/file/must/not/exist/ever"
,
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
buf
,
sizeof
(
buf
),
&
ri
)
==
NULL
);
// Successful fetch
// Successful fetch
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:
33796
/data"
,
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:
"
UNUSED_PORT
"
/data"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
ASSERT
(
ri
.
num_headers
==
2
);
ASSERT
(
ri
.
num_headers
==
2
);
ASSERT
(
!
strcmp
(
ri
.
request_method
,
"HTTP/1.1"
));
ASSERT
(
!
strcmp
(
ri
.
request_method
,
"HTTP/1.1"
));
...
@@ -184,12 +195,31 @@ static void test_mg_fetch(void) {
...
@@ -184,12 +195,31 @@ static void test_mg_fetch(void) {
fclose
(
fp
);
fclose
(
fp
);
// Fetch big file, mongoose.c
// Fetch big file, mongoose.c
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:
33796
/mongoose.c"
,
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:
"
UNUSED_PORT
"
/mongoose.c"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
ASSERT
(
mg_stat
(
"mongoose.c"
,
&
st
)
==
0
);
ASSERT
(
mg_stat
(
fc
(
ctx
),
"mongoose.c"
,
&
file
)
);
ASSERT
(
st
.
size
==
ftell
(
fp
));
ASSERT
(
file
.
size
==
ftell
(
fp
));
ASSERT
(
!
strcmp
(
ri
.
request_method
,
"HTTP/1.1"
));
ASSERT
(
!
strcmp
(
ri
.
request_method
,
"HTTP/1.1"
));
// Fetch nonexistent file, /blah
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:"
UNUSED_PORT
"/boo"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
ASSERT
(
!
mg_strcasecmp
(
ri
.
uri
,
"404"
));
fclose
(
fp
);
// Fetch existing inmemory file
ASSERT
((
fp
=
mg_fetch
(
ctx
,
"http://localhost:"
UNUSED_PORT
"/blah"
,
tmp_file
,
buf
,
sizeof
(
buf
),
&
ri
))
!=
NULL
);
ASSERT
(
!
mg_strcasecmp
(
ri
.
uri
,
"200"
));
n
=
ftell
(
fp
);
fseek
(
fp
,
0
,
SEEK_SET
);
printf
(
"%s %d %d [%.*s]
\n
"
,
__func__
,
n
,
(
int
)
feof
(
fp
),
n
,
buf2
);
n
=
fread
(
buf2
,
1
,
n
,
fp
);
printf
(
"%s %d %d [%.*s]
\n
"
,
__func__
,
n
,
(
int
)
feof
(
fp
),
n
,
buf2
);
ASSERT
((
size_t
)
ftell
(
fp
)
==
(
size_t
)
strlen
(
inmemory_file_data
));
ASSERT
(
!
memcmp
(
inmemory_file_data
,
buf2
,
ftell
(
fp
)));
fclose
(
fp
);
remove
(
tmp_file
);
remove
(
tmp_file
);
mg_stop
(
ctx
);
mg_stop
(
ctx
);
}
}
...
...
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