xref: /lighttpd1.4/src/mod_echo.c (revision 5e14db43)
1517010f2SGlenn Strauss /*
2517010f2SGlenn Strauss  * mod_echo - test/debugging module to echo request back to client as response
3517010f2SGlenn Strauss  *
4517010f2SGlenn Strauss  * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5517010f2SGlenn Strauss  * License: BSD 3-clause (same as lighttpd)
6517010f2SGlenn Strauss  *
7517010f2SGlenn Strauss  * Note: module is hard-coded to handle requests to the exact uri-path: "/echo"
8517010f2SGlenn Strauss  *
9517010f2SGlenn Strauss  * Note: testing GET requests with Content-Length requires lighttpd.conf:
10517010f2SGlenn Strauss  *   server.http-parseopts += ("method-get-body" => "enable")
11517010f2SGlenn Strauss  */
12517010f2SGlenn Strauss #include "first.h"
13517010f2SGlenn Strauss 
14517010f2SGlenn Strauss #include <stdlib.h>
15517010f2SGlenn Strauss 
16517010f2SGlenn Strauss #include "base.h"
17517010f2SGlenn Strauss #include "fdevent.h"
18517010f2SGlenn Strauss #include "http_chunk.h"
19517010f2SGlenn Strauss #include "plugin.h"
20517010f2SGlenn Strauss #include "request.h"
21517010f2SGlenn Strauss #include "response.h"
22517010f2SGlenn Strauss 
23517010f2SGlenn Strauss typedef struct {
24517010f2SGlenn Strauss     PLUGIN_DATA;
25517010f2SGlenn Strauss } plugin_data;
26517010f2SGlenn Strauss 
INIT_FUNC(mod_echo_init)27517010f2SGlenn Strauss INIT_FUNC(mod_echo_init) {
28*5e14db43SGlenn Strauss     return ck_calloc(1, sizeof(plugin_data));
29517010f2SGlenn Strauss }
30517010f2SGlenn Strauss 
31517010f2SGlenn Strauss #if 1 /*(would be simpler if not supporting streaming w/ bufmin)*/
32517010f2SGlenn Strauss 
mod_echo_request_body(request_st * const r)33517010f2SGlenn Strauss static handler_t mod_echo_request_body(request_st * const r) {
34517010f2SGlenn Strauss     chunkqueue * const cq = &r->reqbody_queue;
35517010f2SGlenn Strauss     chunkqueue_remove_finished_chunks(cq); /* unnecessary? */
36517010f2SGlenn Strauss     off_t cqlen = chunkqueue_length(cq);
37517010f2SGlenn Strauss     if ((r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
38517010f2SGlenn Strauss         && r->resp_body_started) {
39517010f2SGlenn Strauss         if (chunkqueue_length(&r->write_queue) > 65536 - 4096) {
40517010f2SGlenn Strauss             /* wait for more data to be sent to client */
41517010f2SGlenn Strauss             return HANDLER_WAIT_FOR_EVENT;
42517010f2SGlenn Strauss         }
43517010f2SGlenn Strauss         else {
44517010f2SGlenn Strauss             if (cqlen > 65536) {
45517010f2SGlenn Strauss                 cqlen = 65536;
46517010f2SGlenn Strauss                 joblist_append(r->con);
47517010f2SGlenn Strauss             }
48517010f2SGlenn Strauss         }
49517010f2SGlenn Strauss     }
50517010f2SGlenn Strauss 
51517010f2SGlenn Strauss     if (0 != http_chunk_transfer_cqlen(r, cq, (size_t)cqlen))
52517010f2SGlenn Strauss         return HANDLER_ERROR;
53517010f2SGlenn Strauss 
54517010f2SGlenn Strauss     if (cq->bytes_out == (off_t)r->reqbody_length) {
55517010f2SGlenn Strauss         /* sent all request body input */
56517010f2SGlenn Strauss         http_response_backend_done(r);
57517010f2SGlenn Strauss         return HANDLER_FINISHED;
58517010f2SGlenn Strauss     }
59517010f2SGlenn Strauss 
60517010f2SGlenn Strauss     cqlen = chunkqueue_length(cq);
61517010f2SGlenn Strauss     if (cq->bytes_in != (off_t)r->reqbody_length && cqlen < 65536 - 16384) {
62517010f2SGlenn Strauss         /*(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
63517010f2SGlenn Strauss         if (!(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) {
64517010f2SGlenn Strauss             r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
65517010f2SGlenn Strauss             r->con->is_readable = 1; /* trigger optimistic read from client */
66517010f2SGlenn Strauss         }
67517010f2SGlenn Strauss     }
68517010f2SGlenn Strauss     return HANDLER_WAIT_FOR_EVENT;
69517010f2SGlenn Strauss }
70517010f2SGlenn Strauss 
SUBREQUEST_FUNC(mod_echo_handle_subrequest)71517010f2SGlenn Strauss SUBREQUEST_FUNC(mod_echo_handle_subrequest) {
72517010f2SGlenn Strauss     UNUSED(p_d);
73517010f2SGlenn Strauss 
74517010f2SGlenn Strauss     handler_t rc = mod_echo_request_body(r);
75517010f2SGlenn Strauss     if (rc != HANDLER_WAIT_FOR_EVENT) return rc;
76517010f2SGlenn Strauss 
77517010f2SGlenn Strauss     chunkqueue * const cq = &r->reqbody_queue;
78517010f2SGlenn Strauss     if (cq->bytes_in != (off_t)r->reqbody_length) {
79517010f2SGlenn Strauss         /*(64k - 4k to attempt to avoid temporary files
80517010f2SGlenn Strauss          * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/
81517010f2SGlenn Strauss         if (chunkqueue_length(cq) > 65536 - 4096
82517010f2SGlenn Strauss             && (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)) {
83517010f2SGlenn Strauss             r->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
84517010f2SGlenn Strauss             return HANDLER_WAIT_FOR_EVENT;
85517010f2SGlenn Strauss         }
86517010f2SGlenn Strauss         else {
87517010f2SGlenn Strauss             rc = r->con->reqbody_read(r);
88517010f2SGlenn Strauss             if (rc != HANDLER_GO_ON) return rc;
89517010f2SGlenn Strauss 
90517010f2SGlenn Strauss             if (-1 == r->reqbody_length
91517010f2SGlenn Strauss                 && !(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST))
92517010f2SGlenn Strauss                 return HANDLER_WAIT_FOR_EVENT;
93517010f2SGlenn Strauss         }
94517010f2SGlenn Strauss     }
95517010f2SGlenn Strauss 
96517010f2SGlenn Strauss     return mod_echo_request_body(r);
97517010f2SGlenn Strauss }
98517010f2SGlenn Strauss 
99517010f2SGlenn Strauss #else /*(would be simpler if not supporting streaming w/ bufmin (above))*/
100517010f2SGlenn Strauss 
SUBREQUEST_FUNC(mod_echo_handle_subrequest)101517010f2SGlenn Strauss SUBREQUEST_FUNC(mod_echo_handle_subrequest) {
102517010f2SGlenn Strauss     UNUSED(p_d);
103517010f2SGlenn Strauss 
104517010f2SGlenn Strauss     handler_t rc = r->con->reqbody_read(r);
105517010f2SGlenn Strauss     if (rc != HANDLER_GO_ON) return rc;
106517010f2SGlenn Strauss 
107517010f2SGlenn Strauss     chunkqueue * const cq = &r->reqbody_queue;
108517010f2SGlenn Strauss     if (0 != http_chunk_transfer_cqlen(r, cq, chunkqueue_length(cq)))
109517010f2SGlenn Strauss         return HANDLER_ERROR;
110517010f2SGlenn Strauss 
111517010f2SGlenn Strauss     if (cq->bytes_out == (off_t)r->reqbody_length) {
112517010f2SGlenn Strauss         http_response_backend_done(r);
113517010f2SGlenn Strauss         return HANDLER_FINISHED;
114517010f2SGlenn Strauss     }
115517010f2SGlenn Strauss     return HANDLER_WAIT_FOR_EVENT;
116517010f2SGlenn Strauss }
117517010f2SGlenn Strauss 
118517010f2SGlenn Strauss #endif
119517010f2SGlenn Strauss 
URIHANDLER_FUNC(mod_echo_handle_uri_clean)120517010f2SGlenn Strauss URIHANDLER_FUNC(mod_echo_handle_uri_clean) {
121517010f2SGlenn Strauss     plugin_data *p = p_d;
122517010f2SGlenn Strauss     if (NULL == r->handler_module
123517010f2SGlenn Strauss         && buffer_eq_slen(&r->uri.path, CONST_STR_LEN("/echo"))) {
124517010f2SGlenn Strauss         r->handler_module = p->self;
125517010f2SGlenn Strauss         r->resp_body_started = 1;
126517010f2SGlenn Strauss         /* XXX: future: might echo request headers here */
127517010f2SGlenn Strauss         if (0 == r->reqbody_length) {
128517010f2SGlenn Strauss             r->resp_body_finished = 1;
129517010f2SGlenn Strauss             return HANDLER_FINISHED;
130517010f2SGlenn Strauss         }
131517010f2SGlenn Strauss     }
132517010f2SGlenn Strauss     return HANDLER_GO_ON;
133517010f2SGlenn Strauss }
134517010f2SGlenn Strauss 
135b82d7b8aSGlenn Strauss 
136b82d7b8aSGlenn Strauss __attribute_cold__
137517010f2SGlenn Strauss int mod_echo_plugin_init(plugin *p);
mod_echo_plugin_init(plugin * p)138517010f2SGlenn Strauss int mod_echo_plugin_init(plugin *p) {
139517010f2SGlenn Strauss     p->version                 = LIGHTTPD_VERSION_ID;
140517010f2SGlenn Strauss     p->name                    = "echo";
141517010f2SGlenn Strauss 
142517010f2SGlenn Strauss     p->handle_uri_clean        = mod_echo_handle_uri_clean;
143517010f2SGlenn Strauss     p->handle_subrequest       = mod_echo_handle_subrequest;
144517010f2SGlenn Strauss     p->init                    = mod_echo_init;
145517010f2SGlenn Strauss 
146517010f2SGlenn Strauss     return 0;
147517010f2SGlenn Strauss }
148