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
98214ce1
Commit
98214ce1
authored
Sep 26, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removed init_lua() and open_file() callbacks
parent
7eed7eab
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
138 additions
and
251 deletions
+138
-251
mod_lua.c
build/mod_lua.c
+8
-11
mongoose.c
mongoose.c
+128
-204
mongoose.h
mongoose.h
+0
-3
unit_test.c
test/unit_test.c
+2
-33
No files found.
build/mod_lua.c
View file @
98214ce1
...
...
@@ -361,32 +361,29 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path,
struct
file
*
filep
,
struct
lua_State
*
ls
)
{
void
*
p
=
NULL
;
lua_State
*
L
=
NULL
;
FILE
*
fp
=
NULL
;
int
error
=
1
;
// We need both mg_stat to get file size, and mg_fopen to get fd
if
(
!
mg_stat
(
conn
,
path
,
filep
)
||
!
mg_fopen
(
conn
,
path
,
"r"
,
filep
)
)
{
if
(
!
mg_stat
(
path
,
filep
)
||
(
fp
=
mg_fopen
(
path
,
"r"
))
==
NULL
)
{
lsp_send_err
(
conn
,
ls
,
"File [%s] not found"
,
path
);
}
else
if
(
filep
->
membuf
==
NULL
&&
(
p
=
mmap
(
NULL
,
(
size_t
)
filep
->
size
,
PROT_READ
,
MAP_PRIVATE
,
fileno
(
filep
->
fp
),
0
))
==
MAP_FAILED
)
{
}
else
if
((
p
=
mmap
(
NULL
,
(
size_t
)
filep
->
size
,
PROT_READ
,
MAP_PRIVATE
,
fileno
(
fp
),
0
))
==
MAP_FAILED
)
{
lsp_send_err
(
conn
,
ls
,
"mmap(%s, %zu, %d): %s"
,
path
,
(
size_t
)
filep
->
size
,
fileno
(
f
ilep
->
f
p
),
strerror
(
errno
));
fileno
(
fp
),
strerror
(
errno
));
}
else
if
((
L
=
ls
!=
NULL
?
ls
:
luaL_newstate
())
==
NULL
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"%s"
,
"luaL_newstate failed"
);
}
else
{
// We're not sending HTTP headers here, Lua page must do it.
if
(
ls
==
NULL
)
{
prepare_lua_environment
(
conn
,
L
);
if
(
conn
->
ctx
->
callbacks
.
init_lua
!=
NULL
)
{
conn
->
ctx
->
callbacks
.
init_lua
(
conn
,
L
);
}
}
error
=
lsp
(
conn
,
path
,
filep
->
membuf
==
NULL
?
p
:
filep
->
membuf
,
filep
->
size
,
L
);
error
=
lsp
(
conn
,
path
,
p
,
filep
->
size
,
L
);
}
if
(
L
!=
NULL
&&
ls
==
NULL
)
lua_close
(
L
);
if
(
p
!=
NULL
)
munmap
(
p
,
filep
->
size
);
mg_fclose
(
filep
);
fclose
(
fp
);
return
error
;
}
mongoose.c
View file @
98214ce1
...
...
@@ -165,8 +165,6 @@ typedef DWORD pthread_t;
static
int
pthread_mutex_lock
(
pthread_mutex_t
*
);
static
int
pthread_mutex_unlock
(
pthread_mutex_t
*
);
static
void
to_unicode
(
const
char
*
path
,
wchar_t
*
wbuf
,
size_t
wbuf_len
);
struct
file
;
static
char
*
mg_fgets
(
char
*
buf
,
size_t
size
,
struct
file
*
filep
,
char
**
p
);
#if defined(HAVE_STDINT)
#include <stdint.h>
...
...
@@ -432,13 +430,11 @@ struct file {
int
is_directory
;
time_t
modification_time
;
int64_t
size
;
FILE
*
fp
;
const
char
*
membuf
;
// Non-NULL if file data is in memory
// set to 1 if the content is gzipped
// in which case we need a content-encoding: gzip header
int
gzipped
;
};
#define STRUCT_FILE_INITIALIZER {
0, 0, 0, NULL, NULL, 0
}
#define STRUCT_FILE_INITIALIZER {
0, 0, 0, 0
}
// Describes listening socket, or socket which was accept()-ed by the master
// thread and queued for future handling by the worker thread.
...
...
@@ -544,42 +540,15 @@ const char **mg_get_valid_option_names(void) {
return
config_options
;
}
static
int
is_file_in_memory
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
size_t
size
=
0
;
if
((
filep
->
membuf
=
conn
->
ctx
->
callbacks
.
open_file
==
NULL
?
NULL
:
conn
->
ctx
->
callbacks
.
open_file
(
conn
,
path
,
&
size
))
!=
NULL
)
{
// NOTE: override filep->size only on success. Otherwise, it might break
// constructs like if (!mg_stat() || !mg_fopen()) ...
filep
->
size
=
size
;
}
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
))
{
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
));
filep
->
fp
=
_wfopen
(
wbuf
,
wmode
);
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
filep
->
fp
=
fopen
(
path
,
mode
);
return
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
)
{
...
...
@@ -1127,29 +1096,27 @@ static int path_cannot_disclose_cgi(const char *path) {
return
isalnum
(
last
)
||
strchr
(
allowed_last_characters
,
last
)
!=
NULL
;
}
static
int
mg_stat
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
static
int
mg_stat
(
const
char
*
path
,
struct
file
*
filep
)
{
wchar_t
wbuf
[
PATH_MAX
]
=
L"
\\\\
?
\\
"
;
WIN32_FILE_ATTRIBUTE_DATA
info
;
if
(
!
is_file_in_memory
(
conn
,
path
,
filep
))
{
to_unicode
(
path
,
wbuf
+
4
,
ARRAY_SIZE
(
wbuf
)
-
4
);
if
(
GetFileAttributesExW
(
wbuf
,
GetFileExInfoStandard
,
&
info
)
!=
0
)
{
filep
->
size
=
MAKEUQUAD
(
info
.
nFileSizeLow
,
info
.
nFileSizeHigh
);
filep
->
modification_time
=
SYS2UNIX_TIME
(
info
.
ftLastWriteTime
.
dwLowDateTime
,
info
.
ftLastWriteTime
.
dwHighDateTime
);
filep
->
is_directory
=
info
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
// If file name is fishy, reset the file structure and return error.
// Note it is important to reset, not just return the error, cause
// functions like is_file_opened() check the struct.
if
(
!
filep
->
is_directory
&&
!
path_cannot_disclose_cgi
(
path
))
{
memset
(
filep
,
0
,
sizeof
(
*
filep
));
}
filep
->
modification_time
=
0
;
to_unicode
(
path
,
wbuf
+
4
,
ARRAY_SIZE
(
wbuf
)
-
4
);
if
(
GetFileAttributesExW
(
wbuf
,
GetFileExInfoStandard
,
&
info
)
!=
0
)
{
filep
->
size
=
MAKEUQUAD
(
info
.
nFileSizeLow
,
info
.
nFileSizeHigh
);
filep
->
modification_time
=
SYS2UNIX_TIME
(
info
.
ftLastWriteTime
.
dwLowDateTime
,
info
.
ftLastWriteTime
.
dwHighDateTime
);
filep
->
is_directory
=
info
.
dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY
;
// If file name is fishy, reset the file structure and return error.
// Note it is important to reset, not just return the error, cause
// functions like is_file_opened() check the struct.
if
(
!
filep
->
is_directory
&&
!
path_cannot_disclose_cgi
(
path
))
{
memset
(
filep
,
0
,
sizeof
(
*
filep
));
}
}
return
filep
->
m
embuf
!=
NULL
||
filep
->
m
odification_time
!=
0
;
return
filep
->
modification_time
!=
0
;
}
static
int
mg_remove
(
const
char
*
path
)
{
...
...
@@ -1305,9 +1272,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
char
*
envblk
,
char
*
envp
[],
int
fdin
,
int
fdout
,
const
char
*
dir
)
{
HANDLE
me
;
char
*
p
,
*
interp
,
full_interp
[
PATH_MAX
],
full_dir
[
PATH_MAX
],
char
*
interp
,
full_interp
[
PATH_MAX
],
full_dir
[
PATH_MAX
],
cmdline
[
PATH_MAX
],
buf
[
PATH_MAX
];
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
;
STARTUPINFOA
si
;
PROCESS_INFORMATION
pi
=
{
0
};
...
...
@@ -1333,10 +1300,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
// Read the first line of the script into the buffer
snprintf
(
cmdline
,
sizeof
(
cmdline
),
"%s%c%s"
,
dir
,
'/'
,
prog
);
if
(
mg_fopen
(
conn
,
cmdline
,
"r"
,
&
file
))
{
p
=
(
char
*
)
file
.
membuf
;
mg_fgets
(
buf
,
sizeof
(
buf
),
&
file
,
&
p
);
mg_fclose
(
&
file
);
if
((
fp
=
mg_fopen
(
cmdline
,
"r"
))
!=
NULL
)
{
fgets
(
buf
,
sizeof
(
buf
),
fp
);
fclose
(
fp
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
}
...
...
@@ -1379,11 +1345,11 @@ static int set_non_blocking_mode(SOCKET sock) {
}
#else
static
int
mg_stat
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
static
int
mg_stat
(
const
char
*
path
,
struct
file
*
filep
)
{
struct
stat
st
;
if
(
!
is_file_in_memory
(
conn
,
path
,
filep
)
&&
!
stat
(
path
,
&
st
))
{
filep
->
modification_time
=
(
time_t
)
0
;
if
(
stat
(
path
,
&
st
)
==
0
)
{
filep
->
size
=
st
.
st_size
;
filep
->
modification_time
=
st
.
st_mtime
;
filep
->
is_directory
=
S_ISDIR
(
st
.
st_mode
);
...
...
@@ -1394,11 +1360,9 @@ static int mg_stat(struct mg_connection *conn, const char *path,
if
(
filep
->
modification_time
==
(
time_t
)
0
)
{
filep
->
modification_time
=
(
time_t
)
1
;
}
}
else
{
filep
->
modification_time
=
(
time_t
)
0
;
}
return
filep
->
m
embuf
!=
NULL
||
filep
->
m
odification_time
!=
(
time_t
)
0
;
return
filep
->
modification_time
!=
(
time_t
)
0
;
}
static
void
set_close_on_exec
(
int
fd
)
{
...
...
@@ -1842,7 +1806,9 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
}
}
if
(
mg_stat
(
conn
,
buf
,
filep
))
return
1
;
if
(
mg_stat
(
buf
,
filep
))
{
return
1
;
}
// if we can't find the actual file, look for the file
// with the same name but a .gz extension. If we find it,
...
...
@@ -1853,7 +1819,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
if
((
accept_encoding
=
mg_get_header
(
conn
,
"Accept-Encoding"
))
!=
NULL
)
{
if
(
strstr
(
accept_encoding
,
"gzip"
)
!=
NULL
)
{
snprintf
(
gz_path
,
sizeof
(
gz_path
),
"%s.gz"
,
buf
);
if
(
mg_stat
(
conn
,
gz_path
,
filep
))
{
if
(
mg_stat
(
gz_path
,
filep
))
{
filep
->
gzipped
=
1
;
return
1
;
}
...
...
@@ -1866,7 +1832,7 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
*
p
=
'\0'
;
if
(
match_prefix
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
],
strlen
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
]),
buf
)
>
0
&&
mg_stat
(
conn
,
buf
,
filep
))
{
mg_stat
(
buf
,
filep
))
{
// Shift PATH_INFO block one character right, e.g.
// "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
// conn->path_info is pointing to the local variable "path" declared
...
...
@@ -2331,23 +2297,23 @@ static int check_password(const char *method, const char *ha1, const char *uri,
// Use the global passwords file, if specified by auth_gpass option,
// or search for .htpasswd in the requested directory.
static
void
open_auth_file
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
static
FILE
*
open_auth_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
char
name
[
PATH_MAX
];
const
char
*
p
,
*
e
,
*
gpass
=
conn
->
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
];
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
=
NULL
;
if
(
gpass
!=
NULL
)
{
// Use global passwords file
if
(
!
mg_fopen
(
conn
,
gpass
,
"r"
,
filep
)
)
{
if
(
(
fp
=
mg_fopen
(
gpass
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"fopen(%s): %s"
,
gpass
,
strerror
(
ERRNO
));
}
// 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
(
conn
,
path
,
&
file
)
&&
file
.
is_directory
)
{
}
else
if
(
mg_stat
(
path
,
&
file
)
&&
file
.
is_directory
)
{
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
path
,
'/'
,
PASSWORDS_FILE_NAME
);
mg_fopen
(
conn
,
name
,
"r"
,
filep
);
fp
=
mg_fopen
(
name
,
"r"
);
}
else
{
// Try to find .htpasswd in requested directory.
for
(
p
=
path
,
e
=
p
+
strlen
(
p
)
-
1
;
e
>
p
;
e
--
)
...
...
@@ -2355,8 +2321,10 @@ static void open_auth_file(struct mg_connection *conn, const char *path,
break
;
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%.*s%c%s"
,
(
int
)
(
e
-
p
),
p
,
'/'
,
PASSWORDS_FILE_NAME
);
mg_fopen
(
conn
,
name
,
"r"
,
filep
);
fp
=
mg_fopen
(
name
,
"r"
);
}
return
fp
;
}
// Parsed Authorization header
...
...
@@ -2428,44 +2396,17 @@ static int parse_auth_header(struct mg_connection *conn, char *buf,
return
1
;
}
static
char
*
mg_fgets
(
char
*
buf
,
size_t
size
,
struct
file
*
filep
,
char
**
p
)
{
char
*
eof
;
size_t
len
;
char
*
memend
;
if
(
filep
->
membuf
!=
NULL
&&
*
p
!=
NULL
)
{
memend
=
(
char
*
)
&
filep
->
membuf
[
filep
->
size
];
// Search for \n from p till the end of stream
eof
=
(
char
*
)
memchr
(
*
p
,
'\n'
,
memend
-
*
p
);
if
(
eof
!=
NULL
)
{
eof
+=
1
;
// Include \n
}
else
{
eof
=
memend
;
// Copy remaining data
}
len
=
(
size_t
)
(
eof
-
*
p
)
>
size
-
1
?
size
-
1
:
(
size_t
)
(
eof
-
*
p
);
memcpy
(
buf
,
*
p
,
len
);
buf
[
len
]
=
'\0'
;
*
p
+=
len
;
return
len
?
eof
:
NULL
;
}
else
if
(
filep
->
fp
!=
NULL
)
{
return
fgets
(
buf
,
size
,
filep
->
fp
);
}
else
{
return
NULL
;
}
}
// Authorize against the opened passwords file. Return 1 if authorized.
static
int
authorize
(
struct
mg_connection
*
conn
,
struct
file
*
file
p
)
{
static
int
authorize
(
struct
mg_connection
*
conn
,
FILE
*
f
p
)
{
struct
ah
ah
;
char
line
[
256
],
f_user
[
256
],
ha1
[
256
],
f_domain
[
256
],
buf
[
MG_BUF_LEN
]
,
*
p
;
char
line
[
256
],
f_user
[
256
],
ha1
[
256
],
f_domain
[
256
],
buf
[
MG_BUF_LEN
];
if
(
!
parse_auth_header
(
conn
,
buf
,
sizeof
(
buf
),
&
ah
))
{
return
0
;
}
// Loop over passwords file
p
=
(
char
*
)
filep
->
membuf
;
while
(
mg_fgets
(
line
,
sizeof
(
line
),
filep
,
&
p
)
!=
NULL
)
{
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
if
(
sscanf
(
line
,
"%[^:]:%[^:]:%s"
,
f_user
,
f_domain
,
ha1
)
!=
3
)
{
continue
;
}
...
...
@@ -2484,7 +2425,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
char
fname
[
PATH_MAX
];
struct
vec
uri_vec
,
filename_vec
;
const
char
*
list
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
=
NULL
;
int
authorized
=
1
;
list
=
conn
->
ctx
->
config
[
PROTECT_URI
];
...
...
@@ -2492,20 +2433,20 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
if
(
!
memcmp
(
conn
->
request_info
.
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
))
{
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
(
int
)
filename_vec
.
len
,
filename_vec
.
ptr
);
if
(
!
mg_fopen
(
conn
,
fname
,
"r"
,
&
file
)
)
{
if
(
(
fp
=
mg_fopen
(
fname
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"%s: cannot open %s: %s"
,
__func__
,
fname
,
strerror
(
errno
));
}
break
;
}
}
if
(
!
is_file_opened
(
&
file
)
)
{
open_auth_file
(
conn
,
path
,
&
file
);
if
(
fp
==
NULL
)
{
fp
=
open_auth_file
(
conn
,
path
);
}
if
(
is_file_opened
(
&
file
)
)
{
authorized
=
authorize
(
conn
,
&
file
);
mg_fclose
(
&
file
);
if
(
fp
!=
NULL
)
{
authorized
=
authorize
(
conn
,
fp
);
fclose
(
fp
);
}
return
authorized
;
...
...
@@ -2523,13 +2464,13 @@ static void send_authorization_request(struct mg_connection *conn) {
}
static
int
is_authorized_for_put
(
struct
mg_connection
*
conn
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
const
char
*
passfile
=
conn
->
ctx
->
config
[
PUT_DELETE_PASSWORDS_FILE
];
FILE
*
fp
;
int
ret
=
0
;
if
(
passfile
!=
NULL
&&
mg_fopen
(
conn
,
passfile
,
"r"
,
&
file
)
)
{
ret
=
authorize
(
conn
,
&
file
);
mg_fclose
(
&
file
);
if
(
passfile
!=
NULL
&&
(
fp
=
mg_fopen
(
passfile
,
"r"
))
!=
NULL
)
{
ret
=
authorize
(
conn
,
fp
);
fclose
(
fp
);
}
return
ret
;
...
...
@@ -2553,7 +2494,7 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
// Create the file if does not exist
if
((
fp
=
fopen
(
fname
,
"a+"
))
!=
NULL
)
{
(
void
)
fclose
(
fp
);
fclose
(
fp
);
}
// Open the given file and temporary file
...
...
@@ -2746,7 +2687,7 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset
(
&
de
.
file
,
0
,
sizeof
(
de
.
file
));
mg_stat
(
conn
,
path
,
&
de
.
file
);
mg_stat
(
path
,
&
de
.
file
);
de
.
file_name
=
dp
->
d_name
;
cb
(
&
de
,
data
);
...
...
@@ -2782,7 +2723,7 @@ static int remove_directory(struct mg_connection *conn, const char *dir) {
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset
(
&
de
.
file
,
0
,
sizeof
(
de
.
file
));
mg_stat
(
conn
,
path
,
&
de
.
file
);
mg_stat
(
path
,
&
de
.
file
);
if
(
de
.
file
.
modification_time
)
{
if
(
de
.
file
.
is_directory
)
{
remove_directory
(
conn
,
path
);
...
...
@@ -2887,42 +2828,36 @@ static void handle_directory_request(struct mg_connection *conn,
}
// Send len bytes from the opened file to the client.
static
void
send_file_data
(
struct
mg_connection
*
conn
,
struct
file
*
file
p
,
static
void
send_file_data
(
struct
mg_connection
*
conn
,
FILE
*
f
p
,
int64_t
offset
,
int64_t
len
)
{
char
buf
[
MG_BUF_LEN
];
int
to_read
,
num_read
,
num_written
;
// Sanity check the offset
offset
=
offset
<
0
?
0
:
offset
>
filep
->
size
?
filep
->
size
:
offset
;
// If offset is beyond file boundaries, don't send anything
if
(
offset
>
0
&&
fseeko
(
fp
,
offset
,
SEEK_SET
)
!=
0
)
{
return
;
}
if
(
len
>
0
&&
filep
->
membuf
!=
NULL
&&
filep
->
size
>
0
)
{
if
(
len
>
filep
->
size
-
offset
)
{
len
=
filep
->
size
-
offset
;
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
;
}
mg_write
(
conn
,
filep
->
membuf
+
offset
,
(
size_t
)
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
if
((
num_read
=
fread
(
buf
,
1
,
(
size_t
)
to_read
,
filep
->
fp
))
<=
0
)
{
break
;
}
// Send read bytes to the client
, exit the loop on error
if
((
num_written
=
mg_write
(
conn
,
buf
,
(
size_t
)
num_read
))
!=
num_read
)
{
break
;
}
// Read from file
, exit the loop on error
if
((
num_read
=
fread
(
buf
,
1
,
(
size_t
)
to_read
,
fp
))
<=
0
)
{
break
;
}
// Both read and were successful, adjust counters
conn
->
num_bytes_sent
+=
num_written
;
len
-=
num_written
;
// Send read bytes to the client, exit the loop on error
if
((
num_written
=
mg_write
(
conn
,
buf
,
(
size_t
)
num_read
))
!=
num_read
)
{
break
;
}
// Both read and were successful, adjust counters
conn
->
num_bytes_sent
+=
num_written
;
len
-=
num_written
;
}
}
...
...
@@ -2940,10 +2875,10 @@ static void construct_etag(char *buf, size_t buf_len,
(
unsigned
long
)
filep
->
modification_time
,
filep
->
size
);
}
static
void
fclose_on_exec
(
struct
file
*
file
p
)
{
if
(
f
ilep
!=
NULL
&&
filep
->
f
p
!=
NULL
)
{
static
void
fclose_on_exec
(
FILE
*
f
p
)
{
if
(
fp
!=
NULL
)
{
#ifndef _WIN32
fcntl
(
fileno
(
f
ilep
->
f
p
),
F_SETFD
,
FD_CLOEXEC
);
fcntl
(
fileno
(
fp
),
F_SETFD
,
FD_CLOEXEC
);
#endif
}
}
...
...
@@ -2958,6 +2893,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
int
n
;
char
gz_path
[
PATH_MAX
];
char
const
*
encoding
=
""
;
FILE
*
fp
;
get_mime_type
(
conn
->
ctx
,
path
,
&
mime_vec
);
cl
=
filep
->
size
;
...
...
@@ -2973,13 +2909,13 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
encoding
=
"Content-Encoding: gzip
\r\n
"
;
}
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
filep
)
)
{
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
return
;
}
fclose_on_exec
(
f
ile
p
);
fclose_on_exec
(
fp
);
// If Range: header specified, act accordingly
r1
=
r2
=
0
;
...
...
@@ -3024,14 +2960,14 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
EXTRA_HTTP_HEADERS
);
if
(
strcmp
(
conn
->
request_info
.
request_method
,
"HEAD"
)
!=
0
)
{
send_file_data
(
conn
,
f
ile
p
,
r1
,
cl
);
send_file_data
(
conn
,
fp
,
r1
,
cl
);
}
mg_fclose
(
file
p
);
fclose
(
f
p
);
}
void
mg_send_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
if
(
mg_stat
(
conn
,
path
,
&
file
))
{
if
(
mg_stat
(
path
,
&
file
))
{
handle_file_request
(
conn
,
path
,
&
file
);
}
else
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
...
...
@@ -3150,7 +3086,7 @@ static int substitute_index_file(struct mg_connection *conn, char *path,
mg_strlcpy
(
path
+
n
+
1
,
filename_vec
.
ptr
,
filename_vec
.
len
+
1
);
// Does it exist?
if
(
mg_stat
(
conn
,
path
,
&
file
))
{
if
(
mg_stat
(
path
,
&
file
))
{
// Yes it does, break the loop
*
filep
=
file
;
found
=
1
;
...
...
@@ -3417,7 +3353,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
struct
mg_request_info
ri
;
struct
cgi_env_block
blk
;
FILE
*
in
=
NULL
,
*
out
=
NULL
;
struct
file
fout
=
STRUCT_FILE_INITIALIZER
;
pid_t
pid
=
(
pid_t
)
-
1
;
prepare_cgi_environment
(
conn
,
prog
,
&
blk
);
...
...
@@ -3470,7 +3405,6 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
setbuf
(
in
,
NULL
);
setbuf
(
out
,
NULL
);
fout
.
fp
=
out
;
// Send POST data to the CGI process if needed
if
(
!
strcmp
(
conn
->
request_info
.
request_method
,
"POST"
)
&&
...
...
@@ -3532,7 +3466,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
(
size_t
)(
data_len
-
headers_len
));
// Read the rest of CGI output and send to the client
send_file_data
(
conn
,
&
f
out
,
0
,
INT64_MAX
);
send_file_data
(
conn
,
out
,
0
,
INT64_MAX
);
done:
if
(
pid
!=
(
pid_t
)
-
1
)
{
...
...
@@ -3562,7 +3496,7 @@ done:
// For a given PUT path, create all intermediate subdirectories
// for given path. Return 0 if the path itself is a directory,
// or -1 on error, 1 if OK.
static
int
put_dir
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
static
int
put_dir
(
const
char
*
path
)
{
char
buf
[
PATH_MAX
];
const
char
*
s
,
*
p
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
...
...
@@ -3579,7 +3513,7 @@ static int put_dir(struct mg_connection *conn, const char *path) {
// Try to create intermediate directory
DEBUG_TRACE
((
"mkdir(%s)"
,
buf
));
if
(
!
mg_stat
(
conn
,
buf
,
&
file
)
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
if
(
!
mg_stat
(
buf
,
&
file
)
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
res
=
-
1
;
break
;
}
...
...
@@ -3596,10 +3530,11 @@ static int put_dir(struct mg_connection *conn, const char *path) {
static
void
mkcol
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
int
rc
,
body_len
;
struct
de
de
;
memset
(
&
de
.
file
,
0
,
sizeof
(
de
.
file
));
mg_stat
(
conn
,
path
,
&
de
.
file
);
mg_stat
(
path
,
&
de
.
file
);
if
(
de
.
file
.
modification_time
)
{
if
(
de
.
file
.
modification_time
)
{
send_http_error
(
conn
,
405
,
"Method Not Allowed"
,
"mkcol(%s): %s"
,
path
,
strerror
(
ERRNO
));
return
;
...
...
@@ -3635,45 +3570,44 @@ static void mkcol(struct mg_connection *conn, const char *path) {
static
void
put_file
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
;
const
char
*
range
;
int64_t
r1
,
r2
;
int
rc
;
conn
->
status_code
=
mg_stat
(
conn
,
path
,
&
file
)
?
200
:
201
;
conn
->
status_code
=
mg_stat
(
path
,
&
file
)
?
200
:
201
;
if
((
rc
=
put_dir
(
conn
,
path
))
==
0
)
{
if
((
rc
=
put_dir
(
path
))
==
0
)
{
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n\r\n
"
,
conn
->
status_code
);
}
else
if
(
rc
==
-
1
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"put_dir(%s): %s"
,
path
,
strerror
(
ERRNO
));
}
else
if
(
!
mg_fopen
(
conn
,
path
,
"wb+"
,
&
file
)
||
file
.
fp
==
NULL
)
{
mg_fclose
(
&
file
);
}
else
if
(
(
fp
=
mg_fopen
(
path
,
"wb+"
))
==
NULL
)
{
fclose
(
fp
);
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
}
else
{
fclose_on_exec
(
&
file
);
fclose_on_exec
(
fp
);
range
=
mg_get_header
(
conn
,
"Content-Range"
);
r1
=
r2
=
0
;
if
(
range
!=
NULL
&&
parse_range_header
(
range
,
&
r1
,
&
r2
)
>
0
)
{
conn
->
status_code
=
206
;
fseeko
(
f
ile
.
f
p
,
r1
,
SEEK_SET
);
fseeko
(
fp
,
r1
,
SEEK_SET
);
}
if
(
!
forward_body_data
(
conn
,
f
ile
.
f
p
,
INVALID_SOCKET
,
NULL
))
{
if
(
!
forward_body_data
(
conn
,
fp
,
INVALID_SOCKET
,
NULL
))
{
conn
->
status_code
=
500
;
}
mg_printf
(
conn
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
conn
->
status_code
);
mg_fclose
(
&
file
);
fclose
(
fp
);
}
}
static
void
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
struct
file
*
,
int
);
static
void
send_ssi_file
(
struct
mg_connection
*
,
const
char
*
,
FILE
*
,
int
);
static
void
do_ssi_include
(
struct
mg_connection
*
conn
,
const
char
*
ssi
,
char
*
tag
,
int
include_level
)
{
char
file_name
[
MG_BUF_LEN
],
path
[
PATH_MAX
],
*
p
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
;
// 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.
...
...
@@ -3699,49 +3633,39 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi,
return
;
}
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
&
file
)
)
{
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
cry
(
conn
,
"Cannot open SSI #include: [%s]: fopen(%s): %s"
,
tag
,
path
,
strerror
(
ERRNO
));
}
else
{
fclose_on_exec
(
&
file
);
fclose_on_exec
(
fp
);
if
(
match_prefix
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
],
strlen
(
conn
->
ctx
->
config
[
SSI_EXTENSIONS
]),
path
)
>
0
)
{
send_ssi_file
(
conn
,
path
,
&
file
,
include_level
+
1
);
send_ssi_file
(
conn
,
path
,
fp
,
include_level
+
1
);
}
else
{
send_file_data
(
conn
,
&
file
,
0
,
INT64_MAX
);
send_file_data
(
conn
,
fp
,
0
,
INT64_MAX
);
}
mg_fclose
(
&
file
);
fclose
(
fp
);
}
}
#if !defined(NO_POPEN)
static
void
do_ssi_exec
(
struct
mg_connection
*
conn
,
char
*
tag
)
{
char
cmd
[
MG_BUF_LEN
];
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
FILE
*
fp
;
if
(
sscanf
(
tag
,
"
\"
%[^
\"
]
\"
"
,
cmd
)
!=
1
)
{
cry
(
conn
,
"Bad SSI #exec: [%s]"
,
tag
);
}
else
if
((
f
ile
.
f
p
=
popen
(
cmd
,
"r"
))
==
NULL
)
{
}
else
if
((
fp
=
popen
(
cmd
,
"r"
))
==
NULL
)
{
cry
(
conn
,
"Cannot SSI #exec: [%s]: %s"
,
cmd
,
strerror
(
ERRNO
));
}
else
{
send_file_data
(
conn
,
&
file
,
0
,
INT64_MAX
);
pclose
(
f
ile
.
f
p
);
send_file_data
(
conn
,
fp
,
0
,
INT64_MAX
);
pclose
(
fp
);
}
}
#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
,
struct
file
*
file
p
,
int
include_level
)
{
FILE
*
f
p
,
int
include_level
)
{
char
buf
[
MG_BUF_LEN
];
int
ch
,
offset
,
len
,
in_ssi_tag
;
...
...
@@ -3751,7 +3675,7 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
}
in_ssi_tag
=
len
=
offset
=
0
;
while
((
ch
=
mg_fgetc
(
filep
,
offset
))
!=
EOF
)
{
while
((
ch
=
fgetc
(
fp
))
!=
EOF
)
{
if
(
in_ssi_tag
&&
ch
==
'>'
)
{
in_ssi_tag
=
0
;
buf
[
len
++
]
=
(
char
)
ch
;
...
...
@@ -3805,22 +3729,22 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
static
void
handle_ssi_file_request
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
struct
vec
mime_vec
;
FILE
*
fp
;
if
(
!
mg_fopen
(
conn
,
path
,
"rb"
,
&
file
)
)
{
if
(
(
fp
=
mg_fopen
(
path
,
"rb"
))
==
NULL
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"fopen(%s): %s"
,
path
,
strerror
(
ERRNO
));
}
else
{
conn
->
must_close
=
1
;
fclose_on_exec
(
&
file
);
fclose_on_exec
(
fp
);
get_mime_type
(
conn
->
ctx
,
path
,
&
mime_vec
);
mg_printf
(
conn
,
"HTTP/1.1 200 OK
\r\n
"
"Content-Type: %.*s
\r\n
"
"Connection: close
\r\n\r\n
"
,
(
int
)
mime_vec
.
len
,
mime_vec
.
ptr
);
send_ssi_file
(
conn
,
path
,
&
file
,
0
);
mg_fclose
(
&
file
);
send_ssi_file
(
conn
,
path
,
fp
,
0
);
fclose
(
fp
);
}
}
...
...
@@ -4447,7 +4371,7 @@ static void handle_delete_request(struct mg_connection *conn,
const
char
*
path
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
if
(
!
mg_stat
(
conn
,
path
,
&
file
))
{
if
(
!
mg_stat
(
path
,
&
file
))
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
}
else
if
(
!
file
.
modification_time
)
{
send_http_error
(
conn
,
500
,
http_500_error
,
"remove(%s): %s"
,
path
,
...
...
@@ -4513,7 +4437,7 @@ static void handle_request(struct mg_connection *conn) {
mkcol
(
conn
,
path
);
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"DELETE"
))
{
handle_delete_request
(
conn
,
path
);
}
else
if
(
(
file
.
membuf
==
NULL
&&
file
.
modification_time
==
(
time_t
)
0
)
||
}
else
if
(
file
.
modification_time
==
(
time_t
)
0
||
must_hide_file
(
conn
,
path
))
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
}
else
if
(
file
.
is_directory
&&
ri
->
uri
[
uri_len
-
1
]
!=
'/'
)
{
...
...
@@ -4903,7 +4827,7 @@ static void uninitialize_ssl(struct mg_context *ctx) {
static
int
set_gpass_option
(
struct
mg_context
*
ctx
)
{
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
const
char
*
path
=
ctx
->
config
[
GLOBAL_PASSWORDS_FILE
];
if
(
path
!=
NULL
&&
!
mg_stat
(
fc
(
ctx
),
path
,
&
file
))
{
if
(
path
!=
NULL
&&
!
mg_stat
(
path
,
&
file
))
{
cry
(
fc
(
ctx
),
"Cannot open %s: %s"
,
path
,
strerror
(
ERRNO
));
return
0
;
}
...
...
mongoose.h
View file @
98214ce1
...
...
@@ -59,9 +59,6 @@ struct mg_callbacks {
void
(
*
websocket_ready
)(
struct
mg_connection
*
);
int
(
*
websocket_data
)(
struct
mg_connection
*
,
int
bits
,
char
*
data
,
size_t
data_len
);
const
char
*
(
*
open_file
)(
const
struct
mg_connection
*
,
const
char
*
path
,
size_t
*
data_len
);
void
(
*
init_lua
)(
struct
mg_connection
*
,
void
*
lua_context
);
void
(
*
upload
)(
struct
mg_connection
*
,
const
char
*
file_name
);
void
(
*
thread_start
)(
void
*
user_data
,
void
**
conn_data
);
void
(
*
thread_stop
)(
void
*
user_data
,
void
**
conn_data
);
...
...
test/unit_test.c
View file @
98214ce1
...
...
@@ -201,21 +201,10 @@ static char *read_file(const char *path, int *size) {
}
static
const
char
*
fetch_data
=
"hello world!
\n
"
;
static
const
char
*
inmemory_file_data
=
"hi there"
;
static
const
char
*
upload_filename
=
"upload_test.txt"
;
static
const
char
*
upload_filename2
=
"upload_test2.txt"
;
static
const
char
*
upload_ok_message
=
"upload successful"
;
static
const
char
*
open_file_cb
(
const
struct
mg_connection
*
conn
,
const
char
*
path
,
size_t
*
size
)
{
(
void
)
conn
;
if
(
!
strcmp
(
path
,
"./blah"
))
{
*
size
=
strlen
(
inmemory_file_data
);
return
inmemory_file_data
;
}
return
NULL
;
}
static
void
upload_cb
(
struct
mg_connection
*
conn
,
const
char
*
path
)
{
const
struct
mg_request_info
*
ri
=
mg_get_request_info
(
conn
);
char
*
p1
,
*
p2
;
...
...
@@ -282,7 +271,7 @@ static int log_message_cb(const struct mg_connection *conn, const char *msg) {
static
const
struct
mg_callbacks
CALLBACKS
=
{
&
begin_request_handler_cb
,
NULL
,
&
log_message_cb
,
NULL
,
NULL
,
NULL
,
NULL
,
&
open_file_cb
,
NULL
,
&
upload_cb
,
NULL
,
NULL
&
upload_cb
,
NULL
,
NULL
};
static
const
char
*
OPTIONS
[]
=
{
...
...
@@ -339,25 +328,6 @@ static void test_mg_download(void) {
free
(
p1
),
free
(
p2
);
mg_close_connection
(
conn
);
// Fetch in-memory file, should succeed.
ASSERT
((
conn
=
mg_download
(
"localhost"
,
port
,
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
"GET /blah HTTP/1.1
\r\n\r\n
"
))
!=
NULL
);
ASSERT
((
p1
=
read_conn
(
conn
,
&
len1
))
!=
NULL
);
ASSERT
(
len1
==
(
int
)
strlen
(
inmemory_file_data
));
ASSERT
(
memcmp
(
p1
,
inmemory_file_data
,
len1
)
==
0
);
free
(
p1
);
mg_close_connection
(
conn
);
// Fetch in-memory data with no Content-Length, should succeed.
ASSERT
((
conn
=
mg_download
(
"localhost"
,
port
,
1
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
"GET /data HTTP/1.1
\r\n\r\n
"
))
!=
NULL
);
ASSERT
((
p1
=
read_conn
(
conn
,
&
len1
))
!=
NULL
);
ASSERT
(
len1
==
(
int
)
strlen
(
fetch_data
));
ASSERT
(
memcmp
(
p1
,
fetch_data
,
len1
)
==
0
);
free
(
p1
);
mg_close_connection
(
conn
);
// Test SSL redirect, IP address
ASSERT
((
conn
=
mg_download
(
"localhost"
,
atoi
(
HTTP_PORT
),
0
,
ebuf
,
sizeof
(
ebuf
),
"%s"
,
...
...
@@ -576,9 +546,8 @@ static void test_lua(void) {
#endif
static
void
test_mg_stat
(
void
)
{
static
struct
mg_context
ctx
;
struct
file
file
=
STRUCT_FILE_INITIALIZER
;
ASSERT
(
!
mg_stat
(
fc
(
&
ctx
),
" does not exist "
,
&
file
));
ASSERT
(
!
mg_stat
(
" does not exist "
,
&
file
));
}
static
void
test_skip_quoted
(
void
)
{
...
...
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