test-http-payload.c revision 8b65acb3893f124707c0f64b5ef55a5a1e0fbd02
/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "llist.h"
#include "abspath.h"
#include "hostpid.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-temp.h"
#include "connection.h"
#include "test-common.h"
#include "http-url.h"
#include "http-request.h"
#include "http-server.h"
#include "http-client.h"
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
static bool request_100_continue = FALSE;
static size_t read_server_partial = 0;
static size_t read_client_partial = 0;
static unsigned int test_max_pending = 200;
static unsigned int client_ioloop_nesting = 0;
static int fd_listen = -1;
static unsigned ioloop_nested_first = 0;
static unsigned ioloop_nested_last = 0;
static unsigned ioloop_nested_depth = 0;
/*
* Test files
*/
static pool_t files_pool;
static void test_files_read_dir(const char *path)
{
/* open the directory */
return;
i_fatal("test files: "
"failed to open directory %s: %m", path);
}
/* read entries */
for (;;) {
const char *file;
errno = 0;
break;
continue;
} else {
}
}
}
if (errno != 0)
i_fatal("test files: "
"failed to read directory %s: %m", path);
/* Close the directory */
i_error("test files: "
"failed to close directory %s: %m", path);
}
static void test_files_init(void)
{
/* initialize file array */
/* obtain all filenames */
test_files_read_dir(".");
}
static void test_files_deinit(void)
{
}
static struct istream *
test_file_open(const char *path,
{
int fd;
*status_r = 200;
*reason_r = "OK";
if (fd < 0) {
if (debug) {
i_debug("test files: "
"open(%s) failed: %m", path);
}
switch (errno) {
case EFAULT:
case ENOENT:
*status_r = 404;
*reason_r = "Not Found";
break;
case EISDIR:
case EACCES:
*status_r = 403;
*reason_r = "Forbidden";
break;
default:
*status_r = 500;
*reason_r = "Internal Server Error";
}
return NULL;
}
}
/*
* Test server
*/
struct client {
struct http_server_connection *http_conn;
};
struct client_request {
struct http_server_request *server_req;
const char *path;
struct istream *payload_input;
struct ostream *payload_output;
};
static const struct http_server_callbacks http_callbacks;
static struct http_server *http_server;
/* location: /succes */
static void
{
const struct http_request *hreq =
struct http_server_response *resp;
405, "Method Not Allowed");
return;
}
}
/* location: /download/... */
static void
struct client_request *creq,
const char *path)
{
const struct http_request *hreq =
struct http_server_response *resp;
unsigned int status;
405, "Method Not Allowed");
return;
}
if (debug) {
i_debug("test server: download: "
"sending payload for %s", fpath);
}
return;
}
if (blocking) {
i_fatal("test server: download: "
"failed to send blocking file payload");
}
if (debug) {
i_debug("test server: download: "
"finished sending blocking payload for %s"
}
} else {
}
}
/* location: /echo */
static void
{
struct http_server_response *resp;
struct istream *payload_input;
switch (res) {
break;
return;
i_fatal("test server: echo: "
i_fatal("test server: echo: "
}
if (debug) {
i_debug("test server: echo: "
}
}
static void
const char *path)
{
const struct http_request *hreq =
struct http_server_response *resp;
struct ostream *payload_output;
405, "Method Not Allowed");
return;
}
size = 0;
if (size == 0) {
return;
}
("/tmp/test-http-server", 0);
if (blocking) {
struct istream *payload_input;
if (read_server_partial > 0) {
}
i_fatal("test server: echo: "
"failed to receive blocking echo payload");
}
if (debug) {
i_debug("test server: echo: "
"finished receiving blocking payload for %s", path);
}
i_fatal("test server: echo: "
"failed to send blocking echo payload");
}
if (debug) {
i_debug("test server: echo: "
"finished sending blocking payload for %s", path);
}
} else {
if (read_server_partial > 0) {
}
}
}
/* request */
static void
http_server_request_destroyed(void *context);
static struct client_request *
struct http_server_request *req)
{
struct client_request *creq;
return creq;
}
{
}
}
static void
{
struct client_request *creq =
(struct client_request *)context;
}
static void
client_handle_request(void *context,
struct http_server_request *req)
{
const struct http_request *hreq =
struct client_request *creq;
if (debug) {
i_debug("test server: "
}
return;
}
return;
}
return;
}
return;
}
return;
}
/* client connection */
static void
static const struct http_server_callbacks http_callbacks = {
};
static void client_init(int fd)
{
}
{
}
static void
{
}
{
int fd;
/* accept new client */
if (fd == -1)
return;
if (fd == -2) {
i_fatal("test server: accept() failed: %m");
}
}
/* */
static void
{
/* open server socket */
}
static void test_server_deinit(void)
{
/* close server socket */
/* deinitialize */
}
/*
* Test client
*/
struct test_client_request {
struct http_client_request *hreq;
unsigned int files_idx;
};
static struct http_client *http_client;
static struct test_client_request *client_requests;
static unsigned int client_files_first, client_files_last;
static struct test_client_request *
test_client_request_new(void)
{
struct test_client_request *tcreq;
return tcreq;
}
static void
{
}
static void
{
struct test_client_request *tcreq;
}
}
/* download */
static void test_client_download_continue(void);
static void
test_client_download_finished(unsigned int files_idx)
{
const char **paths;
unsigned int count;
}
static void
{
/* read payload */
if (debug) {
i_debug("test client: download: "
"got data for [%u] (size=%d)",
}
/* compare with file on disk */
while ((ret=i_stream_read_more
i_fatal("test client: download: "
"received data does not match file "
}
}
i_fatal("test client: download: "
}
}
if (ret == 0) {
if (debug) {
i_debug("test client: download: "
"need more data for [%u]",
}
/* we will be called again for this request */
} else {
if (payload->stream_errno != 0) {
i_fatal("test client: download: "
"failed to read request payload: %s",
fsize = 0;
i_fatal("test client: download: "
"payload ended prematurely "
} else if (debug) {
i_debug("test client: download: "
"finished request for [%u]",
}
/* dereference payload stream; finishes the request */
/* finished */
}
}
static void
struct test_client_request *tcreq)
{
const char **paths;
const char *path;
const char *reason;
if (debug) {
i_debug("test client: download: "
"got response for [%u]",
}
if (debug) {
i_debug("test client: download: "
"path for [%u]: %s",
}
i_fatal("test client: download: "
"got wrong response for %s: %u %s (expected: %u %s)",
}
if (debug) {
i_debug("test client: download: "
"HTTP request for %s failed: %u %s",
}
return;
}
if (debug) {
i_debug("test client: download: "
"no payload for %s [%u]",
}
return;
}
if (read_client_partial == 0) {
} else {
}
}
static void test_client_download_continue(void)
{
struct test_client_request *tcreq;
struct http_client_request *hreq;
const char *const *paths;
unsigned int count;
for (; client_files_first < client_files_last &&
if (debug) {
i_debug("test client: download: "
"received until [%u]",
}
if (client_files_first >= count) {
return;
}
for (; client_files_last < count &&
client_files_last++) {
if (debug) {
i_debug("test client: download: "
"retrieving %s [%u]",
}
}
}
static void
{
/* create client */
/* start querying server */
}
/* echo */
static void test_client_echo_continue(void);
static void
test_client_echo_finished(unsigned int files_idx)
{
const char **paths;
unsigned int count;
}
static void
{
/* read payload */
if (debug) {
i_debug("test client: echo: "
"got data for [%u] (size=%d)",
}
/* compare with file on disk */
while ((ret=i_stream_read_more
i_fatal("test client: echo: "
"received data does not match file "
}
}
i_fatal("test client: echo: "
}
}
if (ret == 0) {
if (debug) {
i_debug("test client: echo: "
"need more data for [%u]",
}
/* we will be called again for this request */
} else {
if (payload->stream_errno != 0) {
i_fatal("test client: echo: "
"failed to read request payload: %s",
fsize = 0;
i_fatal("test client: echo: "
"payload ended prematurely "
} else if (debug) {
i_debug("test client: echo: "
"finished request for [%u]",
}
/* dereference payload stream; finishes the request */
/* finished */
}
}
static void
struct test_client_request *tcreq)
{
const char **paths;
const char *path;
if (debug) {
i_debug("test client: echo: "
"got response for [%u]",
}
if (debug) {
i_debug("test client: echo: "
"path for [%u]: %s",
}
i_fatal("test client: echo: "
"HTTP request for %s failed: %u %s",
}
i_fatal("test client: echo: "
"failed to open %s", path);
}
if (read_server_partial > 0) {
}
// FIXME: check file is empty
if (debug) {
i_debug("test client: echo: "
"no payload for %s [%u]",
}
return;
}
}
static void test_client_echo_continue(void)
{
struct test_client_request *tcreq;
struct http_client_request *hreq;
const char **paths;
unsigned int count, first_submitted;
for (; client_files_first < client_files_last &&
if (debug) {
i_debug("test client: echo: "
}
i_debug("test client: echo: "
"next blocking: %s [%d]",
}
if (client_files_first >= count) {
return;
}
for (; client_files_last < count &&
client_files_last++) {
if (debug) {
i_debug("test client: echo: "
"skipping %s [%u]",
}
continue;
}
if (debug) {
i_debug("test client: echo: "
"retrieving %s [%u]",
}
}
/* run nested ioloop (if requested) if new requests cross a nesting
boundary */
if (ioloop_nested != NULL) {
unsigned int i;
for (i = ioloop_nested_first; i < ioloop_nested_last; i++) {
if (debug) {
i_debug("test client: "
"not leaving ioloop [%u]", i);
}
break;
}
}
if (i == ioloop_nested_last)
} else if (client_ioloop_nesting > 0 &&
(first_submitted / client_ioloop_nesting)) ) {
if (debug) {
i_debug("test client: echo: entering ioloop for %u...%u (depth=%u)",
}
if (debug) {
i_debug("test client: echo: leaving ioloop for %u...%u (depth=%u)",
}
if (client_files_first >= count) {
return;
}
}
}
static void
{
/* create client */
/* start querying server */
}
/* cleanup */
static void test_client_deinit(void)
{
}
/*
* Tests
*/
static void test_open_server_fd(void)
{
if (fd_listen != -1)
if (fd_listen == -1) {
i_fatal("listen(%s:%u) failed: %m",
}
}
static void test_server_kill(void)
{
}
}
static void test_run_client_server(
const struct http_client_settings *client_set,
const struct http_server_settings *server_set,
{
i_fatal("fork() failed: %m");
if (server_pid == 0) {
hostpid_init();
if (debug)
/* child: server */
ioloop_nested_depth = 0;
ioloop = io_loop_create();
} else {
if (debug)
/* parent: client */
ioloop_nested_depth = 0;
ioloop = io_loop_create();
}
}
static void test_run_sequential(
{
struct http_server_settings http_server_set;
struct http_client_settings http_client_set;
/* download files from blocking server */
/* server settings */
/* client settings */
}
static void test_run_pipeline(
{
struct http_server_settings http_server_set;
struct http_client_settings http_client_set;
/* download files from blocking server */
/* server settings */
/* client settings */
}
static void test_run_parallel(
{
struct http_server_settings http_server_set;
struct http_client_settings http_client_set;
/* download files from blocking server */
/* server settings */
/* client settings */
}
static void test_download_server_nonblocking(void)
{
test_begin("http payload download (server non-blocking)");
read_server_partial = 0;
test_end();
}
static void test_download_server_blocking(void)
{
test_begin("http payload download (server blocking)");
read_server_partial = 0;
test_end();
}
static void test_echo_server_nonblocking(void)
{
test_begin("http payload echo (server non-blocking)");
read_server_partial = 0;
test_end();
}
static void test_echo_server_blocking(void)
{
test_begin("http payload echo (server blocking)");
read_server_partial = 0;
test_end();
}
static void test_echo_server_nonblocking_sync(void)
{
test_begin("http payload echo (server non-blocking; 100-continue)");
read_server_partial = 0;
test_end();
}
static void test_echo_server_blocking_sync(void)
{
test_begin("http payload echo (server blocking; 100-continue)");
read_server_partial = 0;
test_end();
}
static void test_echo_server_nonblocking_partial(void)
{
test_begin("http payload echo (server non-blocking; partial short)");
read_server_partial = 1024;
test_end();
test_begin("http payload echo (server non-blocking; partial long)");
test_end();
}
static void test_echo_server_blocking_partial(void)
{
test_begin("http payload echo (server blocking; partial short)");
read_server_partial = 1024;
test_end();
test_begin("http payload echo (server blocking; partial long)");
test_end();
}
static void test_download_client_partial(void)
{
test_begin("http payload download (client partial)");
read_server_partial = 0;
read_client_partial = 1024;
test_end();
test_begin("http payload download (client partial long)");
read_server_partial = 0;
test_end();
}
static void test_download_client_nested_ioloop(void)
{
test_begin("http payload echo (client nested ioloop)");
read_server_partial = 0;
read_client_partial = 0;
client_ioloop_nesting = 10;
test_end();
}
static void (*const test_functions[])(void) = {
};
/*
* Main
*/
volatile sig_atomic_t terminating = 0;
static void
test_signal_handler(int signo)
{
if (terminating != 0)
terminating = 1;
/* make sure we don't leave any pesky children alive */
}
static void test_atexit(void)
{
}
{
int c;
switch (c) {
case 'D':
break;
default:
}
}
/* listen on localhost */
}