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
5425b94f
Commit
5425b94f
authored
Jun 25, 2010
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
introduced struct mg_config. Fixed Range response.
parent
9a5f96e7
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
351 additions
and
564 deletions
+351
-564
main.c
main.c
+111
-37
mongoose.c
mongoose.c
+187
-460
mongoose.h
mongoose.h
+50
-64
test.pl
test/test.pl
+3
-3
No files found.
main.c
View file @
5425b94f
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#include <string.h>
#include <string.h>
#include <errno.h>
#include <errno.h>
#include <limits.h>
#include <limits.h>
#include <stddef.h>
#include "mongoose.h"
#include "mongoose.h"
...
@@ -70,16 +71,6 @@ signal_handler(int sig_num)
...
@@ -70,16 +71,6 @@ signal_handler(int sig_num)
}
}
}
}
/*
* Show usage string and exit.
*/
static
void
show_usage_and_exit
(
void
)
{
mg_show_usage_string
(
stderr
);
exit
(
EXIT_FAILURE
);
}
/*
/*
* Edit the passwords file.
* Edit the passwords file.
*/
*/
...
@@ -88,18 +79,89 @@ mg_edit_passwords(const char *fname, const char *domain,
...
@@ -88,18 +79,89 @@ mg_edit_passwords(const char *fname, const char *domain,
const
char
*
user
,
const
char
*
pass
)
const
char
*
user
,
const
char
*
pass
)
{
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
struct
mg_config
config
;
int
retval
;
int
retval
;
ctx
=
mg_start
();
memset
(
&
config
,
0
,
sizeof
(
config
));
(
void
)
mg_set_option
(
ctx
,
"auth_realm"
,
domain
);
config
.
auth_domain
=
(
char
*
)
domain
;
config
.
num_threads
=
"0"
;
config
.
listening_ports
=
""
;
ctx
=
mg_start
(
&
config
);
retval
=
mg_modify_passwords_file
(
ctx
,
fname
,
user
,
pass
);
retval
=
mg_modify_passwords_file
(
ctx
,
fname
,
user
,
pass
);
mg_stop
(
ctx
);
mg_stop
(
ctx
);
return
(
retval
);
return
(
retval
);
}
}
#define OFFSET(x) offsetof(struct mg_config, x)
static
struct
option_descriptor
{
const
char
*
name
;
const
char
*
description
;
size_t
offset
;
}
known_options
[]
=
{
{
"root"
,
"
\t
Web root directory"
,
OFFSET
(
document_root
)},
{
"index_files"
,
"Index files"
,
OFFSET
(
index_files
)},
{
"ssl_cert"
,
"SSL certificate file"
,
OFFSET
(
ssl_certificate
)},
{
"ports"
,
"Listening ports"
,
OFFSET
(
listening_ports
)},
{
"dir_list"
,
"Directory listing"
,
OFFSET
(
enable_directory_listing
)},
{
"protect"
,
"URI to htpasswd mapping"
,
OFFSET
(
protect
)},
{
"cgi_ext"
,
"CGI extensions"
,
OFFSET
(
cgi_extensions
)},
{
"cgi_interp"
,
"CGI interpreter to use"
,
OFFSET
(
cgi_interpreter
)},
{
"cgi_env"
,
"Custom CGI enviroment variables"
,
OFFSET
(
cgi_environment
)},
{
"ssi_ext"
,
"SSI extensions"
,
OFFSET
(
ssi_extensions
)},
{
"auth_realm"
,
"Authentication domain name"
,
OFFSET
(
auth_domain
)},
{
"auth_gpass"
,
"Global passwords file"
,
OFFSET
(
global_passwords_file
)},
{
"auth_PUT"
,
"PUT,DELETE auth file"
,
OFFSET
(
put_delete_passwords_file
)},
{
"uid"
,
"
\t
Run as user"
,
OFFSET
(
uid
)},
{
"access_log"
,
"Access log file"
,
OFFSET
(
access_log_file
)},
{
"error_log"
,
"Error log file"
,
OFFSET
(
error_log_file
)},
{
"acl"
,
"
\t
Allow/deny IP addresses/subnets"
,
OFFSET
(
acl
)},
{
"num_threads"
,
"Threads to spawn"
,
OFFSET
(
num_threads
)},
{
"mime_types"
,
"Extra mime types to use"
,
OFFSET
(
mime_types
)},
{
NULL
,
NULL
,
0
}
};
static
void
show_usage_and_exit
(
const
struct
mg_config
*
config
)
{
const
struct
option_descriptor
*
o
;
const
char
*
value
;
(
void
)
fprintf
(
stderr
,
"Mongoose version %s (c) Sergey Lyubka
\n
"
"usage: mongoose [options] [config_file]
\n
"
,
mg_version
());
fprintf
(
stderr
,
" -A <htpasswd_file> <realm> <user> <passwd>
\n
"
);
for
(
o
=
known_options
;
o
->
name
!=
NULL
;
o
++
)
{
(
void
)
fprintf
(
stderr
,
" -%s
\t
%s"
,
o
->
name
,
o
->
description
);
value
=
*
(
char
**
)
((
char
*
)
config
+
o
->
offset
);
if
(
value
!=
NULL
)
fprintf
(
stderr
,
" (default:
\"
%s
\"
)"
,
value
);
fputc
(
'\n'
,
stderr
);
}
exit
(
EXIT_FAILURE
);
}
static
void
static
void
process_command_line_arguments
(
struct
mg_context
*
ctx
,
char
*
argv
[])
set_option
(
struct
mg_config
*
config
,
const
char
*
name
,
char
*
value
)
{
const
struct
option_descriptor
*
o
;
for
(
o
=
known_options
;
o
->
name
!=
NULL
;
o
++
)
if
(
strcmp
(
name
,
o
->
name
)
==
0
)
{
*
(
char
**
)
((
char
*
)
config
+
o
->
offset
)
=
value
;
break
;
}
if
(
o
->
name
==
NULL
)
show_usage_and_exit
(
config
);
}
static
void
process_command_line_arguments
(
struct
mg_config
*
config
,
char
*
argv
[])
{
{
const
char
*
config_file
=
CONFIG_FILE
;
const
char
*
config_file
=
CONFIG_FILE
;
char
line
[
512
],
opt
[
512
],
*
vals
[
100
],
char
line
[
512
],
opt
[
512
],
*
vals
[
100
],
...
@@ -110,11 +172,11 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
...
@@ -110,11 +172,11 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
/* First find out, which config file to open */
/* First find out, which config file to open */
for
(
i
=
1
;
argv
[
i
]
!=
NULL
&&
argv
[
i
][
0
]
==
'-'
;
i
+=
2
)
for
(
i
=
1
;
argv
[
i
]
!=
NULL
&&
argv
[
i
][
0
]
==
'-'
;
i
+=
2
)
if
(
argv
[
i
+
1
]
==
NULL
)
if
(
argv
[
i
+
1
]
==
NULL
)
show_usage_and_exit
();
show_usage_and_exit
(
config
);
if
(
argv
[
i
]
!=
NULL
&&
argv
[
i
+
1
]
!=
NULL
)
{
if
(
argv
[
i
]
!=
NULL
&&
argv
[
i
+
1
]
!=
NULL
)
{
/* More than one non-option arguments are given */
/* More than one non-option arguments are given */
show_usage_and_exit
();
show_usage_and_exit
(
config
);
}
else
if
(
argv
[
i
]
!=
NULL
)
{
}
else
if
(
argv
[
i
]
!=
NULL
)
{
/* Just one non-option argument is given, this is config file */
/* Just one non-option argument is given, this is config file */
config_file
=
argv
[
i
];
config_file
=
argv
[
i
];
...
@@ -140,7 +202,8 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
...
@@ -140,7 +202,8 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
(
void
)
memset
(
vals
,
0
,
sizeof
(
vals
));
(
void
)
memset
(
vals
,
0
,
sizeof
(
vals
));
if
(
fp
!=
NULL
)
{
if
(
fp
!=
NULL
)
{
(
void
)
printf
(
"Loading config file %s
\n
"
,
config_file
);
(
void
)
printf
(
"Loading config file %s, "
"ignoring command line arguments
\n
"
,
config_file
);
/* Loop over the lines in config file */
/* Loop over the lines in config file */
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
...
@@ -156,56 +219,67 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
...
@@ -156,56 +219,67 @@ process_command_line_arguments(struct mg_context *ctx, char *argv[])
config_file
,
(
int
)
line_no
);
config_file
,
(
int
)
line_no
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
(
mg_set_option
(
ctx
,
opt
,
val
)
!=
1
)
/* TODO(lsm): free this at some point */
exit
(
EXIT_FAILURE
);
p
=
malloc
(
strlen
(
val
)
+
1
);
(
void
)
strcpy
(
p
,
val
);
set_option
(
config
,
opt
,
p
);
}
}
(
void
)
fclose
(
fp
);
(
void
)
fclose
(
fp
);
}
}
else
{
/* Now pass through the command line options */
for
(
i
=
1
;
argv
[
i
]
!=
NULL
&&
argv
[
i
][
0
]
==
'-'
;
i
+=
2
)
for
(
i
=
1
;
argv
[
i
]
!=
NULL
&&
argv
[
i
][
0
]
==
'-'
;
i
+=
2
)
if
(
mg_set_option
(
ctx
,
&
argv
[
i
][
1
],
argv
[
i
+
1
])
!=
1
)
set_option
(
config
,
&
argv
[
i
][
1
],
argv
[
i
+
1
]);
exit
(
EXIT_FAILURE
);
}
}
}
int
int
main
(
int
argc
,
char
*
argv
[])
main
(
int
argc
,
char
*
argv
[])
{
{
struct
mg_config
config
;
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
;
char
ports
[
1024
],
web_root
[
1024
];
/* Initialize configuration with default values */
(
void
)
memset
(
&
config
,
0
,
sizeof
(
config
));
config
.
document_root
=
"."
;
config
.
enable_directory_listing
=
"yes"
;
config
.
auth_domain
=
"mydomain.com"
;
config
.
num_threads
=
"20"
;
config
.
index_files
=
"index.html,index.htm,index.cgi"
;
config
.
cgi_extensions
=
".cgi,.pl,.php"
;
config
.
ssi_extensions
=
".shtml,.shtm"
;
config
.
listening_ports
=
"8080"
;
/* Edit passwords file if -A option is specified */
if
(
argc
>
1
&&
argv
[
1
][
0
]
==
'-'
&&
argv
[
1
][
1
]
==
'A'
)
{
if
(
argc
>
1
&&
argv
[
1
][
0
]
==
'-'
&&
argv
[
1
][
1
]
==
'A'
)
{
if
(
argc
!=
6
)
if
(
argc
!=
6
)
show_usage_and_exit
();
show_usage_and_exit
(
&
config
);
exit
(
mg_edit_passwords
(
argv
[
2
],
argv
[
3
],
argv
[
4
],
argv
[
5
])
==
exit
(
mg_edit_passwords
(
argv
[
2
],
argv
[
3
],
argv
[
4
],
argv
[
5
])
==
MG_SUCCESS
?
EXIT_SUCCESS
:
EXIT_FAILURE
);
MG_SUCCESS
?
EXIT_SUCCESS
:
EXIT_FAILURE
);
}
}
/* Show usage if -h or --help options are specified */
if
(
argc
==
2
&&
(
!
strcmp
(
argv
[
1
],
"-h"
)
||
!
strcmp
(
argv
[
1
],
"--help"
)))
if
(
argc
==
2
&&
(
!
strcmp
(
argv
[
1
],
"-h"
)
||
!
strcmp
(
argv
[
1
],
"--help"
)))
show_usage_and_exit
();
show_usage_and_exit
(
&
config
);
/* Update config based on command line arguments */
process_command_line_arguments
(
&
config
,
argv
);
/* Setup signal handler: quit on Ctrl-C */
#ifndef _WIN32
#ifndef _WIN32
(
void
)
signal
(
SIGCHLD
,
signal_handler
);
(
void
)
signal
(
SIGCHLD
,
signal_handler
);
#endif
/* _WIN32 */
#endif
/* _WIN32 */
(
void
)
signal
(
SIGTERM
,
signal_handler
);
(
void
)
signal
(
SIGTERM
,
signal_handler
);
(
void
)
signal
(
SIGINT
,
signal_handler
);
(
void
)
signal
(
SIGINT
,
signal_handler
);
if
((
ctx
=
mg_start
())
==
NULL
)
{
/* Start Mongoose */
if
((
ctx
=
mg_start
(
&
config
))
==
NULL
)
{
(
void
)
printf
(
"%s
\n
"
,
"Cannot initialize Mongoose context"
);
(
void
)
printf
(
"%s
\n
"
,
"Cannot initialize Mongoose context"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
process_command_line_arguments
(
ctx
,
argv
);
(
void
)
printf
(
"Mongoose %s started on port(s) %s "
(
void
)
mg_get_option
(
ctx
,
"ports"
,
ports
,
sizeof
(
ports
));
"with web root [%s]
\n
"
,
if
(
ports
[
0
]
==
'\0'
&&
mg_version
(),
config
.
listening_ports
,
config
.
document_root
);
mg_set_option
(
ctx
,
"ports"
,
"8080"
)
!=
MG_SUCCESS
)
exit
(
EXIT_FAILURE
);
(
void
)
mg_get_option
(
ctx
,
"ports"
,
ports
,
sizeof
(
ports
));
(
void
)
mg_get_option
(
ctx
,
"root"
,
web_root
,
sizeof
(
web_root
));
(
void
)
printf
(
"Mongoose %s started on port(s)
\"
%s
\"
, "
"serving directory
\"
%s
\"\n
"
,
mg_version
(),
ports
,
web_root
);
fflush
(
stdout
);
fflush
(
stdout
);
while
(
exit_flag
==
0
)
while
(
exit_flag
==
0
)
...
...
mongoose.c
View file @
5425b94f
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,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
#define
_XOPEN_SOURCE 600
/* Needed for pthread_rwlock on linux
*/
#define
_XOPEN_SOURCE 600
/* For flockfile() on Linux
*/
#define _LARGEFILE_SOURCE
/* Enable 64-bit file offsets */
#define _LARGEFILE_SOURCE
/* Enable 64-bit file offsets */
#endif
#endif
...
@@ -129,7 +129,6 @@ typedef long off_t;
...
@@ -129,7 +129,6 @@ typedef long off_t;
#endif
/* !fileno MINGW #defines fileno */
#endif
/* !fileno MINGW #defines fileno */
typedef
HANDLE
pthread_mutex_t
;
typedef
HANDLE
pthread_mutex_t
;
typedef
HANDLE
pthread_rwlock_t
;
typedef
HANDLE
pthread_cond_t
;
typedef
HANDLE
pthread_cond_t
;
typedef
DWORD
pthread_t
;
typedef
DWORD
pthread_t
;
#define pid_t HANDLE
/* MINGW typedefs pid_t to int. Using #define here. */
#define pid_t HANDLE
/* MINGW typedefs pid_t to int. Using #define here. */
...
@@ -143,13 +142,6 @@ static int pthread_mutex_lock(pthread_mutex_t *);
...
@@ -143,13 +142,6 @@ 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
);
static
FILE
*
mg_fopen
(
const
char
*
path
,
const
char
*
mode
);
/* TODO(lsm): Implement these */
#define pthread_rwlock_init pthread_mutex_init
#define pthread_rwlock_destroy pthread_mutex_destroy
#define pthread_rwlock_rdlock pthread_mutex_lock
#define pthread_rwlock_wrlock pthread_mutex_lock
#define pthread_rwlock_unlock pthread_mutex_unlock
#if defined(HAVE_STDINT)
#if defined(HAVE_STDINT)
#include <stdint.h>
#include <stdint.h>
#else
#else
...
@@ -367,27 +359,6 @@ struct mgstat {
...
@@ -367,27 +359,6 @@ struct mgstat {
time_t
mtime
;
/* Modification time */
time_t
mtime
;
/* Modification time */
};
};
struct
mg_option
{
const
char
*
name
;
const
char
*
description
;
const
char
*
default_value
;
int
index
;
enum
mg_error_t
(
*
setter
)(
struct
mg_context
*
,
const
char
*
);
};
/*
* Numeric indexes for the option values in context, ctx->options
*/
enum
mg_option_index
{
OPT_ROOT
,
OPT_INDEX_FILES
,
OPT_PORTS
,
OPT_DIR_LIST
,
OPT_CGI_EXTENSIONS
,
OPT_CGI_INTERPRETER
,
OPT_CGI_ENV
,
OPT_SSI_EXTENSIONS
,
OPT_AUTH_DOMAIN
,
OPT_AUTH_GPASSWD
,
OPT_AUTH_PUT
,
OPT_ACCESS_LOG
,
OPT_ERROR_LOG
,
OPT_SSL_CERTIFICATE
,
OPT_ALIASES
,
OPT_ACL
,
OPT_UID
,
OPT_PROTECT
,
OPT_SERVICE
,
OPT_HIDE
,
OPT_ADMIN_URI
,
OPT_MAX_THREADS
,
OPT_IDLE_TIME
,
OPT_MIME_TYPES
,
NUM_OPTIONS
};
/*
/*
* Structure used to describe listening socket, or socket which was
* Structure used to describe listening socket, or socket which was
* accept()-ed by the master thread and queued for future handling
* accept()-ed by the master thread and queued for future handling
...
@@ -407,16 +378,14 @@ struct socket {
...
@@ -407,16 +378,14 @@ struct socket {
struct
mg_context
{
struct
mg_context
{
int
stop_flag
;
/* Should we stop event loop */
int
stop_flag
;
/* Should we stop event loop */
SSL_CTX
*
ssl_ctx
;
/* SSL context */
SSL_CTX
*
ssl_ctx
;
/* SSL context */
const
struct
mg_config
*
config
;
/* Mongoose configuration */
struct
socket
*
listening_sockets
;
struct
socket
*
listening_sockets
;
char
*
options
[
NUM_OPTIONS
];
mg_callback_t
callbacks
[
NUM_EVENTS
];
int
num_threads
;
/* Number of threads */
int
num_threads
;
/* Number of threads */
int
num_idle
;
/* Number of idle threads */
int
num_idle
;
/* Number of idle threads */
pthread_mutex_t
mutex
;
/* Protects (max|num)_threads */
pthread_mutex_t
mutex
;
/* Protects (max|num)_threads */
pthread_rwlock_t
rwlock
;
/* Protects options, callbacks */
pthread_cond_t
thr_cond
;
/* Condvar for thread sync */
pthread_cond_t
thr_cond
;
/* Condvar for thread sync */
struct
socket
queue
[
20
];
/* Accepted sockets */
struct
socket
queue
[
20
];
/* Accepted sockets */
...
@@ -461,15 +430,13 @@ cry(struct mg_connection *conn, const char *fmt, ...)
...
@@ -461,15 +430,13 @@ cry(struct mg_connection *conn, const char *fmt, ...)
* I suppose this is fine, since function cannot disappear in the
* I suppose this is fine, since function cannot disappear in the
* same way string option can.
* same way string option can.
*/
*/
log_callback
=
conn
->
ctx
->
c
allbacks
[
MG_EVENT_LOG
]
;
log_callback
=
conn
->
ctx
->
c
onfig
->
event_log_handler
;
conn
->
request_info
.
log_message
=
buf
;
conn
->
request_info
.
log_message
=
buf
;
if
(
log_callback
!=
NULL
)
if
(
log_callback
!=
NULL
)
processed
=
log_callback
(
conn
,
&
conn
->
request_info
);
processed
=
log_callback
(
conn
,
&
conn
->
request_info
);
if
(
processed
==
MG_ERROR
)
{
if
(
processed
==
MG_ERROR
)
{
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
fp
=
conn
->
ctx
->
config
->
error_log_file
==
NULL
?
stderr
:
fp
=
conn
->
ctx
->
options
[
OPT_ERROR_LOG
]
==
NULL
?
stderr
:
mg_fopen
(
conn
->
ctx
->
config
->
error_log_file
,
"a+"
);
mg_fopen
(
conn
->
ctx
->
options
[
OPT_ERROR_LOG
],
"a+"
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
if
(
fp
!=
NULL
)
{
if
(
fp
!=
NULL
)
{
flockfile
(
fp
);
flockfile
(
fp
);
...
@@ -530,7 +497,7 @@ fc(struct mg_context *ctx)
...
@@ -530,7 +497,7 @@ fc(struct mg_context *ctx)
const
char
*
const
char
*
mg_version
(
void
)
mg_version
(
void
)
{
{
return
(
"
\"
"
MONGOOSE_VERSION
", $Rev: 517 $
\"
"
);
return
(
MONGOOSE_VERSION
);
}
}
static
void
static
void
...
@@ -634,22 +601,6 @@ mg_snprintf(struct mg_connection *conn,
...
@@ -634,22 +601,6 @@ mg_snprintf(struct mg_connection *conn,
return
(
n
);
return
(
n
);
}
}
/*
* Convert string representing a boolean value to a boolean value
*/
static
bool_t
is_true
(
const
char
*
str
)
{
static
const
char
*
trues
[]
=
{
"1"
,
"yes"
,
"true"
,
"ja"
,
NULL
};
int
i
;
for
(
i
=
0
;
trues
[
i
]
!=
NULL
;
i
++
)
if
(
str
!=
NULL
&&
mg_strcasecmp
(
str
,
trues
[
i
])
==
0
)
return
(
TRUE
);
return
(
FALSE
);
}
/*
/*
* Skip the characters until one of the delimiters characters found.
* Skip the characters until one of the delimiters characters found.
* 0-terminate resulting word. Skip the rest of the delimiters if any.
* 0-terminate resulting word. Skip the rest of the delimiters if any.
...
@@ -775,7 +726,7 @@ send_error(struct mg_connection *conn, int status, const char *reason,
...
@@ -775,7 +726,7 @@ send_error(struct mg_connection *conn, int status, const char *reason,
DEBUG_TRACE
((
DEBUG_MGS_PREFIX
"%s: %d %s"
,
__func__
,
status
,
reason
));
DEBUG_TRACE
((
DEBUG_MGS_PREFIX
"%s: %d %s"
,
__func__
,
status
,
reason
));
conn
->
request_info
.
status_code
=
status
;
conn
->
request_info
.
status_code
=
status
;
error_handler
=
conn
->
ctx
->
c
allbacks
[
MG_EVENT_HTTP_ERROR
]
;
error_handler
=
conn
->
ctx
->
c
onfig
->
http_error_handler
;
handled
=
error_handler
?
handled
=
error_handler
?
error_handler
(
conn
,
&
conn
->
request_info
)
:
FALSE
;
error_handler
(
conn
,
&
conn
->
request_info
)
:
FALSE
;
...
@@ -1225,7 +1176,6 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
...
@@ -1225,7 +1176,6 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
&
si
.
hStdOutput
,
0
,
TRUE
,
DUPLICATE_SAME_ACCESS
);
&
si
.
hStdOutput
,
0
,
TRUE
,
DUPLICATE_SAME_ACCESS
);
/* If CGI file is a script, try to read the interpreter line */
/* If CGI file is a script, try to read the interpreter line */
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
interp
=
conn
->
ctx
->
options
[
OPT_CGI_INTERPRETER
];
interp
=
conn
->
ctx
->
options
[
OPT_CGI_INTERPRETER
];
if
(
interp
==
NULL
)
{
if
(
interp
==
NULL
)
{
line
[
2
]
=
'\0'
;
line
[
2
]
=
'\0'
;
...
@@ -1249,7 +1199,6 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
...
@@ -1249,7 +1199,6 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
(
void
)
mg_snprintf
(
conn
,
cmdline
,
sizeof
(
cmdline
),
"%s%s%s"
,
(
void
)
mg_snprintf
(
conn
,
cmdline
,
sizeof
(
cmdline
),
"%s%s%s"
,
interp
,
interp
[
0
]
==
'\0'
?
""
:
" "
,
prog
);
interp
,
interp
[
0
]
==
'\0'
?
""
:
" "
,
prog
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
(
void
)
mg_snprintf
(
conn
,
line
,
sizeof
(
line
),
"%s"
,
dir
);
(
void
)
mg_snprintf
(
conn
,
line
,
sizeof
(
line
),
"%s"
,
dir
);
fix_directory_separators
(
line
);
fix_directory_separators
(
line
);
...
@@ -1364,7 +1313,7 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
...
@@ -1364,7 +1313,7 @@ spawn_process(struct mg_connection *conn, const char *prog, char *envblk,
(
void
)
close
(
fd_stdout
);
(
void
)
close
(
fd_stdout
);
/* Execute CGI program. No need to lock: new process */
/* Execute CGI program. No need to lock: new process */
interp
=
conn
->
ctx
->
options
[
OPT_CGI_INTERPRETER
]
;
interp
=
conn
->
ctx
->
config
->
cgi_interpreter
;
if
(
interp
==
NULL
)
{
if
(
interp
==
NULL
)
{
(
void
)
execle
(
prog
,
prog
,
NULL
,
envp
);
(
void
)
execle
(
prog
,
prog
,
NULL
,
envp
);
cry
(
conn
,
"%s: execle(%s): %s"
,
cry
(
conn
,
"%s: execle(%s): %s"
,
...
@@ -1619,30 +1568,44 @@ mg_get_cookie(const struct mg_connection *conn,
...
@@ -1619,30 +1568,44 @@ mg_get_cookie(const struct mg_connection *conn,
}
}
/*
/*
*
Transform URI to the file name
.
*
Get document root for the given URI
.
*/
*/
static
void
static
int
convert_uri_to_file_name
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
get_document_root
(
const
struct
mg_connection
*
conn
,
struct
vec
*
document_root
)
char
*
buf
,
size_t
buf_len
)
{
{
struct
mg_context
*
ctx
=
conn
->
ctx
;
const
char
*
root
,
*
uri
;
int
len_of_matched_uri
;
struct
vec
uri_vec
,
path_vec
;
struct
vec
uri_vec
,
path_vec
;
const
char
*
list
;
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
uri
=
conn
->
request_info
.
uri
;
mg_snprintf
(
conn
,
buf
,
buf_len
,
"%s%s"
,
ctx
->
options
[
OPT_ROOT
],
uri
);
len_of_matched_uri
=
0
;
root
=
next_option
(
conn
->
ctx
->
config
->
document_root
,
document_root
,
NULL
);
/* If requested URI has aliased prefix, use alternate root */
while
((
root
=
next_option
(
root
,
&
uri_vec
,
&
path_vec
))
!=
NULL
)
{
list
=
ctx
->
options
[
OPT_ALIASES
];
while
((
list
=
next_option
(
list
,
&
uri_vec
,
&
path_vec
))
!=
NULL
)
{
if
(
memcmp
(
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
)
==
0
)
{
if
(
memcmp
(
uri
,
uri_vec
.
ptr
,
uri_vec
.
len
)
==
0
)
{
(
void
)
mg_snprintf
(
conn
,
buf
,
buf_len
,
"%.*s%s"
,
*
document_root
=
path_vec
;
path_vec
.
len
,
path_vec
.
ptr
,
uri
+
uri_vec
.
len
)
;
len_of_matched_uri
=
uri_vec
.
len
;
break
;
break
;
}
}
}
}
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
return
(
len_of_matched_uri
);
}
/*
* Transform URI to the file name.
*/
static
void
convert_uri_to_file_name
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
char
*
buf
,
size_t
buf_len
)
{
struct
vec
vec
;
int
match_len
;
match_len
=
get_document_root
(
conn
,
&
vec
);
(
void
)
mg_snprintf
(
conn
,
buf
,
buf_len
,
"%.*s%s"
,
vec
.
len
,
vec
.
ptr
,
uri
+
match_len
);
#ifdef _WIN32
#ifdef _WIN32
fix_directory_separators
(
buf
);
fix_directory_separators
(
buf
);
...
@@ -1873,18 +1836,15 @@ get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
...
@@ -1873,18 +1836,15 @@ get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
* Scan user-defined mime types first, in case user wants to
* Scan user-defined mime types first, in case user wants to
* override default mime types.
* override default mime types.
*/
*/
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
list
=
ctx
->
config
->
mime_types
;
list
=
ctx
->
options
[
OPT_MIME_TYPES
];
while
((
list
=
next_option
(
list
,
&
ext_vec
,
&
mime_vec
))
!=
NULL
)
{
while
((
list
=
next_option
(
list
,
&
ext_vec
,
&
mime_vec
))
!=
NULL
)
{
/* ext now points to the path suffix */
/* ext now points to the path suffix */
ext
=
path
+
path_len
-
ext_vec
.
len
;
ext
=
path
+
path_len
-
ext_vec
.
len
;
if
(
mg_strncasecmp
(
ext
,
ext_vec
.
ptr
,
ext_vec
.
len
)
==
0
)
{
if
(
mg_strncasecmp
(
ext
,
ext_vec
.
ptr
,
ext_vec
.
len
)
==
0
)
{
*
vec
=
mime_vec
;
*
vec
=
mime_vec
;
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
return
;
return
;
}
}
}
}
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
/* Now scan built-in mime types */
/* Now scan built-in mime types */
for
(
i
=
0
;
mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
for
(
i
=
0
;
mime_types
[
i
].
extension
!=
NULL
;
i
++
)
{
...
@@ -2217,13 +2177,12 @@ open_auth_file(struct mg_connection *conn, const char *path)
...
@@ -2217,13 +2177,12 @@ open_auth_file(struct mg_connection *conn, const char *path)
struct
mgstat
st
;
struct
mgstat
st
;
FILE
*
fp
;
FILE
*
fp
;
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
if
(
ctx
->
config
->
global_passwords_file
!=
NULL
)
{
if
(
ctx
->
options
[
OPT_AUTH_GPASSWD
]
!=
NULL
)
{
/* Use global passwords file */
/* Use global passwords file */
fp
=
mg_fopen
(
ctx
->
options
[
OPT_AUTH_GPASSWD
]
,
"r"
);
fp
=
mg_fopen
(
ctx
->
config
->
global_passwords_file
,
"r"
);
if
(
fp
==
NULL
)
if
(
fp
==
NULL
)
cry
(
fc
(
ctx
),
"fopen(%s): %s"
,
cry
(
fc
(
ctx
),
"fopen(%s): %s"
,
ctx
->
options
[
OPT_AUTH_GPASSWD
]
,
strerror
(
ERRNO
));
ctx
->
config
->
global_passwords_file
,
strerror
(
ERRNO
));
}
else
if
(
!
mg_stat
(
path
,
&
st
)
&&
st
.
is_directory
)
{
}
else
if
(
!
mg_stat
(
path
,
&
st
)
&&
st
.
is_directory
)
{
(
void
)
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
(
void
)
mg_snprintf
(
conn
,
name
,
sizeof
(
name
),
"%s%c%s"
,
path
,
DIRSEP
,
PASSWORDS_FILE_NAME
);
path
,
DIRSEP
,
PASSWORDS_FILE_NAME
);
...
@@ -2249,7 +2208,6 @@ open_auth_file(struct mg_connection *conn, const char *path)
...
@@ -2249,7 +2208,6 @@ open_auth_file(struct mg_connection *conn, const char *path)
(
int
)
(
e
-
p
),
p
,
DIRSEP
,
PASSWORDS_FILE_NAME
);
(
int
)
(
e
-
p
),
p
,
DIRSEP
,
PASSWORDS_FILE_NAME
);
fp
=
mg_fopen
(
name
,
"r"
);
fp
=
mg_fopen
(
name
,
"r"
);
}
}
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
return
(
fp
);
return
(
fp
);
}
}
...
@@ -2330,24 +2288,20 @@ static bool_t
...
@@ -2330,24 +2288,20 @@ static bool_t
authorize
(
struct
mg_connection
*
conn
,
FILE
*
fp
)
authorize
(
struct
mg_connection
*
conn
,
FILE
*
fp
)
{
{
struct
ah
ah
;
struct
ah
ah
;
char
line
[
256
],
f_user
[
256
],
domain
[
256
],
ha1
[
256
],
char
line
[
256
],
f_user
[
256
],
ha1
[
256
],
f_domain
[
256
],
buf
[
MAX_REQUEST_SIZE
];
f_domain
[
256
],
buf
[
MAX_REQUEST_SIZE
];
if
(
!
parse_auth_header
(
conn
,
buf
,
sizeof
(
buf
),
&
ah
))
if
(
!
parse_auth_header
(
conn
,
buf
,
sizeof
(
buf
),
&
ah
))
return
(
FALSE
);
return
(
FALSE
);
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
mg_strlcpy
(
domain
,
conn
->
ctx
->
options
[
OPT_AUTH_DOMAIN
],
sizeof
(
domain
));
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
/* Loop over passwords file */
/* Loop over passwords file */
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
if
(
sscanf
(
line
,
"%[^:]:%[^:]:%s"
,
f_user
,
f_domain
,
ha1
)
!=
3
)
if
(
sscanf
(
line
,
"%[^:]:%[^:]:%s"
,
f_user
,
f_domain
,
ha1
)
!=
3
)
continue
;
continue
;
if
(
!
strcmp
(
ah
.
user
,
f_user
)
&&
!
strcmp
(
domain
,
f_domain
))
if
(
!
strcmp
(
ah
.
user
,
f_user
)
&&
!
strcmp
(
conn
->
ctx
->
config
->
auth_domain
,
f_domain
))
return
(
check_password
(
return
(
check_password
(
conn
->
request_info
.
request_method
,
conn
->
request_info
.
request_method
,
ha1
,
ah
.
uri
,
ah
.
nonce
,
ah
.
nc
,
ah
.
cnonce
,
ah
.
qop
,
ha1
,
ah
.
uri
,
ah
.
nonce
,
ah
.
nc
,
ah
.
cnonce
,
ah
.
qop
,
...
@@ -2372,8 +2326,7 @@ check_authorization(struct mg_connection *conn, const char *path)
...
@@ -2372,8 +2326,7 @@ check_authorization(struct mg_connection *conn, const char *path)
fp
=
NULL
;
fp
=
NULL
;
authorized
=
TRUE
;
authorized
=
TRUE
;
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
list
=
conn
->
ctx
->
config
->
protect
;
list
=
conn
->
ctx
->
options
[
OPT_PROTECT
];
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
))
{
(
void
)
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
(
void
)
mg_snprintf
(
conn
,
fname
,
sizeof
(
fname
),
"%.*s"
,
...
@@ -2384,7 +2337,6 @@ check_authorization(struct mg_connection *conn, const char *path)
...
@@ -2384,7 +2337,6 @@ check_authorization(struct mg_connection *conn, const char *path)
break
;
break
;
}
}
}
}
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
if
(
fp
==
NULL
)
if
(
fp
==
NULL
)
fp
=
open_auth_file
(
conn
,
path
);
fp
=
open_auth_file
(
conn
,
path
);
...
@@ -2400,18 +2352,13 @@ check_authorization(struct mg_connection *conn, const char *path)
...
@@ -2400,18 +2352,13 @@ check_authorization(struct mg_connection *conn, const char *path)
static
void
static
void
send_authorization_request
(
struct
mg_connection
*
conn
)
send_authorization_request
(
struct
mg_connection
*
conn
)
{
{
char
domain
[
128
];
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
mg_strlcpy
(
domain
,
conn
->
ctx
->
options
[
OPT_AUTH_DOMAIN
],
sizeof
(
domain
));
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
conn
->
request_info
.
status_code
=
401
;
conn
->
request_info
.
status_code
=
401
;
(
void
)
mg_printf
(
conn
,
(
void
)
mg_printf
(
conn
,
"HTTP/1.1 401 Unauthorized
\r\n
"
"HTTP/1.1 401 Unauthorized
\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
"
,
domain
,
(
unsigned
long
)
time
(
NULL
));
conn
->
ctx
->
config
->
auth_domain
,
(
unsigned
long
)
time
(
NULL
));
}
}
static
bool_t
static
bool_t
...
@@ -2420,10 +2367,8 @@ is_authorized_for_put(struct mg_connection *conn)
...
@@ -2420,10 +2367,8 @@ is_authorized_for_put(struct mg_connection *conn)
FILE
*
fp
;
FILE
*
fp
;
int
ret
=
FALSE
;
int
ret
=
FALSE
;
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
fp
=
conn
->
ctx
->
config
->
put_delete_passwords_file
==
NULL
?
NULL
:
fp
=
conn
->
ctx
->
options
[
OPT_AUTH_PUT
]
==
NULL
?
NULL
:
mg_fopen
(
conn
->
ctx
->
config
->
put_delete_passwords_file
,
"r"
);
mg_fopen
(
conn
->
ctx
->
options
[
OPT_AUTH_PUT
],
"r"
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
if
(
fp
!=
NULL
)
{
if
(
fp
!=
NULL
)
{
...
@@ -2439,16 +2384,13 @@ mg_modify_passwords_file(struct mg_context *ctx, const char *fname,
...
@@ -2439,16 +2384,13 @@ mg_modify_passwords_file(struct mg_context *ctx, const char *fname,
const
char
*
user
,
const
char
*
pass
)
const
char
*
user
,
const
char
*
pass
)
{
{
int
found
;
int
found
;
char
line
[
512
],
u
[
512
],
d
[
512
],
domain
[
512
],
char
line
[
512
],
u
[
512
],
d
[
512
],
ha1
[
33
],
tmp
[
FILENAME_MAX
];
ha1
[
33
],
tmp
[
FILENAME_MAX
]
;
const
char
*
domain
;
FILE
*
fp
,
*
fp2
;
FILE
*
fp
,
*
fp2
;
found
=
0
;
found
=
0
;
fp
=
fp2
=
NULL
;
fp
=
fp2
=
NULL
;
domain
=
ctx
->
config
->
auth_domain
;
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
mg_strlcpy
(
domain
,
ctx
->
options
[
OPT_AUTH_DOMAIN
],
sizeof
(
domain
));
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
/* Regard empty password as no password - remove user record. */
/* Regard empty password as no password - remove user record. */
if
(
pass
[
0
]
==
'\0'
)
if
(
pass
[
0
]
==
'\0'
)
...
@@ -2731,7 +2673,7 @@ send_opened_file_stream(struct mg_connection *conn, FILE *fp, int64_t len)
...
@@ -2731,7 +2673,7 @@ send_opened_file_stream(struct mg_connection *conn, FILE *fp, int64_t len)
static
int
static
int
parse_range_header
(
const
char
*
header
,
int64_t
*
a
,
int64_t
*
b
)
parse_range_header
(
const
char
*
header
,
int64_t
*
a
,
int64_t
*
b
)
{
{
return
sscanf
(
header
,
"bytes=%"
INT64_FMT
"
u-%"
INT64_FMT
"u"
,
a
,
b
);
return
sscanf
(
header
,
"bytes=%"
INT64_FMT
"
-%"
INT64_FMT
,
a
,
b
);
}
}
/*
/*
...
@@ -2906,8 +2848,7 @@ substitute_index_file(struct mg_connection *conn,
...
@@ -2906,8 +2848,7 @@ substitute_index_file(struct mg_connection *conn,
* Traverse index files list. For each entry, append it to the given
* Traverse index files list. For each entry, append it to the given
* path and see if the file exists. If it exists, break the loop
* path and see if the file exists. If it exists, break the loop
*/
*/
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
list
=
conn
->
ctx
->
config
->
index_files
;
list
=
conn
->
ctx
->
options
[
OPT_INDEX_FILES
];
found
=
FALSE
;
found
=
FALSE
;
while
((
list
=
next_option
(
list
,
&
filename_vec
,
NULL
))
!=
NULL
)
{
while
((
list
=
next_option
(
list
,
&
filename_vec
,
NULL
))
!=
NULL
)
{
...
@@ -2928,7 +2869,6 @@ substitute_index_file(struct mg_connection *conn,
...
@@ -2928,7 +2869,6 @@ substitute_index_file(struct mg_connection *conn,
break
;
break
;
}
}
}
}
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
/* If no index file exists, restore directory path */
/* If no index file exists, restore directory path */
if
(
found
==
FALSE
)
if
(
found
==
FALSE
)
...
@@ -3100,7 +3040,7 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
...
@@ -3100,7 +3040,7 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
struct
cgi_env_block
*
blk
)
struct
cgi_env_block
*
blk
)
{
{
const
char
*
s
,
*
script_filename
,
*
slash
;
const
char
*
s
,
*
script_filename
,
*
slash
;
struct
vec
var_vec
;
struct
vec
var_vec
,
root
;
char
*
p
;
char
*
p
;
int
i
;
int
i
;
...
@@ -3112,11 +3052,11 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
...
@@ -3112,11 +3052,11 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
if
((
s
=
strrchr
(
prog
,
'/'
))
!=
NULL
)
if
((
s
=
strrchr
(
prog
,
'/'
))
!=
NULL
)
script_filename
=
s
+
1
;
script_filename
=
s
+
1
;
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
get_document_root
(
conn
,
&
root
);
addenv
(
blk
,
"SERVER_NAME=%s"
,
conn
->
ctx
->
options
[
OPT_AUTH_DOMAIN
]);
addenv
(
blk
,
"SERVER_
ROOT=%s"
,
conn
->
ctx
->
options
[
OPT_ROOT
]
);
addenv
(
blk
,
"SERVER_
NAME=%s"
,
conn
->
ctx
->
config
->
auth_domain
);
addenv
(
blk
,
"
DOCUMENT_ROOT=%s"
,
conn
->
ctx
->
options
[
OPT_ROOT
]
);
addenv
(
blk
,
"
SERVER_ROOT=%.*s"
,
root
.
len
,
root
.
ptr
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
addenv
(
blk
,
"DOCUMENT_ROOT=%.*s"
,
root
.
len
,
root
.
ptr
);
/* Prepare the environment block */
/* Prepare the environment block */
addenv
(
blk
,
"%s"
,
"GATEWAY_INTERFACE=CGI/1.1"
);
addenv
(
blk
,
"%s"
,
"GATEWAY_INTERFACE=CGI/1.1"
);
...
@@ -3183,11 +3123,9 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
...
@@ -3183,11 +3123,9 @@ prepare_cgi_environment(struct mg_connection *conn, const char *prog,
}
}
/* Add user-specified variables */
/* Add user-specified variables */
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
s
=
conn
->
ctx
->
config
->
cgi_environment
;
s
=
conn
->
ctx
->
options
[
OPT_CGI_ENV
];
while
((
s
=
next_option
(
s
,
&
var_vec
,
NULL
))
!=
NULL
)
while
((
s
=
next_option
(
s
,
&
var_vec
,
NULL
))
!=
NULL
)
addenv
(
blk
,
"%.*s"
,
var_vec
.
len
,
var_vec
.
ptr
);
addenv
(
blk
,
"%.*s"
,
var_vec
.
len
,
var_vec
.
ptr
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
blk
->
vars
[
blk
->
nvars
++
]
=
NULL
;
blk
->
vars
[
blk
->
nvars
++
]
=
NULL
;
blk
->
buf
[
blk
->
len
++
]
=
'\0'
;
blk
->
buf
[
blk
->
len
++
]
=
'\0'
;
...
@@ -3386,19 +3324,20 @@ do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag,
...
@@ -3386,19 +3324,20 @@ do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag,
int
include_level
)
int
include_level
)
{
{
char
file_name
[
BUFSIZ
],
path
[
FILENAME_MAX
],
*
p
;
char
file_name
[
BUFSIZ
],
path
[
FILENAME_MAX
],
*
p
;
struct
vec
root
;
bool_t
is_ssi
;
bool_t
is_ssi
;
FILE
*
fp
;
FILE
*
fp
;
get_document_root
(
conn
,
&
root
);
/*
/*
* sscanf() is safe here, since send_ssi_file() also uses buffer
* sscanf() is safe here, since send_ssi_file() also uses buffer
* of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ.
* of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ.
*/
*/
if
(
sscanf
(
tag
,
" virtual=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
if
(
sscanf
(
tag
,
" virtual=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
/* File name is relative to the webserver root */
/* File name is relative to the webserver root */
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%.*s%c%s"
,
(
void
)
mg_snprintf
(
conn
,
path
,
sizeof
(
path
),
"%s%c%s"
,
root
.
len
,
root
.
ptr
,
DIRSEP
,
file_name
);
conn
->
ctx
->
options
[
OPT_ROOT
],
DIRSEP
,
file_name
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
}
else
if
(
sscanf
(
tag
,
" file=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
}
else
if
(
sscanf
(
tag
,
" file=
\"
%[^
\"
]
\"
"
,
file_name
)
==
1
)
{
/*
/*
* File name is relative to the webserver working directory
* File name is relative to the webserver working directory
...
@@ -3422,10 +3361,8 @@ do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag,
...
@@ -3422,10 +3361,8 @@ do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag,
tag
,
path
,
strerror
(
ERRNO
));
tag
,
path
,
strerror
(
ERRNO
));
}
else
{
}
else
{
set_close_on_exec
(
fileno
(
fp
));
set_close_on_exec
(
fileno
(
fp
));
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
is_ssi
=
match_extension
(
path
,
is_ssi
=
match_extension
(
path
,
conn
->
ctx
->
options
[
OPT_SSI_EXTENSIONS
]);
conn
->
ctx
->
config
->
ssi_extensions
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
if
(
is_ssi
)
{
if
(
is_ssi
)
{
send_ssi_file
(
conn
,
path
,
fp
,
include_level
+
1
);
send_ssi_file
(
conn
,
path
,
fp
,
include_level
+
1
);
}
else
{
}
else
{
...
@@ -3542,7 +3479,7 @@ send_ssi(struct mg_connection *conn, const char *path)
...
@@ -3542,7 +3479,7 @@ send_ssi(struct mg_connection *conn, const char *path)
* a directory, or call embedded function, etcetera.
* a directory, or call embedded function, etcetera.
*/
*/
static
void
static
void
analyz
e_request
(
struct
mg_connection
*
conn
)
handl
e_request
(
struct
mg_connection
*
conn
)
{
{
struct
mg_request_info
*
ri
;
struct
mg_request_info
*
ri
;
char
path
[
FILENAME_MAX
];
char
path
[
FILENAME_MAX
];
...
@@ -3555,7 +3492,7 @@ analyze_request(struct mg_connection *conn)
...
@@ -3555,7 +3492,7 @@ analyze_request(struct mg_connection *conn)
if
((
conn
->
request_info
.
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
if
((
conn
->
request_info
.
query_string
=
strchr
(
ri
->
uri
,
'?'
))
!=
NULL
)
*
conn
->
request_info
.
query_string
++
=
'\0'
;
*
conn
->
request_info
.
query_string
++
=
'\0'
;
uri_len
=
strlen
(
ri
->
uri
);
uri_len
=
strlen
(
ri
->
uri
);
new_request_callback
=
conn
->
ctx
->
c
allbacks
[
MG_EVENT_NEW_REQUEST
]
;
new_request_callback
=
conn
->
ctx
->
c
onfig
->
new_request_handler
;
(
void
)
url_decode
(
ri
->
uri
,
uri_len
,
ri
->
uri
,
uri_len
+
1
,
FALSE
);
(
void
)
url_decode
(
ri
->
uri
,
uri_len
,
ri
->
uri
,
uri_len
+
1
,
FALSE
);
remove_double_dots_and_double_slashes
(
ri
->
uri
);
remove_double_dots_and_double_slashes
(
ri
->
uri
);
convert_uri_to_file_name
(
conn
,
ri
->
uri
,
path
,
sizeof
(
path
));
convert_uri_to_file_name
(
conn
,
ri
->
uri
,
path
,
sizeof
(
path
));
...
@@ -3567,9 +3504,11 @@ analyze_request(struct mg_connection *conn)
...
@@ -3567,9 +3504,11 @@ analyze_request(struct mg_connection *conn)
}
else
if
(
strstr
(
path
,
PASSWORDS_FILE_NAME
))
{
}
else
if
(
strstr
(
path
,
PASSWORDS_FILE_NAME
))
{
/* Do not allow to view passwords files */
/* Do not allow to view passwords files */
send_error
(
conn
,
403
,
"Forbidden"
,
"Access Forbidden"
);
send_error
(
conn
,
403
,
"Forbidden"
,
"Access Forbidden"
);
}
else
if
(
conn
->
ctx
->
config
->
document_root
==
NULL
)
{
send_error
(
conn
,
404
,
"Not Found"
,
"Not Found"
);
}
else
if
((
!
strcmp
(
ri
->
request_method
,
"PUT"
)
||
}
else
if
((
!
strcmp
(
ri
->
request_method
,
"PUT"
)
||
!
strcmp
(
ri
->
request_method
,
"DELETE"
))
&&
!
strcmp
(
ri
->
request_method
,
"DELETE"
))
&&
(
conn
->
ctx
->
options
[
OPT_AUTH_PUT
]
==
NULL
||
(
conn
->
ctx
->
config
->
put_delete_passwords_file
==
NULL
||
!
is_authorized_for_put
(
conn
)))
{
!
is_authorized_for_put
(
conn
)))
{
send_authorization_request
(
conn
);
send_authorization_request
(
conn
);
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"PUT"
))
{
}
else
if
(
!
strcmp
(
ri
->
request_method
,
"PUT"
))
{
...
@@ -3588,15 +3527,14 @@ analyze_request(struct mg_connection *conn)
...
@@ -3588,15 +3527,14 @@ analyze_request(struct mg_connection *conn)
"Location: %s/
\r\n\r\n
"
,
ri
->
uri
);
"Location: %s/
\r\n\r\n
"
,
ri
->
uri
);
}
else
if
(
st
.
is_directory
&&
}
else
if
(
st
.
is_directory
&&
substitute_index_file
(
conn
,
path
,
sizeof
(
path
),
&
st
)
==
FALSE
)
{
substitute_index_file
(
conn
,
path
,
sizeof
(
path
),
&
st
)
==
FALSE
)
{
if
(
is_true
(
conn
->
ctx
->
options
[
OPT_DIR_LIST
])
)
{
if
(
conn
->
ctx
->
config
->
enable_directory_listing
)
{
send_directory
(
conn
,
path
);
send_directory
(
conn
,
path
);
}
else
{
}
else
{
send_error
(
conn
,
403
,
"Directory Listing Denied"
,
send_error
(
conn
,
403
,
"Directory Listing Denied"
,
"Directory listing denied"
);
"Directory listing denied"
);
}
}
#if !defined(NO_CGI)
#if !defined(NO_CGI)
}
else
if
(
match_extension
(
path
,
}
else
if
(
match_extension
(
path
,
conn
->
ctx
->
config
->
cgi_extensions
))
{
conn
->
ctx
->
options
[
OPT_CGI_EXTENSIONS
]))
{
if
(
strcmp
(
ri
->
request_method
,
"POST"
)
&&
if
(
strcmp
(
ri
->
request_method
,
"POST"
)
&&
strcmp
(
ri
->
request_method
,
"GET"
))
{
strcmp
(
ri
->
request_method
,
"GET"
))
{
send_error
(
conn
,
501
,
"Not Implemented"
,
send_error
(
conn
,
501
,
"Not Implemented"
,
...
@@ -3606,8 +3544,7 @@ analyze_request(struct mg_connection *conn)
...
@@ -3606,8 +3544,7 @@ analyze_request(struct mg_connection *conn)
}
}
#endif
/* NO_CGI */
#endif
/* NO_CGI */
#if !defined(NO_SSI)
#if !defined(NO_SSI)
}
else
if
(
match_extension
(
path
,
}
else
if
(
match_extension
(
path
,
conn
->
ctx
->
config
->
ssi_extensions
))
{
conn
->
ctx
->
options
[
OPT_SSI_EXTENSIONS
]))
{
send_ssi
(
conn
,
path
);
send_ssi
(
conn
,
path
);
#endif
/* NO_SSI */
#endif
/* NO_SSI */
}
else
if
(
is_not_modified
(
conn
,
&
st
))
{
}
else
if
(
is_not_modified
(
conn
,
&
st
))
{
...
@@ -3630,12 +3567,13 @@ close_all_listening_sockets(struct mg_context *ctx)
...
@@ -3630,12 +3567,13 @@ close_all_listening_sockets(struct mg_context *ctx)
}
}
static
enum
mg_error_t
static
enum
mg_error_t
set_ports_option
(
struct
mg_context
*
ctx
,
const
char
*
list
)
set_ports_option
(
struct
mg_context
*
ctx
)
{
{
SOCKET
sock
;
SOCKET
sock
;
int
is_ssl
;
int
is_ssl
;
struct
vec
vec
;
struct
vec
vec
;
struct
socket
*
listener
;
struct
socket
*
listener
;
const
char
*
list
=
ctx
->
config
->
listening_ports
;
close_all_listening_sockets
(
ctx
);
close_all_listening_sockets
(
ctx
);
...
@@ -3685,10 +3623,8 @@ log_access(const struct mg_connection *conn)
...
@@ -3685,10 +3623,8 @@ log_access(const struct mg_connection *conn)
FILE
*
fp
;
FILE
*
fp
;
char
date
[
64
];
char
date
[
64
];
(
void
)
pthread_rwlock_rdlock
(
&
conn
->
ctx
->
rwlock
);
fp
=
conn
->
ctx
->
config
->
access_log_file
==
NULL
?
NULL
:
fp
=
conn
->
ctx
->
options
[
OPT_ACCESS_LOG
]
==
NULL
?
NULL
:
mg_fopen
(
conn
->
ctx
->
config
->
access_log_file
,
"a+"
);
mg_fopen
(
conn
->
ctx
->
options
[
OPT_ACCESS_LOG
],
"a+"
);
(
void
)
pthread_rwlock_unlock
(
&
conn
->
ctx
->
rwlock
);
if
(
fp
==
NULL
)
if
(
fp
==
NULL
)
return
;
return
;
...
@@ -3728,12 +3664,16 @@ isbyte(int n) {
...
@@ -3728,12 +3664,16 @@ isbyte(int n) {
* Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
* Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
*/
*/
static
enum
mg_error_t
static
enum
mg_error_t
check_acl
(
struct
mg_context
*
ctx
,
const
char
*
list
,
const
struct
usa
*
usa
)
check_acl
(
struct
mg_context
*
ctx
,
const
struct
usa
*
usa
)
{
{
int
a
,
b
,
c
,
d
,
n
,
mask
,
allowed
;
int
a
,
b
,
c
,
d
,
n
,
mask
,
allowed
;
char
flag
;
char
flag
;
uint32_t
acl_subnet
,
acl_mask
,
remote_ip
;
uint32_t
acl_subnet
,
acl_mask
,
remote_ip
;
struct
vec
vec
;
struct
vec
vec
;
const
char
*
list
=
ctx
->
config
->
acl
;
if
(
list
==
NULL
)
return
(
MG_SUCCESS
);
(
void
)
memcpy
(
&
remote_ip
,
&
usa
->
u
.
sin
.
sin_addr
,
sizeof
(
remote_ip
));
(
void
)
memcpy
(
&
remote_ip
,
&
usa
->
u
.
sin
.
sin_addr
,
sizeof
(
remote_ip
));
...
@@ -3783,48 +3723,17 @@ add_to_set(SOCKET fd, fd_set *set, int *max_fd)
...
@@ -3783,48 +3723,17 @@ add_to_set(SOCKET fd, fd_set *set, int *max_fd)
*
max_fd
=
(
int
)
fd
;
*
max_fd
=
(
int
)
fd
;
}
}
/*
* Deallocate mongoose context, free up the resources
*/
static
void
mg_fini
(
struct
mg_context
*
ctx
)
{
int
i
;
close_all_listening_sockets
(
ctx
);
/* Wait until all threads finish */
(
void
)
pthread_mutex_lock
(
&
ctx
->
mutex
);
while
(
ctx
->
num_threads
>
0
)
(
void
)
pthread_cond_wait
(
&
ctx
->
thr_cond
,
&
ctx
->
mutex
);
(
void
)
pthread_mutex_unlock
(
&
ctx
->
mutex
);
/* Deallocate all options */
for
(
i
=
0
;
i
<
NUM_OPTIONS
;
i
++
)
if
(
ctx
->
options
[
i
]
!=
NULL
)
free
(
ctx
->
options
[
i
]);
/* Deallocate SSL context */
if
(
ctx
->
ssl_ctx
)
SSL_CTX_free
(
ctx
->
ssl_ctx
);
(
void
)
pthread_rwlock_destroy
(
&
ctx
->
rwlock
);
(
void
)
pthread_mutex_destroy
(
&
ctx
->
mutex
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
thr_cond
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
empty_cond
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
full_cond
);
/* Signal mg_stop() that we're done */
ctx
->
stop_flag
=
2
;
}
#if !defined(_WIN32)
#if !defined(_WIN32)
static
enum
mg_error_t
static
enum
mg_error_t
set_uid_option
(
struct
mg_context
*
ctx
,
const
char
*
uid
)
set_uid_option
(
struct
mg_context
*
ctx
)
{
{
struct
passwd
*
pw
;
struct
passwd
*
pw
;
enum
mg_error_t
error
=
MG_ERROR
;
const
char
*
uid
=
ctx
->
config
->
uid
;
enum
mg_error_t
error
;
if
(
uid
==
NULL
)
{
error
=
MG_SUCCESS
;
}
else
{
if
((
pw
=
getpwnam
(
uid
))
==
NULL
)
if
((
pw
=
getpwnam
(
uid
))
==
NULL
)
cry
(
fc
(
ctx
),
"%s: unknown user [%s]"
,
__func__
,
uid
);
cry
(
fc
(
ctx
),
"%s: unknown user [%s]"
,
__func__
,
uid
);
else
if
(
setgid
(
pw
->
pw_gid
)
==
-
1
)
else
if
(
setgid
(
pw
->
pw_gid
)
==
-
1
)
...
@@ -3835,6 +3744,7 @@ set_uid_option(struct mg_context *ctx, const char *uid)
...
@@ -3835,6 +3744,7 @@ set_uid_option(struct mg_context *ctx, const char *uid)
__func__
,
uid
,
strerror
(
errno
));
__func__
,
uid
,
strerror
(
errno
));
else
else
error
=
MG_SUCCESS
;
error
=
MG_SUCCESS
;
}
return
(
error
);
return
(
error
);
}
}
...
@@ -3900,10 +3810,14 @@ load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
...
@@ -3900,10 +3810,14 @@ load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
* Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
* Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
*/
*/
static
enum
mg_error_t
static
enum
mg_error_t
set_ssl_option
(
struct
mg_context
*
ctx
,
const
char
*
pem
)
set_ssl_option
(
struct
mg_context
*
ctx
)
{
{
SSL_CTX
*
CTX
;
SSL_CTX
*
CTX
;
int
i
,
size
;
int
i
,
size
;
const
char
*
pem
=
ctx
->
config
->
ssl_certificate
;
if
(
pem
==
NULL
)
return
(
MG_SUCCESS
);
if
(
load_dll
(
ctx
,
SSL_LIB
,
ssl_sw
)
==
FALSE
||
if
(
load_dll
(
ctx
,
SSL_LIB
,
ssl_sw
)
==
FALSE
||
load_dll
(
ctx
,
CRYPTO_LIB
,
crypto_sw
)
==
FALSE
)
load_dll
(
ctx
,
CRYPTO_LIB
,
crypto_sw
)
==
FALSE
)
...
@@ -3915,9 +3829,9 @@ set_ssl_option(struct mg_context *ctx, const char *pem)
...
@@ -3915,9 +3829,9 @@ set_ssl_option(struct mg_context *ctx, const char *pem)
if
((
CTX
=
SSL_CTX_new
(
SSLv23_server_method
()))
==
NULL
)
if
((
CTX
=
SSL_CTX_new
(
SSLv23_server_method
()))
==
NULL
)
ssl_cry
(
fc
(
ctx
),
"SSL_CTX_new error"
);
ssl_cry
(
fc
(
ctx
),
"SSL_CTX_new error"
);
else
if
(
ctx
->
c
allbacks
[
MG_EVENT_SSL_PASSWORD
]
!=
NULL
)
else
if
(
ctx
->
c
onfig
->
ssl_password_handler
!=
NULL
)
SSL_CTX_set_default_passwd_cb
(
CTX
,
SSL_CTX_set_default_passwd_cb
(
CTX
,
ctx
->
callbacks
[
MG_EVENT_SSL_PASSWORD
]
);
ctx
->
config
->
ssl_password_handler
);
if
(
CTX
!=
NULL
&&
SSL_CTX_use_certificate_file
(
if
(
CTX
!=
NULL
&&
SSL_CTX_use_certificate_file
(
CTX
,
pem
,
SSL_FILETYPE_PEM
)
==
0
)
{
CTX
,
pem
,
SSL_FILETYPE_PEM
)
==
0
)
{
...
@@ -3953,247 +3867,40 @@ set_ssl_option(struct mg_context *ctx, const char *pem)
...
@@ -3953,247 +3867,40 @@ set_ssl_option(struct mg_context *ctx, const char *pem)
#endif
/* !NO_SSL */
#endif
/* !NO_SSL */
static
enum
mg_error_t
static
enum
mg_error_t
set_gpass_option
(
struct
mg_context
*
ctx
,
const
char
*
path
)
set_gpass_option
(
struct
mg_context
*
ctx
)
{
{
struct
mgstat
mgstat
;
struct
mgstat
mgstat
;
ctx
=
NULL
;
const
char
*
path
=
ctx
->
config
->
global_passwords_file
;
return
(
mg_stat
(
path
,
&
mgstat
)
==
0
?
MG_SUCCESS
:
MG_ERROR
);
}
static
enum
mg_error_t
return
(
path
==
NULL
||
mg_stat
(
path
,
&
mgstat
)
==
0
?
set_acl_option
(
struct
mg_context
*
ctx
,
const
char
*
acl
)
MG_SUCCESS
:
MG_ERROR
);
{
struct
usa
fake
;
return
(
check_acl
(
ctx
,
acl
,
&
fake
));
}
}
/*
* Check if the comma-separated list of options has a format of key-value
* pairs: "k1=v1,k2=v2". Return FALSE if any entry has invalid key or value.
*/
static
enum
mg_error_t
static
enum
mg_error_t
set_
kv_list_option
(
struct
mg_context
*
ctx
,
const
char
*
str
)
set_
acl_option
(
struct
mg_context
*
ctx
)
{
{
const
char
*
list
;
struct
usa
fake
;
struct
vec
key
,
value
;
return
(
check_acl
(
ctx
,
&
fake
));
list
=
str
;
while
((
list
=
next_option
(
list
,
&
key
,
&
value
))
!=
NULL
)
if
(
key
.
len
==
0
||
value
.
len
==
0
)
{
cry
(
fc
(
ctx
),
"Invalid list specified: [%s], "
"expecting key1=value1,key2=value2,..."
,
str
);
return
(
MG_ERROR
);
}
return
(
MG_SUCCESS
);
}
}
static
enum
mg_error
_t
static
bool
_t
set_root_option
(
struct
mg_context
*
ctx
,
const
char
*
root
)
verify_document_root
(
struct
mg_context
*
ctx
,
const
char
*
root
)
{
{
char
path
[
FILENAME_MAX
],
*
p
;
struct
mgstat
buf
;
struct
mgstat
buf
;
if
(
mg_stat
(
root
,
&
buf
)
!=
0
)
{
cry
(
fc
(
ctx
),
"Invalid root directory:
\"
%s
\"
"
,
root
);
return
(
MG_ERROR
);
}
return
(
MG_SUCCESS
);
}
static
const
struct
mg_option
known_options
[]
=
{
{
"root"
,
"
\t
Web root directory"
,
"."
,
OPT_ROOT
,
set_root_option
},
{
"index_files"
,
"Index files"
,
"index.html,index.htm,index.cgi"
,
OPT_INDEX_FILES
,
NULL
},
#if !defined(NO_SSL)
{
"ssl_cert"
,
"SSL certificate file"
,
NULL
,
OPT_SSL_CERTIFICATE
,
&
set_ssl_option
},
#endif
/* !NO_SSL */
{
"ports"
,
"Listening ports"
,
NULL
,
OPT_PORTS
,
&
set_ports_option
},
{
"dir_list"
,
"Directory listing"
,
"yes"
,
OPT_DIR_LIST
,
NULL
},
{
"protect"
,
"URI to htpasswd mapping"
,
NULL
,
OPT_PROTECT
,
&
set_kv_list_option
},
#if !defined(NO_CGI)
{
"cgi_ext"
,
"CGI extensions"
,
".cgi,.pl,.php"
,
OPT_CGI_EXTENSIONS
,
NULL
},
{
"cgi_interp"
,
"CGI interpreter to use with all CGI scripts"
,
NULL
,
OPT_CGI_INTERPRETER
,
NULL
},
{
"cgi_env"
,
"Custom CGI enviroment variables"
,
NULL
,
OPT_CGI_ENV
,
&
set_kv_list_option
},
#endif
/* NO_CGI */
{
"ssi_ext"
,
"SSI extensions"
,
".shtml,.shtm"
,
OPT_SSI_EXTENSIONS
,
NULL
},
{
"auth_realm"
,
"Authentication domain name"
,
"mydomain.com"
,
OPT_AUTH_DOMAIN
,
NULL
},
{
"auth_gpass"
,
"Global passwords file"
,
NULL
,
OPT_AUTH_GPASSWD
,
&
set_gpass_option
},
{
"auth_PUT"
,
"PUT,DELETE auth file"
,
NULL
,
OPT_AUTH_PUT
,
NULL
},
#if !defined(_WIN32)
{
"uid"
,
"
\t
Run as user"
,
NULL
,
OPT_UID
,
&
set_uid_option
},
#endif
/* !_WIN32 */
{
"access_log"
,
"Access log file"
,
NULL
,
OPT_ACCESS_LOG
,
NULL
},
{
"error_log"
,
"Error log file"
,
NULL
,
OPT_ERROR_LOG
,
NULL
},
{
"aliases"
,
"Path=URI mappings"
,
NULL
,
OPT_ALIASES
,
&
set_kv_list_option
},
{
"admin_uri"
,
"Administration page URI"
,
NULL
,
OPT_ADMIN_URI
,
NULL
},
{
"acl"
,
"
\t
Allow/deny IP addresses/subnets"
,
NULL
,
OPT_ACL
,
&
set_acl_option
},
{
"max_threads"
,
"Maximum simultaneous threads to spawn"
,
"100"
,
OPT_MAX_THREADS
,
NULL
},
{
"idle_time"
,
"Time in seconds connection stays idle"
,
"10"
,
OPT_IDLE_TIME
,
NULL
},
{
"mime_types"
,
"Comma separated list of ext=mime_type pairs"
,
NULL
,
OPT_MIME_TYPES
,
&
set_kv_list_option
},
{
NULL
,
NULL
,
NULL
,
0
,
NULL
}
};
static
const
struct
mg_option
*
find_opt
(
const
char
*
opt_name
)
{
int
i
;
for
(
i
=
0
;
known_options
[
i
].
name
!=
NULL
;
i
++
)
if
(
!
strcmp
(
opt_name
,
known_options
[
i
].
name
))
return
(
known_options
+
i
);
return
(
NULL
);
}
enum
mg_error_t
mg_set_option
(
struct
mg_context
*
ctx
,
const
char
*
opt
,
const
char
*
val
)
{
const
struct
mg_option
*
option
;
int
i
,
error
;
DEBUG_TRACE
((
DEBUG_MGS_PREFIX
"%s: [%s]->[%s]"
,
__func__
,
opt
,
val
));
if
(
opt
!=
NULL
&&
(
option
=
find_opt
(
opt
))
!=
NULL
)
{
i
=
(
int
)
(
option
-
known_options
);
error
=
option
->
setter
?
option
->
setter
(
ctx
,
val
)
:
MG_SUCCESS
;
/*
* Write lock the option. Free old value, set new value.
* Make sure no calls that may trigger read lock are made.
*/
(
void
)
pthread_rwlock_wrlock
(
&
ctx
->
rwlock
);
if
(
ctx
->
options
[
option
->
index
]
!=
NULL
)
free
(
ctx
->
options
[
option
->
index
]);
ctx
->
options
[
option
->
index
]
=
val
?
mg_strdup
(
val
)
:
NULL
;
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
if
(
error
!=
MG_SUCCESS
)
cry
(
fc
(
ctx
),
"%s(%s): failure"
,
__func__
,
opt
);
}
else
{
cry
(
fc
(
ctx
),
"%s: No such option: [%s]"
,
__func__
,
opt
);
error
=
MG_NOT_FOUND
;
}
return
(
error
);
}
void
mg_show_usage_string
(
FILE
*
fp
)
{
const
struct
mg_option
*
o
;
(
void
)
fprintf
(
stderr
,
"Mongoose version %s (c) Sergey Lyubka
\n
"
"usage: mongoose [options] [config_file]
\n
"
,
mg_version
());
fprintf
(
fp
,
" -A <htpasswd_file> <realm> <user> <passwd>
\n
"
);
for
(
o
=
known_options
;
o
->
name
!=
NULL
;
o
++
)
{
(
void
)
fprintf
(
fp
,
" -%s
\t
%s"
,
o
->
name
,
o
->
description
);
if
(
o
->
default_value
!=
NULL
)
fprintf
(
fp
,
" (default:
\"
%s
\"
)"
,
o
->
default_value
);
fputc
(
'\n'
,
fp
);
}
}
enum
mg_error_t
mg_get_option
(
struct
mg_context
*
ctx
,
const
char
*
option_name
,
char
*
dst
,
size_t
dst_len
)
{
const
struct
mg_option
*
option
;
enum
mg_error_t
error
;
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
if
((
option
=
find_opt
(
option_name
))
==
NULL
)
{
error
=
MG_NOT_FOUND
;
}
else
if
(
ctx
->
options
[
option
->
index
]
==
NULL
)
{
error
=
MG_SUCCESS
;
dst
[
0
]
=
'\0'
;
}
else
if
(
strlen
(
ctx
->
options
[
option
->
index
])
>=
dst_len
)
{
error
=
MG_BUFFER_TOO_SMALL
;
}
else
{
mg_strlcpy
(
dst
,
ctx
->
options
[
option
->
index
],
dst_len
);
error
=
MG_SUCCESS
;
}
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
return
(
error
);
}
void
if
((
p
=
strchr
(
root
,
','
))
==
NULL
)
{
mg_set_callback
(
struct
mg_context
*
ctx
,
enum
mg_event_t
event
,
mg_callback_t
cb
)
mg_strlcpy
(
path
,
root
,
sizeof
(
path
));
{
/* No locking, no sanity checking. Suppose this is fine? */
ctx
->
callbacks
[
event
]
=
cb
;
}
#if 0
static void
admin_page(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
const struct mg_option *option;
const char *option_name, *option_value;
user_data = NULL; /* Unused */
(void) mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<html><body><h1>Mongoose v. %s</h1>", mg_version());
if (!strcmp(ri->request_method, "POST")) {
option_name = mg_get_var(conn, "o");
option_value = mg_get_var(conn, "v");
if (mg_set_option(conn->ctx,
option_name, option_value) == -1) {
(void) mg_printf(conn,
"<p style=\"background: red\">Error setting "
"option \"%s\"</p>",
option_name ? option_name : "(null)");
}
else
{
}
else
{
(void) mg_printf(conn,
mg_strlcpy
(
path
,
root
,
p
-
root
+
1
);
"<p style=\"color: green\">Saved: %s=%s</p>",
option_name, option_value ? option_value : "NULL");
}
}
}
/* Print table with all options */
(void) mg_printf(conn, "%s", "<table border=\"1\""
"<tr><th>Option</th><th>Description</th>"
"<th colspan=2>Value</th></tr>");
for (option = known_options; option->name != NULL; option++) {
if
(
mg_stat
(
path
,
&
buf
)
!=
0
)
{
option_value = mg_get_option(conn->ctx, option->name);
cry
(
fc
(
ctx
),
"Invalid root directory:
\"
%s
\"
"
,
root
);
if (option_value == NULL)
return
(
FALSE
);
option_value = "";
(void) mg_printf(conn,
"<form method=post><tr><td>%s</td><td>%s</td>"
"<input type=hidden name=o value='%s'>"
"<td><input type=text name=v value='%s'></td>"
"<td><input type=submit value=save></td></form></tr>",
option->name, option->description,
option->name, option_value);
}
}
return
(
TRUE
);
(void) mg_printf(conn, "%s", "</table></body></html>");
}
}
#endif
static
void
static
void
reset_per_request_attributes
(
struct
mg_connection
*
conn
)
reset_per_request_attributes
(
struct
mg_connection
*
conn
)
...
@@ -4312,7 +4019,7 @@ process_new_connection(struct mg_connection *conn)
...
@@ -4312,7 +4019,7 @@ process_new_connection(struct mg_connection *conn)
ri
->
post_data
=
buf
+
request_len
;
ri
->
post_data
=
buf
+
request_len
;
ri
->
post_data_len
=
nread
-
request_len
;
ri
->
post_data_len
=
nread
-
request_len
;
conn
->
birth_time
=
time
(
NULL
);
conn
->
birth_time
=
time
(
NULL
);
analyz
e_request
(
conn
);
handl
e_request
(
conn
);
log_access
(
conn
);
log_access
(
conn
);
shift_to_next
(
conn
,
buf
,
request_len
,
&
nread
);
shift_to_next
(
conn
,
buf
,
request_len
,
&
nread
);
}
}
...
@@ -4340,7 +4047,7 @@ get_socket(struct mg_context *ctx, struct socket *sp)
...
@@ -4340,7 +4047,7 @@ get_socket(struct mg_context *ctx, struct socket *sp)
ctx
->
num_idle
++
;
ctx
->
num_idle
++
;
while
(
ctx
->
sq_head
==
ctx
->
sq_tail
)
{
while
(
ctx
->
sq_head
==
ctx
->
sq_tail
)
{
ts
.
tv_nsec
=
0
;
ts
.
tv_nsec
=
0
;
ts
.
tv_sec
=
time
(
NULL
)
+
atoi
(
ctx
->
options
[
OPT_IDLE_TIME
])
+
1
;
ts
.
tv_sec
=
time
(
NULL
)
+
10
;
if
(
pthread_cond_timedwait
(
&
ctx
->
empty_cond
,
if
(
pthread_cond_timedwait
(
&
ctx
->
empty_cond
,
&
ctx
->
mutex
,
&
ts
)
!=
0
)
{
&
ctx
->
mutex
,
&
ts
)
!=
0
)
{
/* Timeout! release the mutex and return */
/* Timeout! release the mutex and return */
...
@@ -4447,7 +4154,7 @@ put_socket(struct mg_context *ctx, const struct socket *sp)
...
@@ -4447,7 +4154,7 @@ put_socket(struct mg_context *ctx, const struct socket *sp)
/* If there are no idle threads, start one */
/* If there are no idle threads, start one */
if
(
ctx
->
num_idle
==
0
&&
if
(
ctx
->
num_idle
==
0
&&
ctx
->
num_threads
<
atoi
(
ctx
->
options
[
OPT_MAX_THREADS
]
))
{
ctx
->
num_threads
<
atoi
(
ctx
->
config
->
num_threads
))
{
if
(
start_thread
(
ctx
,
if
(
start_thread
(
ctx
,
(
mg_thread_func_t
)
worker_thread
,
ctx
)
!=
0
)
(
mg_thread_func_t
)
worker_thread
,
ctx
)
!=
0
)
cry
(
fc
(
ctx
),
"Cannot start thread: %d"
,
ERRNO
);
cry
(
fc
(
ctx
),
"Cannot start thread: %d"
,
ERRNO
);
...
@@ -4471,10 +4178,7 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
...
@@ -4471,10 +4178,7 @@ accept_new_connection(const struct socket *listener, struct mg_context *ctx)
&
accepted
.
rsa
.
u
.
sa
,
&
accepted
.
rsa
.
len
))
==
INVALID_SOCKET
)
&
accepted
.
rsa
.
u
.
sa
,
&
accepted
.
rsa
.
len
))
==
INVALID_SOCKET
)
return
;
return
;
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
allowed
=
check_acl
(
ctx
,
&
accepted
.
rsa
)
==
MG_SUCCESS
;
allowed
=
ctx
->
options
[
OPT_ACL
]
==
NULL
||
check_acl
(
ctx
,
ctx
->
options
[
OPT_ACL
],
&
accepted
.
rsa
)
==
MG_SUCCESS
;
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
if
(
allowed
)
{
if
(
allowed
)
{
/* Put accepted socket structure into the queue */
/* Put accepted socket structure into the queue */
...
@@ -4502,10 +4206,8 @@ master_thread(struct mg_context *ctx)
...
@@ -4502,10 +4206,8 @@ master_thread(struct mg_context *ctx)
max_fd
=
-
1
;
max_fd
=
-
1
;
/* Add listening sockets to the read set */
/* Add listening sockets to the read set */
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
for
(
sp
=
ctx
->
listening_sockets
;
sp
!=
NULL
;
sp
=
sp
->
next
)
for
(
sp
=
ctx
->
listening_sockets
;
sp
!=
NULL
;
sp
=
sp
->
next
)
add_to_set
(
sp
->
sock
,
&
read_set
,
&
max_fd
);
add_to_set
(
sp
->
sock
,
&
read_set
,
&
max_fd
);
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
tv
.
tv_sec
=
1
;
tv
.
tv_sec
=
1
;
tv
.
tv_usec
=
0
;
tv
.
tv_usec
=
0
;
...
@@ -4521,17 +4223,33 @@ master_thread(struct mg_context *ctx)
...
@@ -4521,17 +4223,33 @@ master_thread(struct mg_context *ctx)
sleep
(
1
);
sleep
(
1
);
#endif
/* _WIN32 */
#endif
/* _WIN32 */
}
else
{
}
else
{
(
void
)
pthread_rwlock_rdlock
(
&
ctx
->
rwlock
);
for
(
sp
=
ctx
->
listening_sockets
;
for
(
sp
=
ctx
->
listening_sockets
;
sp
!=
NULL
;
sp
=
sp
->
next
)
sp
!=
NULL
;
sp
=
sp
->
next
)
if
(
FD_ISSET
(
sp
->
sock
,
&
read_set
))
if
(
FD_ISSET
(
sp
->
sock
,
&
read_set
))
accept_new_connection
(
sp
,
ctx
);
accept_new_connection
(
sp
,
ctx
);
(
void
)
pthread_rwlock_unlock
(
&
ctx
->
rwlock
);
}
}
}
}
/* Stop signal received: somebody called mg_stop. Quit. */
/* Stop signal received: somebody called mg_stop. Quit. */
mg_fini
(
ctx
);
close_all_listening_sockets
(
ctx
);
/* Wait until all threads finish */
(
void
)
pthread_mutex_lock
(
&
ctx
->
mutex
);
while
(
ctx
->
num_threads
>
0
)
(
void
)
pthread_cond_wait
(
&
ctx
->
thr_cond
,
&
ctx
->
mutex
);
(
void
)
pthread_mutex_unlock
(
&
ctx
->
mutex
);
/* Deallocate SSL context */
if
(
ctx
->
ssl_ctx
!=
NULL
)
SSL_CTX_free
(
ctx
->
ssl_ctx
);
(
void
)
pthread_mutex_destroy
(
&
ctx
->
mutex
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
thr_cond
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
empty_cond
);
(
void
)
pthread_cond_destroy
(
&
ctx
->
full_cond
);
/* Signal mg_stop() that we're done */
ctx
->
stop_flag
=
2
;
}
}
void
void
...
@@ -4552,48 +4270,57 @@ mg_stop(struct mg_context *ctx)
...
@@ -4552,48 +4270,57 @@ mg_stop(struct mg_context *ctx)
}
}
struct
mg_context
*
struct
mg_context
*
mg_start
(
void
)
mg_start
(
struct
mg_config
*
config
)
{
{
struct
mg_context
*
ctx
;
struct
mg_context
*
ctx
,
fake_ctx
;
const
struct
mg_option
*
option
;
#if defined(_WIN32)
#if defined(_WIN32)
WSADATA
data
;
WSADATA
data
;
WSAStartup
(
MAKEWORD
(
2
,
2
),
&
data
);
WSAStartup
(
MAKEWORD
(
2
,
2
),
&
data
);
#endif
/* _WIN32 */
#endif
/* _WIN32 */
if
((
ctx
=
(
struct
mg_context
*
)
calloc
(
1
,
sizeof
(
*
ctx
)))
==
NULL
)
{
fake_ctx
.
config
=
config
;
cry
(
fc
(
ctx
),
"cannot allocate mongoose context"
);
if
(
config
->
listening_ports
==
NULL
||
config
->
num_threads
==
NULL
||
config
->
auth_domain
==
NULL
)
{
cry
(
fc
(
&
fake_ctx
),
"Please specify "
"num_threads, listening_ports, auth_domain"
);
return
(
NULL
);
}
else
if
(
config
->
document_root
!=
NULL
&&
verify_document_root
(
&
fake_ctx
,
config
->
document_root
)
!=
TRUE
)
{
cry
(
fc
(
&
fake_ctx
),
"Invalid root directory:
\"
%s
\"
"
,
config
->
document_root
);
return
(
NULL
);
}
else
if
((
ctx
=
calloc
(
1
,
sizeof
(
*
ctx
)))
==
NULL
)
{
cry
(
fc
(
&
fake_ctx
),
"Cannot allocate mongoose context"
);
return
(
NULL
);
return
(
NULL
);
}
}
ctx
->
config
=
config
;
/*
Initialize options. First pass: set default option values */
/*
for
(
option
=
known_options
;
option
->
name
!=
NULL
;
option
++
)
* NOTE(lsm): order is important here. SSL certificates must
ctx
->
options
[
option
->
index
]
=
option
->
default_value
==
NULL
?
* be initialized before listening ports.
NULL
:
mg_strdup
(
option
->
default_value
);
*/
if
(
set_ssl_option
(
ctx
)
==
MG_ERROR
||
/* Call setter functions */
set_ports_option
(
ctx
)
==
MG_ERROR
||
for
(
option
=
known_options
;
option
->
name
!=
NULL
;
option
++
)
set_gpass_option
(
ctx
)
==
MG_ERROR
||
if
(
option
->
setter
!=
NULL
&&
#if !defined(_WIN32)
ctx
->
options
[
option
->
index
]
!=
NULL
)
set_uid_option
(
ctx
)
==
MG_ERROR
||
if
(
option
->
setter
(
ctx
,
#endif
ctx
->
options
[
option
->
index
])
==
FALSE
)
{
set_acl_option
(
ctx
)
==
MG_ERROR
)
{
mg_fini
(
ctx
);
free
(
ctx
);
return
(
NULL
);
return
(
NULL
);
}
}
DEBUG_TRACE
((
DEBUG_MGS_PREFIX
"%s: root [%s]"
,
__func__
,
ctx
->
options
[
OPT_ROOT
]));
#if !defined(_WIN32)
#if !defined(_WIN32)
/*
/*
* Ignore SIGPIPE signal, so if browser cancels the request, it
* Ignore SIGPIPE signal, so if browser cancels the request, it
* won't kill the whole process.
* won't kill the whole process.
*/
*/
(
void
)
signal
(
SIGPIPE
,
SIG_IGN
);
(
void
)
signal
(
SIGPIPE
,
SIG_IGN
);
#endif
/* _WIN32 */
#endif
/*
!
_WIN32 */
(
void
)
pthread_rwlock_init
(
&
ctx
->
rwlock
,
NULL
);
(
void
)
pthread_mutex_init
(
&
ctx
->
mutex
,
NULL
);
(
void
)
pthread_mutex_init
(
&
ctx
->
mutex
,
NULL
);
(
void
)
pthread_cond_init
(
&
ctx
->
thr_cond
,
NULL
);
(
void
)
pthread_cond_init
(
&
ctx
->
thr_cond
,
NULL
);
(
void
)
pthread_cond_init
(
&
ctx
->
empty_cond
,
NULL
);
(
void
)
pthread_cond_init
(
&
ctx
->
empty_cond
,
NULL
);
...
...
mongoose.h
View file @
5425b94f
...
@@ -59,8 +59,21 @@ struct mg_request_info {
...
@@ -59,8 +59,21 @@ struct mg_request_info {
/*
/*
* Error codes for all functions that return 'int'.
* User-defined handler function. It must return MG_SUCCESS or MG_ERROR.
*
* If handler returns MG_SUCCESS, that means that handler has processed the
* request by sending appropriate HTTP reply to the client. Mongoose treats
* the request as served.
*
* If callback returns MG_ERROR, that means that callback has not processed
* the request. Handler must not send any data to the client in this case.
* Mongoose proceeds with request handling as if nothing happened.
*
* NOTE: ssl_password_handler must have the following prototype:
* int (*)(char *, int, int, void *)
* Refer to OpenSSL documentation for more details.
*/
*/
enum
mg_error_t
{
enum
mg_error_t
{
MG_ERROR
,
MG_ERROR
,
MG_SUCCESS
,
MG_SUCCESS
,
...
@@ -68,15 +81,48 @@ enum mg_error_t {
...
@@ -68,15 +81,48 @@ enum mg_error_t {
MG_BUFFER_TOO_SMALL
MG_BUFFER_TOO_SMALL
};
};
typedef
enum
mg_error_t
(
*
mg_callback_t
)(
struct
mg_connection
*
,
const
struct
mg_request_info
*
);
/*
* This structure describes Mongoose configuration.
*/
struct
mg_config
{
char
*
document_root
;
char
*
index_files
;
char
*
ssl_certificate
;
char
*
listening_ports
;
char
*
cgi_extensions
;
char
*
cgi_interpreter
;
char
*
cgi_environment
;
char
*
ssi_extensions
;
char
*
auth_domain
;
char
*
protect
;
char
*
global_passwords_file
;
char
*
put_delete_passwords_file
;
char
*
access_log_file
;
char
*
error_log_file
;
char
*
acl
;
char
*
uid
;
char
*
mime_types
;
char
*
enable_directory_listing
;
char
*
num_threads
;
mg_callback_t
new_request_handler
;
mg_callback_t
http_error_handler
;
mg_callback_t
event_log_handler
;
mg_callback_t
ssl_password_handler
;
};
/*
/*
* Start the web server.
* Start the web server.
*
*
* This must be the first function called by the application.
* This must be the first function called by the application.
* It creates a serving thread, and returns a context structure that
* It creates a serving thread, and returns a context structure that
* can be used to
alter the configuration, and
stop the server.
* can be used to stop the server.
*/
*/
struct
mg_context
*
mg_start
(
void
);
struct
mg_context
*
mg_start
(
struct
mg_config
*
);
/*
/*
...
@@ -89,32 +135,6 @@ struct mg_context *mg_start(void);
...
@@ -89,32 +135,6 @@ struct mg_context *mg_start(void);
void
mg_stop
(
struct
mg_context
*
);
void
mg_stop
(
struct
mg_context
*
);
/*
* Get the current value of a particular option.
*
* Return:
* MG_SUCCESS, MG_NOT_FOUND, MG_BUFFER_TOO_SMALL
*/
enum
mg_error_t
mg_get_option
(
struct
mg_context
*
,
const
char
*
option_name
,
char
*
buf
,
size_t
buf_len
);
/*
* Set a value for a particular option.
*
* Mongoose makes an internal copy of the option value string, which must be
* valid nul-terminated ASCII or UTF-8 string. It is safe to change any option
* at any time. The order of setting various options is also irrelevant with
* one exception: if "ports" option contains SSL listening ports, a "ssl_cert"
* option must be set BEFORE the "ports" option.
*
* Return:
* MG_ERROR, MG_SUCCESS, or MG_NOT_FOUND if option is unknown.
*/
enum
mg_error_t
mg_set_option
(
struct
mg_context
*
,
const
char
*
name
,
const
char
*
value
);
/*
/*
* Add, edit or delete the entry in the passwords file.
* Add, edit or delete the entry in the passwords file.
*
*
...
@@ -133,36 +153,6 @@ enum mg_error_t mg_modify_passwords_file(struct mg_context *ctx,
...
@@ -133,36 +153,6 @@ enum mg_error_t mg_modify_passwords_file(struct mg_context *ctx,
const
char
*
file_name
,
const
char
*
user
,
const
char
*
password
);
const
char
*
file_name
,
const
char
*
user
,
const
char
*
password
);
/*
* Attach a callback function to certain event.
* Callback must return MG_SUCCESS or MG_ERROR.
*
* If callback returns MG_SUCCESS, that means that callback has processed the
* request by sending appropriate HTTP reply to the client. Mongoose treats
* the request as served.
*
* If callback returns MG_ERROR, that means that callback has not processed
* the request. Callback must not send any data to client in this case.
* Mongoose proceeds with request handling.
*
* NOTE: for MG_EVENT_SSL_PASSWORD event the callback must have
* int (*)(char *, int, int, void *) prototype. Refer to OpenSSL documentation
* for more details about the SSL password callback.
*/
enum
mg_event_t
{
MG_EVENT_NEW_REQUEST
,
/* New HTTP request has arrived */
MG_EVENT_HTTP_ERROR
,
/* Mongoose is about to send HTTP error */
MG_EVENT_LOG
,
/* Mongoose is about to log a message */
MG_EVENT_SSL_PASSWORD
,
/* SSL certificate needs verification */
NUM_EVENTS
};
typedef
enum
mg_error_t
(
*
mg_callback_t
)(
struct
mg_connection
*
,
const
struct
mg_request_info
*
);
void
mg_set_callback
(
struct
mg_context
*
,
enum
mg_event_t
,
mg_callback_t
);
/*
/*
* Send data to the client.
* Send data to the client.
*/
*/
...
@@ -185,6 +175,7 @@ int mg_printf(struct mg_connection *, const char *fmt, ...);
...
@@ -185,6 +175,7 @@ int mg_printf(struct mg_connection *, const char *fmt, ...);
*/
*/
int
mg_read
(
struct
mg_connection
*
,
void
*
buf
,
size_t
len
);
int
mg_read
(
struct
mg_connection
*
,
void
*
buf
,
size_t
len
);
/*
/*
* Get the value of particular HTTP header.
* Get the value of particular HTTP header.
*
*
...
@@ -247,11 +238,6 @@ const char *mg_version(void);
...
@@ -247,11 +238,6 @@ const char *mg_version(void);
void
mg_md5
(
char
*
buf
,
...);
void
mg_md5
(
char
*
buf
,
...);
/*
* Print command line usage string.
*/
void
mg_show_usage_string
(
FILE
*
fp
);
#ifdef __cplusplus
#ifdef __cplusplus
}
}
#endif
/* __cplusplus */
#endif
/* __cplusplus */
...
...
test/test.pl
View file @
5425b94f
...
@@ -13,12 +13,11 @@ sub on_windows { $^O =~ /win32/i; }
...
@@ -13,12 +13,11 @@ sub on_windows { $^O =~ /win32/i; }
my
$port
=
23456
;
my
$port
=
23456
;
my
$pid
=
undef
;
my
$pid
=
undef
;
my
$num_requests
;
my
$num_requests
;
my
$root
=
'test'
;
my
$dir_separator
=
on_windows
()
?
'\\'
:
'/'
;
my
$dir_separator
=
on_windows
()
?
'\\'
:
'/'
;
my
$copy_cmd
=
on_windows
()
?
'copy'
:
'cp'
;
my
$copy_cmd
=
on_windows
()
?
'copy'
:
'cp'
;
my
$test_dir_uri
=
"test_dir"
;
my
$test_dir_uri
=
"test_dir"
;
my
$root
=
'test'
;
my
$test_dir
=
$root
.
$dir_separator
.
$test_dir_uri
;
my
$test_dir
=
$root
.
$dir_separator
.
$test_dir_uri
;
my
$alias
=
"/aliased=/etc/,/ta=$test_dir"
;
my
$config
=
'mongoose.conf'
;
my
$config
=
'mongoose.conf'
;
my
$exe
=
'.'
.
$dir_separator
.
'mongoose'
;
my
$exe
=
'.'
.
$dir_separator
.
'mongoose'
;
my
$embed_exe
=
'.'
.
$dir_separator
.
'embed'
;
my
$embed_exe
=
'.'
.
$dir_separator
.
'embed'
;
...
@@ -89,6 +88,7 @@ sub o {
...
@@ -89,6 +88,7 @@ sub o {
# Spawn a server listening on specified port
# Spawn a server listening on specified port
sub
spawn
{
sub
spawn
{
my
(
$cmdline
)
=
@_
;
my
(
$cmdline
)
=
@_
;
print
'Executing: '
,
@_
,
"\n"
;
if
(
on_windows
())
{
if
(
on_windows
())
{
my
@args
=
split
/\s+/
,
$cmdline
;
my
@args
=
split
/\s+/
,
$cmdline
;
my
$executable
=
$args
[
0
];
my
$executable
=
$args
[
0
];
...
@@ -159,7 +159,7 @@ kill_spawned_child();
...
@@ -159,7 +159,7 @@ kill_spawned_child();
my
$cmd
=
"$exe -ports $port -access_log access.log -error_log debug.log "
.
my
$cmd
=
"$exe -ports $port -access_log access.log -error_log debug.log "
.
"-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz "
.
"-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz "
.
"-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo "
.
"-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo "
.
"-root
test -aliases $alias -admin_uri /hh
"
;
"-root
$root,/aiased=/etc/,/ta=$test_dir
"
;
$cmd
.=
' -cgi_interp perl'
if
on_windows
();
$cmd
.=
' -cgi_interp perl'
if
on_windows
();
spawn
(
$cmd
);
spawn
(
$cmd
);
...
...
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