API change for mg_start: most binary compatible across releases.

This commit is contained in:
valenok committed 2010-08-29 22:30:49 +01:00
1 parent 0b1e621c36
commit 546bec333c
5 files changed
+689 -701

No files matched your search

+112 -136
View File
@@ -1,85 +1,92 @@
/*
* Copyright (c) 2004-2009 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* $Id: embed.c 471 2009-08-30 14:30:21Z valenok $
* Unit test for the mongoose web server. Tests embedded API.
*/
// Copyright (c) 2004-2009 Sergey Lyubka
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Unit test for the mongoose web server. Tests embedded API.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "mongoose.h"
#if !defined(LISTENING_PORT)
#define LISTENING_PORT "23456"
#endif /* !LISTENING_PORT */
#endif
static const char *standard_reply = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n";
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n";
static void
test_get_var(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
char *value;
static void test_get_var(struct mg_connection *conn,
const struct mg_request_info *ri) {
char *var, *buf;
size_t buf_len;
const char *cl;
int var_len;
mg_printf(conn, "%s", standard_reply);
value = mg_get_var(conn, "my_var");
if (value != NULL) {
mg_printf(conn, "Value: [%s]\n", value);
mg_printf(conn, "Value size: [%u]\n", (unsigned) strlen(value));
free(value);
}
buf_len = 0;
var = buf = NULL;
cl = mg_get_header(conn, "Content-Length");
mg_printf(conn, "cl: %p\n", cl);
if (!strcmp(ri->request_method, "POST") && cl != NULL) {
buf_len = atoi(cl);
buf = malloc(buf_len);
mg_read(conn, buf, buf_len);
} else if (ri->query_string != NULL) {
buf_len = strlen(ri->query_string);
buf = malloc(buf_len + 1);
strcpy(buf, ri->query_string);
}
var = malloc(buf_len + 1);
var_len = mg_get_var(buf, buf_len, "my_var", var, buf_len + 1);
mg_printf(conn, "Value: [%s]\n", var);
mg_printf(conn, "Value size: [%d]\n", var_len);
free(buf);
free(var);
}
static void
test_get_header(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
static void test_get_header(struct mg_connection *conn,
const struct mg_request_info *ri) {
const char *value;
int i;
mg_printf(conn, "%s", standard_reply);
{
int i;
printf("HTTP headers: %d\n", ri->num_headers);
for (i = 0; i < ri->num_headers; i++)
printf("[%s]: [%s]\n",
ri->http_headers[i].name,
ri->http_headers[i].value);
}
printf("HTTP headers: %d\n", ri->num_headers);
for (i = 0; i < ri->num_headers; i++) {
printf("[%s]: [%s]\n", ri->http_headers[i].name, ri->http_headers[i].value);
}
value = mg_get_header(conn, "Host");
if (value != NULL)
if (value != NULL) {
mg_printf(conn, "Value: [%s]", value);
}
}
static void
test_get_ri(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
static void test_get_request_info(struct mg_connection *conn,
const struct mg_request_info *ri) {
int i;
mg_printf(conn, "%s", standard_reply);
@@ -88,110 +95,79 @@ test_get_ri(struct mg_connection *conn, const struct mg_request_info *ri,
mg_printf(conn, "URI: [%s]\n", ri->uri);
mg_printf(conn, "HTTP version: [%s]\n", ri->http_version);
for (i = 0; i < ri->num_headers; i++)
for (i = 0; i < ri->num_headers; i++) {
mg_printf(conn, "HTTP header [%s]: [%s]\n",
ri->http_headers[i].name,
ri->http_headers[i].value);
}
mg_printf(conn, "Query string: [%s]\n",
ri->query_string ? ri->query_string: "");
mg_printf(conn, "POST data: [%.*s]\n",
ri->post_data_len, ri->post_data);
mg_printf(conn, "Remote IP: [%lu]\n", ri->remote_ip);
mg_printf(conn, "Remote port: [%d]\n", ri->remote_port);
mg_printf(conn, "Remote user: [%s]\n",
ri->remote_user ? ri->remote_user : "");
}
static void
test_error(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
const char *value;
static void test_error(struct mg_connection *conn,
const struct mg_request_info *ri) {
mg_printf(conn, "HTTP/1.1 %d XX\r\n"
"Conntection: close\r\n\r\n", ri->status_code);
mg_printf(conn, "Error: [%d]", ri->status_code);
}
static void
test_user_data(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
const char *value;
static void test_post(struct mg_connection *conn,
const struct mg_request_info *ri) {
const char *cl;
char *buf;
int len;
mg_printf(conn, "%s", standard_reply);
mg_printf(conn, "User data: [%d]", * (int *) user_data);
if (strcmp(ri->request_method, "POST") == 0 &&
(cl = mg_get_header(conn, "Content-Length")) != NULL) {
len = atoi(cl);
if ((buf = malloc(len)) != NULL) {
mg_write(conn, buf, len);
free(buf);
}
}
}
static void
test_protect(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
const char *allowed_user = * (char **) user_data;
const char *remote_user = ri->remote_user;
int allowed;
static const struct test_config {
enum mg_event event;
const char *uri;
void (*func)(struct mg_connection *, const struct mg_request_info *);
} test_config[] = {
{MG_NEW_REQUEST, "/test_get_header", &test_get_header},
{MG_NEW_REQUEST, "/test_get_var", &test_get_var},
{MG_NEW_REQUEST, "/test_get_request_info", &test_get_request_info},
{MG_NEW_REQUEST, "/test_post", &test_post},
{MG_HTTP_ERROR, "", &test_error},
{0, NULL, NULL}
};
allowed = remote_user != NULL && !strcmp(allowed_user, remote_user);
static void *callback(enum mg_event event,
struct mg_connection *conn,
struct mg_request_info *request_info) {
int i;
* (long *) user_data = allowed ? 1 : 0;
for (i = 0; test_config[i].uri != NULL; i++) {
if (event == test_config[i].event &&
(event == MG_HTTP_ERROR ||
!strcmp(request_info->uri, test_config[i].uri))) {
test_config[i].func(conn, request_info);
return "processed";
}
}
return NULL;
}
static void
test_post(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
mg_printf(conn, "%s", standard_reply);
mg_write(conn, ri->post_data, ri->post_data_len);
}
static void
test_put(struct mg_connection *conn, const struct mg_request_info *ri,
void *user_data)
{
mg_printf(conn, "%s", standard_reply);
mg_write(conn, ri->post_data, ri->post_data_len);
}
static void
test_remove_callback(struct mg_connection *conn,
const struct mg_request_info *ri, void *user_data)
{
struct mg_context *ctx = (struct mg_context *) user_data;
const char *uri_regex = "/foo/*";
mg_printf(conn, "%sRemoving callbacks bound to [%s]",
standard_reply, uri_regex);
/* Un-bind bound callback */
mg_set_uri_callback(ctx, uri_regex, NULL, NULL);
}
int main(void)
{
int user_data = 1234;
int main(void) {
struct mg_context *ctx;
const char *options[] = {"listening_ports", LISTENING_PORT, NULL};
ctx = mg_start();
mg_set_option(ctx, "ports", LISTENING_PORT);
mg_set_uri_callback(ctx, "/test_get_header", &test_get_header, NULL);
mg_set_uri_callback(ctx, "/test_get_var", &test_get_var, NULL);
mg_set_uri_callback(ctx, "/test_get_request_info", &test_get_ri, NULL);
mg_set_uri_callback(ctx, "/foo/*", &test_get_ri, NULL);
mg_set_uri_callback(ctx, "/test_user_data",
&test_user_data, &user_data);
mg_set_uri_callback(ctx, "/p", &test_post, NULL);
mg_set_uri_callback(ctx, "/put", &test_put, NULL);
mg_set_uri_callback(ctx, "/test_remove_callback",
&test_remove_callback, ctx);
mg_set_error_callback(ctx, 404, &test_error, NULL);
mg_set_error_callback(ctx, 0, &test_error, NULL);
mg_set_auth_callback(ctx, "/foo/secret", &test_protect, (void *) "joe");
for (;;)
(void) getchar();
ctx = mg_start(callback, options);
pause();
return 0;
}
+16 -31
View File
@@ -146,7 +146,7 @@ if (scalar(@ARGV) > 0 and $ARGV[0] eq 'embedded') {
}
# 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);
my $saved_port = $port;
$port = 12345;
@@ -156,11 +156,13 @@ unlink $config;
kill_spawned_child();
# Spawn the server on port $port
my $cmd = "$exe -ports $port -access_log access.log -error_log debug.log ".
"-cgi_env CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
"-mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
"-root $root,/aiased=/etc/,/ta=$test_dir";
$cmd .= ' -cgi_interp perl' if on_windows();
my $cmd = "$exe -listening_ports $port -access_log_file access.log ".
"-error_log_file debug.log ".
"-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
"-extra_mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
'-put_delete_passwords_file test/passfile ' .
"-document_root $root,/aiased=/etc/,/ta=$test_dir";
$cmd .= ' -cgi_interpreter perl' if on_windows();
spawn($cmd);
# Try to overflow: Send very long request
@@ -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");
unlink $path;
kill_spawned_child();
do_PUT_test();
#do_embedded_test();
kill_spawned_child();
do_embedded_test();
}
sub do_PUT_test {
$cmd .= ' -auth_PUT test/passfile';
spawn($cmd);
my $auth_header = "Authorization: Digest username=guest, ".
"realm=mydomain.com, nonce=1145872809, uri=/put.txt, ".
"response=896327350763836180c61d87578037d9, qop=auth, ".
@@ -379,16 +378,14 @@ sub do_PUT_test {
o("PUT /put.txt HTTP/1.0\nExpect: 100-continue\nContent-Length: 4\n".
"$auth_header\nabcd",
"HTTP/1.1 100 Continue.+HTTP/1.1 200", 'PUT 100-Continue');
kill_spawned_child();
}
sub do_embedded_test {
my $cmd = "cc -o $embed_exe $root/embed.c mongoose.c -I. ".
"-DNO_SSL -lpthread -DLISTENING_PORT=\\\"$port\\\"";
my $cmd = "cc -W -Wall -o $embed_exe $root/embed.c mongoose.c -I. ".
"-pthread -DLISTENING_PORT=\\\"$port\\\"";
if (on_windows()) {
$cmd = "cl $root/embed.c mongoose.c /I. /nologo ".
"/DNO_SSL /DLISTENING_PORT=\\\"$port\\\" ".
"/link /out:$embed_exe.exe ws2_32.lib ";
"/DLISTENING_PORT=\\\"$port\\\" /link /out:$embed_exe.exe ws2_32.lib ";
}
print $cmd, "\n";
system($cmd) == 0 or fail("Cannot compile embedded unit test");
@@ -415,30 +412,24 @@ sub do_embedded_test {
# + in form data MUST be decoded to space
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
my $my_var = 'x' x 64000;
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);
# Test PUT
o("PUT /put HTTP/1.0\nContent-Length: 3\n\nabc",
'\nabc$', 'put callback', 0);
"my_var=$my_var", 'Value size: \[64000\]', 'mg_get_var 10', 0);
o("POST /test_get_request_info?xx=yy HTTP/1.0\nFoo: bar\n".
"Content-Length: 3\n\na=b",
'Method: \[POST\].URI: \[/test_get_request_info\].'.
'HTTP version: \[1.0\].HTTP header \[Foo\]: \[bar\].'.
'HTTP header \[Content-Length\]: \[3\].'.
'Query string: \[xx=yy\].POST data: \[a=b\].'.
'Query string: \[xx=yy\].'.
'Remote IP: \[\d+\].Remote port: \[\d+\].'.
'Remote user: \[\]'
, 'request_info', 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("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",
# '401 Unauthorized', 'mg_protect_uri', 0);
# o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=bill\n\n",
@@ -446,12 +437,6 @@ sub do_embedded_test {
# o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=joe\n\n",
# '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();
}