Commit 546bec33 authored by valenok's avatar valenok

API change for mg_start: most binary compatible across releases.

parent 0b1e621c
This diff is collapsed.
This diff is collapsed.
...@@ -29,8 +29,7 @@ struct mg_context; // Handle for the HTTP service itself ...@@ -29,8 +29,7 @@ struct mg_context; // Handle for the HTTP service itself
struct mg_connection; // Handle for the individual connection struct mg_connection; // Handle for the individual connection
// This structure contains full information about the HTTP request. // This structure contains information about the HTTP request.
// It is passed to the user-specified callback function as a parameter.
struct mg_request_info { struct mg_request_info {
char *request_method; // "GET", "POST", etc char *request_method; // "GET", "POST", etc
char *uri; // URL-decoded URI char *uri; // URL-decoded URI
...@@ -40,7 +39,7 @@ struct mg_request_info { ...@@ -40,7 +39,7 @@ struct mg_request_info {
char *log_message; // Mongoose error log message char *log_message; // Mongoose error log message
long remote_ip; // Client's IP address long remote_ip; // Client's IP address
int remote_port; // Client's port int remote_port; // Client's port
int status_code; // HTTP status code int status_code; // HTTP reply status code
int is_ssl; // 1 if SSL-ed, 0 if not int is_ssl; // 1 if SSL-ed, 0 if not
int num_headers; // Number of headers int num_headers; // Number of headers
struct mg_header { struct mg_header {
...@@ -49,65 +48,57 @@ struct mg_request_info { ...@@ -49,65 +48,57 @@ struct mg_request_info {
} http_headers[64]; // Maximum 64 headers } http_headers[64]; // Maximum 64 headers
}; };
// User-defined handler function. It must return MG_SUCCESS or MG_ERROR. // Various events on which user-defined function is called by Mongoose.
// enum mg_event {
// If handler returns MG_SUCCESS, that means that handler has processed the MG_NEW_REQUEST, // New HTTP request has arrived from the client
// request by sending appropriate HTTP reply to the client. Mongoose treats MG_HTTP_ERROR, // HTTP error must be returned to the client
// the request as served. MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
// MG_INIT_SSL, // Mongoose initializes SSL. Instead of mg_connection *,
// If callback returns MG_ERROR, that means that callback has not processed // SSL context is passed to the callback function.
// 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 {
MG_ERROR,
MG_SUCCESS,
MG_NOT_FOUND,
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;
}; };
// Prototype for the user-defined function. Mongoose calls this function
// Start the web server. // on every event mentioned above.
//
// Parameters:
// event: which event has been triggered.
// conn: opaque connection handler. Could be used to read, write data to the
// client, etc. See functions below that accept "mg_connection *".
// request_info: Information about HTTP request.
// //
// This must be the first function called by the application. // Return:
// It creates a serving thread, and returns a context structure that // If handler returns non-NULL, that means that handler has processed the
// can be used to stop the server. // request by sending appropriate HTTP reply to the client. Mongoose treats
// After calling mg_start(), configuration data must not be changed. // the request as served.
struct mg_context *mg_start(const struct mg_config *); // If callback returns NULL, 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.
typedef void * (*mg_callback_t)(enum mg_event event,
struct mg_connection *conn,
struct mg_request_info *request_info);
// Start web server.
//
// Parameters:
// callback: user defined event handling function or NULL.
// options: NULL terminated list of option_name, option_value pairs that
// specify Mongoose configuration parameters.
//
// Example:
// const char *options[] = {
// "document_root", "/var/www",
// "listening_ports", "80,443s",
// NULL
// };
// struct mg_context *ctx = mg_start(&my_func, options);
//
// Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual
// for the list of valid option and their possible values.
//
// Return:
// web server context, or NULL on error.
struct mg_context *mg_start(mg_callback_t callback, const char **options);
// Stop the web server. // Stop the web server.
...@@ -118,6 +109,19 @@ struct mg_context *mg_start(const struct mg_config *); ...@@ -118,6 +109,19 @@ struct mg_context *mg_start(const struct mg_config *);
void mg_stop(struct mg_context *); void mg_stop(struct mg_context *);
// Get the value of particular configuration parameter.
// The value returned is read-only. Mongoose does not allow changing
// configuration at run time.
// If given parameter name is not valid, NULL is returned. For valid
// names, return value is guaranteed to be non-NULL. If parameter is not
// set, zero-length string is returned.
const char *mg_get_option(const struct mg_context *ctx, const char *name);
// Return array of valid configuration options.
const char **mg_get_valid_option_names(void);
// Add, edit or delete the entry in the passwords file. // Add, edit or delete the entry in the passwords file.
// //
// This function allows an application to manipulate .htpasswd files on the // This function allows an application to manipulate .htpasswd files on the
...@@ -129,9 +133,9 @@ void mg_stop(struct mg_context *); ...@@ -129,9 +133,9 @@ void mg_stop(struct mg_context *);
// If password is NULL, entry is deleted. // If password is NULL, entry is deleted.
// //
// Return: // Return:
// MG_ERROR, MG_SUCCESS // 1 on success, 0 on error.
enum mg_error_t mg_modify_passwords_file(struct mg_context *ctx, int mg_modify_passwords_file(struct mg_context *ctx,
const char *file_name, const char *user, const char *password); const char *passwords_file_name, const char *user, const char *password);
// Send data to the client. // Send data to the client.
int mg_write(struct mg_connection *, const void *buf, size_t len); int mg_write(struct mg_connection *, const void *buf, size_t len);
...@@ -160,32 +164,35 @@ const char *mg_get_header(const struct mg_connection *, const char *name); ...@@ -160,32 +164,35 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
// Get a value of particular form variable. // Get a value of particular form variable.
// //
// Either request_info->query_string or read POST data can be scanned. // Parameters:
// mg_get_qsvar() is convenience method to get variable from the query string. // data: pointer to form-uri-encoded buffer. This could be either POST data,
// Destination buffer is guaranteed to be '\0' - terminated. In case of // or request_info.query_string.
// failure, dst[0] == '\0'. // data_len: length of the encoded data.
// var_name: variable name to decode from the buffer
// buf: destination buffer for the decoded variable
// buf_len: length of the destination buffer
// //
// Return: // Return:
// MG_SUCCESS Variable value was successfully copied in the buffer. // On success, length of the decoded variable.
// MG_NOT_FOUND Requested variable not found. // On error, -1 (variable not found, or destination buffer is too small).
// MG_BUFFER_TOO_SMALL Destination buffer is too small to hold the value. //
enum mg_error_t mg_get_var(const char *data, size_t data_len, // Destination buffer is guaranteed to be '\0' - terminated. In case of
const char *var_name, char *buf, size_t buf_len); // failure, dst[0] == '\0'.
enum mg_error_t mg_get_qsvar(const struct mg_request_info *, int mg_get_var(const char *data, size_t data_len,
const char *var_name, char *buf, size_t buf_len); const char *var_name, char *buf, size_t buf_len);
// Fetch value of certain cookie variable into the destination buffer. // Fetch value of certain cookie variable into the destination buffer.
// //
// Destination buffer is guaranteed to be '\0' - terminated. In case of // Destination buffer is guaranteed to be '\0' - terminated. In case of
// failure, dst[0] == '\0'. Note that RFC allows many occurences of the same // failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
// parameter. This function returns only first occurance. // parameter. This function returns only first occurrence.
// //
// Return: // Return:
// MG_SUCCESS Cookie parameter was successfully copied in the buffer. // On success, value length.
// MG_NOT_FOUND Either "Cookie:" header is not present at all, or the // On error, -1 (either "Cookie:" header is not present at all, or the
// requested parameter is not found. // requested parameter is not found, or destination buffer is too small
// MG_BUFFER_TOO_SMALL Destination buffer is too small to hold the value. // to hold the value).
enum mg_error_t mg_get_cookie(const struct mg_connection *, int mg_get_cookie(const struct mg_connection *,
const char *cookie_name, char *buf, size_t buf_len); const char *cookie_name, char *buf, size_t buf_len);
......
This diff is collapsed.
...@@ -146,7 +146,7 @@ if (scalar(@ARGV) > 0 and $ARGV[0] eq 'embedded') { ...@@ -146,7 +146,7 @@ if (scalar(@ARGV) > 0 and $ARGV[0] eq 'embedded') {
} }
# Make sure we load config file if no options are given # Make sure we load config file if no options are given
write_file($config, "ports 12345\naccess_log access.log\n"); write_file($config, "listening_ports 12345\naccess_log_file access.log\n");
spawn($exe); spawn($exe);
my $saved_port = $port; my $saved_port = $port;
$port = 12345; $port = 12345;
...@@ -156,11 +156,13 @@ unlink $config; ...@@ -156,11 +156,13 @@ unlink $config;
kill_spawned_child(); kill_spawned_child();
# Spawn the server on port $port # Spawn the server on port $port
my $cmd = "$exe -ports $port -access_log access.log -error_log debug.log ". my $cmd = "$exe -listening_ports $port -access_log_file access.log ".
"-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " . "-error_log_file debug.log ".
"-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " . "-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
"-root $root,/aiased=/etc/,/ta=$test_dir"; "-extra_mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
$cmd .= ' -cgi_interp perl' if on_windows(); '-put_delete_passwords_file test/passfile ' .
"-document_root $root,/aiased=/etc/,/ta=$test_dir";
$cmd .= ' -cgi_interpreter perl' if on_windows();
spawn($cmd); spawn($cmd);
# Try to overflow: Send very long request # Try to overflow: Send very long request
...@@ -349,15 +351,12 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") { ...@@ -349,15 +351,12 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
$content =~ /^b:a:\w+$/gs or fail("Bad content of the passwd file"); $content =~ /^b:a:\w+$/gs or fail("Bad content of the passwd file");
unlink $path; unlink $path;
kill_spawned_child();
do_PUT_test(); do_PUT_test();
#do_embedded_test(); kill_spawned_child();
do_embedded_test();
} }
sub do_PUT_test { sub do_PUT_test {
$cmd .= ' -auth_PUT test/passfile';
spawn($cmd);
my $auth_header = "Authorization: Digest username=guest, ". my $auth_header = "Authorization: Digest username=guest, ".
"realm=mydomain.com, nonce=1145872809, uri=/put.txt, ". "realm=mydomain.com, nonce=1145872809, uri=/put.txt, ".
"response=896327350763836180c61d87578037d9, qop=auth, ". "response=896327350763836180c61d87578037d9, qop=auth, ".
...@@ -379,16 +378,14 @@ sub do_PUT_test { ...@@ -379,16 +378,14 @@ sub do_PUT_test {
o("PUT /put.txt HTTP/1.0\nExpect: 100-continue\nContent-Length: 4\n". o("PUT /put.txt HTTP/1.0\nExpect: 100-continue\nContent-Length: 4\n".
"$auth_header\nabcd", "$auth_header\nabcd",
"HTTP/1.1 100 Continue.+HTTP/1.1 200", 'PUT 100-Continue'); "HTTP/1.1 100 Continue.+HTTP/1.1 200", 'PUT 100-Continue');
kill_spawned_child();
} }
sub do_embedded_test { sub do_embedded_test {
my $cmd = "cc -o $embed_exe $root/embed.c mongoose.c -I. ". my $cmd = "cc -W -Wall -o $embed_exe $root/embed.c mongoose.c -I. ".
"-DNO_SSL -lpthread -DLISTENING_PORT=\\\"$port\\\""; "-pthread -DLISTENING_PORT=\\\"$port\\\"";
if (on_windows()) { if (on_windows()) {
$cmd = "cl $root/embed.c mongoose.c /I. /nologo ". $cmd = "cl $root/embed.c mongoose.c /I. /nologo ".
"/DNO_SSL /DLISTENING_PORT=\\\"$port\\\" ". "/DLISTENING_PORT=\\\"$port\\\" /link /out:$embed_exe.exe ws2_32.lib ";
"/link /out:$embed_exe.exe ws2_32.lib ";
} }
print $cmd, "\n"; print $cmd, "\n";
system($cmd) == 0 or fail("Cannot compile embedded unit test"); system($cmd) == 0 or fail("Cannot compile embedded unit test");
...@@ -415,30 +412,24 @@ sub do_embedded_test { ...@@ -415,30 +412,24 @@ sub do_embedded_test {
# + in form data MUST be decoded to space # + in form data MUST be decoded to space
o("POST /test_get_var HTTP/1.0\nContent-Length: 10\n\n". o("POST /test_get_var HTTP/1.0\nContent-Length: 10\n\n".
"my_var=b+c", 'Value: \[b c\]', 'mg_get_var 7', 0); "my_var=b+c", 'Value: \[b c\]', 'mg_get_var 9', 0);
# Test that big POSTed vars are not truncated # Test that big POSTed vars are not truncated
my $my_var = 'x' x 64000; my $my_var = 'x' x 64000;
o("POST /test_get_var HTTP/1.0\nContent-Length: 64007\n\n". o("POST /test_get_var HTTP/1.0\nContent-Length: 64007\n\n".
"my_var=$my_var", 'Value size: \[64000\]', 'mg_get_var 8', 0); "my_var=$my_var", 'Value size: \[64000\]', 'mg_get_var 10', 0);
# Test PUT
o("PUT /put HTTP/1.0\nContent-Length: 3\n\nabc",
'\nabc$', 'put callback', 0);
o("POST /test_get_request_info?xx=yy HTTP/1.0\nFoo: bar\n". o("POST /test_get_request_info?xx=yy HTTP/1.0\nFoo: bar\n".
"Content-Length: 3\n\na=b", "Content-Length: 3\n\na=b",
'Method: \[POST\].URI: \[/test_get_request_info\].'. 'Method: \[POST\].URI: \[/test_get_request_info\].'.
'HTTP version: \[1.0\].HTTP header \[Foo\]: \[bar\].'. 'HTTP version: \[1.0\].HTTP header \[Foo\]: \[bar\].'.
'HTTP header \[Content-Length\]: \[3\].'. 'HTTP header \[Content-Length\]: \[3\].'.
'Query string: \[xx=yy\].POST data: \[a=b\].'. 'Query string: \[xx=yy\].'.
'Remote IP: \[\d+\].Remote port: \[\d+\].'. 'Remote IP: \[\d+\].Remote port: \[\d+\].'.
'Remote user: \[\]' 'Remote user: \[\]'
, 'request_info', 0); , 'request_info', 0);
o("GET /not_exist HTTP/1.0\n\n", 'Error: \[404\]', '404 handler', 0); o("GET /not_exist HTTP/1.0\n\n", 'Error: \[404\]', '404 handler', 0);
o("bad request\n\n", 'Error: \[400\]', '* error handler', 0); o("bad request\n\n", 'Error: \[400\]', '* error handler', 0);
o("GET /test_user_data HTTP/1.0\n\n",
'User data: \[1234\]', 'user data in callback', 0);
# o("GET /foo/secret HTTP/1.0\n\n", # o("GET /foo/secret HTTP/1.0\n\n",
# '401 Unauthorized', 'mg_protect_uri', 0); # '401 Unauthorized', 'mg_protect_uri', 0);
# o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=bill\n\n", # o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=bill\n\n",
...@@ -446,12 +437,6 @@ sub do_embedded_test { ...@@ -446,12 +437,6 @@ sub do_embedded_test {
# o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=joe\n\n", # o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=joe\n\n",
# '200 OK', 'mg_protect_uri (joe)', 0); # '200 OK', 'mg_protect_uri (joe)', 0);
# Test un-binding the URI
o("GET /foo/bar HTTP/1.0\n\n", 'HTTP/1.1 200 OK', '/foo bound', 0);
o("GET /test_remove_callback HTTP/1.0\n\n",
'Removing callbacks', 'Callback removal', 0);
o("GET /foo/bar HTTP/1.0\n\n", 'HTTP/1.1 404', '/foo unbound', 0);
kill_spawned_child(); kill_spawned_child();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment