blob: 5e3df16676a17861ff286bda463bd10ea26c835d [file] [log] [blame]
/* Copyright 2000-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apr.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_buckets.h"
#include "apr_md5.h"
#include "apr_network_io.h"
#include "apr_pools.h"
#include "apr_strings.h"
#include "apr_uri.h"
#include "apr_date.h"
#include "apr_fnmatch.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
#include "apr_hooks.h"
#include "apr_optional_hooks.h"
#include "apr_buckets.h"
#include "ajp.h"
#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if APR_HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#define TEST_POST_DATA "This document is a proposal of evolution of the current " \
"Apache JServ Protocol version 1.3, also known as ajp13. " \
"I'll not cover here the full protocol but only the add-on from ajp13. " \
"This nth pass include comments from the tomcat-dev list and " \
"misses discovered during developpment."
#define TEST_CASE_URL "http://localhost/servlets-examples/servlet/RequestHeaderExample"
/* Main process */
static process_rec *main_process;
/* Default server */
static server_rec *main_server;
/* This function is part of backend.
* The backend return connected socket and conn_rec
*/
static apr_status_t connect_to_backend(apr_socket_t **socket, conn_rec **con,
const char *host, apr_uint16_t port,
server_rec *server, apr_pool_t *pool)
{
apr_status_t rv;
apr_sockaddr_t *remote_sa;
if ((rv = apr_sockaddr_info_get(&remote_sa, host, APR_UNSPEC,
port, 0, pool)) != APR_SUCCESS)
return rv;
if ((rv = apr_socket_create(socket, remote_sa->family, SOCK_STREAM,
#if (APR_MAJOR_VERSION > 0)
APR_PROTO_TCP,
#endif
pool)) != APR_SUCCESS)
return rv;
if ((rv = apr_socket_timeout_set(*socket,
apr_time_from_sec(3))) != APR_SUCCESS)
return rv;
if ((rv = apr_socket_connect(*socket, remote_sa)) != APR_SUCCESS)
return rv;
if (!(*con = ap_run_create_connection(pool, server, *socket,
0, NULL, NULL)))
return APR_EGENERAL;
return APR_SUCCESS;
}
#if APR_HAS_THREADS
#define TEST_THREAD_COUNT 10
static apr_thread_t *threads[TEST_THREAD_COUNT];
static void * APR_THREAD_FUNC thread_worker_func(apr_thread_t *thd, void *data)
{
request_rec *r;
conn_rec *c = (conn_rec *)data;
/* Create an empty request */
if (!(r = ap_wrap_create_request(c)))
goto cleanup;
/* TODO: do something usefull */
apr_sleep(apr_time_from_sec(1));
/* Clean up the request */
apr_pool_destroy(r->pool);
apr_thread_exit(thd, APR_SUCCESS);
return NULL;
cleanup:
apr_thread_exit(thd, APR_EGENERAL);
return NULL;
}
static int create_threads(server_rec *server)
{
int i;
apr_status_t rv;
for (i = 0; i < TEST_THREAD_COUNT; i++) {
conn_rec *c;
/* Create a single client connection. The dummy one of course. */
if (!(c = ap_run_create_connection(server->process->pool, server,
NULL, 0, NULL, NULL)))
return -1;
if ((rv = apr_thread_create(&threads[i], NULL,
thread_worker_func, (void *)c,
server->process->pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_INFO, rv, NULL, "apr_create_thread failed");
return -1;
}
}
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Created %d worker threads", i);
return 0;
}
static int join_threads()
{
int i, rc = 0;
apr_status_t rv;
for (i = 0; i < TEST_THREAD_COUNT; i++) {
apr_thread_join(&rv, threads[i]);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "Worker thread %d failed", i);
rc = -1;
}
}
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "All (%d) worker threads joined", i);
return rc;
}
#endif
int main(int argc, const char * const * argv, const char * const *env)
{
int rv = 0;
apr_status_t rc;
conn_rec *c, *con;
request_rec *r;
apr_socket_t *sock;
ajp_msg_t *msg;
char *buf;
apr_size_t len;
apr_app_initialize(&argc, &argv, &env);
/* This is done in httpd.conf using LogLevel debug directive.
* We are setting this directly.
*/
ap_default_loglevel = APLOG_DEBUG;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Testing ajp...");
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Creating main server...");
main_process = ap_wrap_create_process(argc, argv);
/* Create the main server_rec */
main_server = ap_wrap_create_server(main_process, main_process->pool);
/* Create a single client connection. The dummy one of course. */
if (!(c = ap_run_create_connection(main_process->pool, main_server,
NULL, 0, NULL, NULL))) {
rv = -1;
goto finished;
}
/* ... and a empty request */
if (!(r = ap_wrap_create_request(c))) {
rv = -1;
goto finished;
}
/* 0. Fill in the request data */
if (ap_wrap_make_request(r, TEST_CASE_URL,
"POST",
NULL, //"application/x-www-form-urlencoded",
NULL,
sizeof(TEST_POST_DATA) - 1,
TEST_POST_DATA) != APR_SUCCESS) {
goto finished;
}
/*
* Up to here HTTPD created that for each request.
* From now on, we have a server_rec, conn_rec, and request_rec
* Who will ever need something else :)
*/
/* 1. Obtain a connection to backend */
if ((rc = connect_to_backend(&sock, &con, AJP13_DEF_HOST, AJP13_DEF_PORT,
main_server, r->pool)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "connect_to_backend");
rv = -1;
goto finished;
}
/* 2. Create AJP message */
if ((rc = ajp_send_header(sock, r)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "ajp_send_header");
rv = -1;
goto finished;
}
/* 3. Send AJP message */
ajp_alloc_data_msg(r, &buf, &len, &msg);
/* Send the initial POST BODY */
if (ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"Error ajp_marshal_into_msgb - "
"Can't setting client block");
}
if (ap_should_client_block(r)) {
len = ap_get_client_block(r, buf, len);
}
else
len = ap_get_client_block(r, buf, len);
ajp_send_data_msg(sock, r, msg, len);
/* 4. Read AJP response */
if ((rc = ajp_read_header(sock, r, &msg)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "ajp_read_header");
rv = -1;
goto finished;
}
ajp_msg_create(r->pool, &msg);
ajp_msg_reset(msg);
ajp_ilink_receive(sock, msg);
/* 5. Display results */
#if 1
ajp_msg_dump(msg, "");
#endif
{
apr_uint16_t blen;
ajp_parse_data(r, msg, &blen, &buf);
fputs(buf, stdout);
}
/* 6. Release the connection */
#if APR_HAS_THREADS_remove_this
/* or make the few requests in paralel
* to test the threading.
* the upper 7 steps will go to thread_worker_func
*/
if ((rv = create_threads(main_server)))
goto finished;
if ((rv = join_threads()))
goto finished;
#endif
finished:
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "%s", rv == 0 ? "OK" : "FAILED");
apr_terminate();
return rv;
}