842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * http://www.apache.org/licenses/LICENSE-2.0
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding */
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding
2d71630471d1c23f0137309e3c3957c633ecbfd6rbb#include "ap_config.h"
8f3ec4772d2aeb347cf40e87c77627bb784dd018rbb#include "ap_mmn.h"
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben#include "httpd.h"
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben#include "http_config.h"
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben#include "http_connection.h"
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe#include "http_core.h"
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe#include "http_log.h"
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb#include "apr_buckets.h"
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe#include "apr_strings.h"
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb#include "util_filter.h"
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe#include "scoreboard.h"
813bf7d72e14d04d4f40d4c5a6a2d93f203bf900wrowe
813bf7d72e14d04d4f40d4c5a6a2d93f203bf900wrowemodule AP_MODULE_DECLARE_DATA echo_module;
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coartypedef struct {
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben int bEnabled;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar} EchoConfig;
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coarstatic void *create_echo_server_config(apr_pool_t *p, server_rec *s)
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar{
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar EchoConfig *pConfig = apr_pcalloc(p, sizeof *pConfig);
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar pConfig->bEnabled = 0;
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben return pConfig;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar}
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
e4afb803ff9a51f9ec7969f232b7fd4a4e94d5d4rbbstatic const char *echo_on(cmd_parms *cmd, void *dummy, int arg)
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar{
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar EchoConfig *pConfig = ap_get_module_config(cmd->server->module_config,
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar &echo_module);
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar pConfig->bEnabled = arg;
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben return NULL;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar}
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowestatic apr_status_t brigade_peek(apr_bucket_brigade *bbIn,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe char *buff, apr_size_t bufflen)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe{
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_bucket *b;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_size_t readbytes = 0;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (bufflen--)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* compensate for NULL */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe *buff = '\0';
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe else
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return APR_EGENERAL;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (APR_BRIGADE_EMPTY(bbIn))
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return APR_EGENERAL;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe b = APR_BRIGADE_FIRST(bbIn);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe while ((b != APR_BRIGADE_SENTINEL(bbIn)) && (readbytes < bufflen)) {
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe const char *pos;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe const char *str;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_size_t len;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_status_t rv;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if ((rv = apr_bucket_read(b, &str, &len, APR_NONBLOCK_READ))
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe != APR_SUCCESS)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return rv;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if ((pos = memchr(str, APR_ASCII_LF, len)) != NULL)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe len = pos - str;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (len > bufflen - readbytes)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe len = bufflen - readbytes;
e2f3f3a981b845a0f26efacbe145659a63240944jailletc memcpy (buff + readbytes, str, len);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe readbytes += len;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe buff[readbytes] = '\0';
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe b = APR_BUCKET_NEXT(b);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return APR_SUCCESS;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe}
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jimstatic int update_echo_child_status(ap_sb_handle_t *sbh,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe int status, conn_rec *c,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_bucket_brigade *last_echoed)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe{
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe worker_score *ws = ap_get_scoreboard_worker(sbh);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe int old_status = ws->status;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe ws->status = status;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (!ap_extended_status)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return old_status;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe ws->last_used = apr_time_now();
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* initial pass only, please - in the name of efficiency */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (c) {
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim apr_cpystrn(ws->client,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe ap_get_remote_host(c, c->base_server->lookup_defaults,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe REMOTE_NOLOOKUP, NULL),
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe sizeof(ws->client));
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_cpystrn(ws->vhost, c->base_server->server_hostname,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe sizeof(ws->vhost));
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* Deliberate trailing space - filling in string on WRITE passes */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_cpystrn(ws->request, "ECHO ", sizeof(ws->request));
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* each subsequent WRITE pass, let's update what we echoed */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (last_echoed) {
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim brigade_peek(last_echoed, ws->request + sizeof("ECHO ") - 1,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe sizeof(ws->request) - sizeof("ECHO ") + 1);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe return old_status;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe}
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
c6e3de48da56d5a2d6298585b895cf75e3ffada2benstatic int process_echo_connection(conn_rec *c)
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar{
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb apr_bucket_brigade *bb;
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb apr_bucket *b;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_socket_t *csd = NULL;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar EchoConfig *pConfig = ap_get_module_config(c->base_server->module_config,
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar &echo_module);
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar if (!pConfig->bEnabled) {
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar return DECLINED;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar }
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe ap_time_process_request(c->sbh, START_PREQUEST);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe update_echo_child_status(c->sbh, SERVER_BUSY_READ, c, NULL);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe bb = apr_brigade_create(c->pool, c->bucket_alloc);
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe for ( ; ; ) {
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_status_t rv;
ac00100e1ead618f1d91b77ba2d8a468782a23b7jorton
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb /* Get a single line of input from the client */
b931e2cf90d43b0894c2e2927a2a42aca46f277erpluem if (((rv = ap_get_brigade(c->input_filters, bb, AP_MODE_GETLINE,
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe APR_BLOCK_READ, 0)) != APR_SUCCESS)) {
b0870018de400ab2bec8ddcd102c401900253046jorton apr_brigade_cleanup(bb);
e2f3f3a981b845a0f26efacbe145659a63240944jailletc if (!APR_STATUS_IS_EOF(rv) && ! APR_STATUS_IS_TIMEUP(rv))
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01611)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe "ProtocolEcho: Failure reading from %s",
c41be3600a58bd39a76d1215abcdbbd8e9b1c356minfrin c->client_ip);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe break;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* Something horribly wrong happened. Someone didn't block! */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (APR_BRIGADE_EMPTY(bb)) {
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01612)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe "ProtocolEcho: Error - read empty brigade from %s!",
c41be3600a58bd39a76d1215abcdbbd8e9b1c356minfrin c->client_ip);
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar break;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar }
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (!csd) {
9bec939825399ac2816ea0d912d2e3c3b2ed91f4sf csd = ap_get_conn_socket(c);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe update_echo_child_status(c->sbh, SERVER_BUSY_WRITE, NULL, bb);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb /* Make sure the data is flushed to the client */
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley b = apr_bucket_flush_create(c->bucket_alloc);
3f4d7fdb598d64d80ab8656852276246f2f3b502rbb APR_BRIGADE_INSERT_TAIL(bb, b);
ac00100e1ead618f1d91b77ba2d8a468782a23b7jorton rv = ap_pass_brigade(c->output_filters, bb);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe if (rv != APR_SUCCESS) {
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server, APLOGNO(01613)
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe "ProtocolEcho: Failure writing to %s",
c41be3600a58bd39a76d1215abcdbbd8e9b1c356minfrin c->client_ip);
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim break;
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_brigade_cleanup(bb);
ac00100e1ead618f1d91b77ba2d8a468782a23b7jorton
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe /* Announce our intent to loop */
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe update_echo_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL, NULL);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe }
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe apr_brigade_destroy(bb);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe ap_time_process_request(c->sbh, STOP_PREQUEST);
e46d12b7a404d93e9ed9d09299e98b9431d95800wrowe update_echo_child_status(c->sbh, SERVER_CLOSING, c, NULL);
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar return OK;
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar}
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
e8f95a682820a599fe41b22977010636be5c2717jimstatic const command_rec echo_cmds[] =
ebe70c2684539a5fb2d899241d1601710dfa38a4trawick{
e4afb803ff9a51f9ec7969f232b7fd4a4e94d5d4rbb AP_INIT_FLAG("ProtocolEcho", echo_on, NULL, RSRC_CONF,
e4afb803ff9a51f9ec7969f232b7fd4a4e94d5d4rbb "Run an echo server on this host"),
ebe70c2684539a5fb2d899241d1601710dfa38a4trawick { NULL }
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben};
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowestatic void register_hooks(apr_pool_t *p)
2bf9d434b718368d72c1be69ede336cf19162902ben{
6e8fa9b44c6d5f5b3ac9dab52c4734259bcd8335coar ap_hook_process_connection(process_echo_connection, NULL, NULL,
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe APR_HOOK_MIDDLE);
2bf9d434b718368d72c1be69ede336cf19162902ben}
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asfAP_DECLARE_MODULE(echo) = {
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben STANDARD20_MODULE_STUFF,
f05787953018140838ad51456c86c965d6a86267jim NULL, /* create per-directory config structure */
f05787953018140838ad51456c86c965d6a86267jim NULL, /* merge per-directory config structures */
f05787953018140838ad51456c86c965d6a86267jim create_echo_server_config, /* create per-server config structure */
f05787953018140838ad51456c86c965d6a86267jim NULL, /* merge per-server config structures */
f05787953018140838ad51456c86c965d6a86267jim echo_cmds, /* command apr_table_t */
f05787953018140838ad51456c86c965d6a86267jim register_hooks /* register hooks */
c6e3de48da56d5a2d6298585b895cf75e3ffada2ben};