xref: /lighttpd1.4/src/mod_ajp13.c (revision 463c60ce)
1 /*
2  * mod_ajp13 - Apache JServ Protocol version 1.3 (AJP13) gateway
3  *
4  * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5  * License: BSD 3-clause (same as lighttpd)
6  *
7  * AJPv13 protocol reference:
8  *   https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
9  *
10  * Note: connection pool (and connection reuse) is not implemented
11  */
12 #include "first.h"
13 
14 #include <sys/types.h>
15 #include <limits.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "gw_backend.h"
20 typedef gw_plugin_config plugin_config;
21 typedef gw_plugin_data   plugin_data;
22 typedef gw_handler_ctx   handler_ctx;
23 
24 #include "base.h"
25 #include "buffer.h"
26 #include "chunk.h"
27 #include "fdevent.h"
28 #include "http_chunk.h"
29 #include "http_header.h"
30 #include "http_kv.h"
31 #include "log.h"
32 
33 #define AJP13_MAX_PACKET_SIZE 8192
34 
35 
36 static void
37 mod_ajp13_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv)
38 {
39     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
40       case 0: /* ajp13.server */
41         if (cpv->vtype == T_CONFIG_LOCAL) {
42             gw_plugin_config * const gw = cpv->v.v;
43             pconf->exts      = gw->exts;
44             pconf->exts_auth = gw->exts_auth;
45             pconf->exts_resp = gw->exts_resp;
46         }
47         break;
48       case 1: /* ajp13.balance */
49         /*if (cpv->vtype == T_CONFIG_LOCAL)*//*always true here for this param*/
50             pconf->balance = (int)cpv->v.u;
51         break;
52       case 2: /* ajp13.debug */
53         pconf->debug = (int)cpv->v.u;
54         break;
55       case 3: /* ajp13.map-extensions */
56         pconf->ext_mapping = cpv->v.a;
57         break;
58       default:/* should not happen */
59         return;
60     }
61 }
62 
63 
64 static void
65 mod_ajp13_merge_config (plugin_config * const pconf, const config_plugin_value_t *cpv)
66 {
67     do {
68         mod_ajp13_merge_config_cpv(pconf, cpv);
69     } while ((++cpv)->k_id != -1);
70 }
71 
72 
73 static void
74 mod_ajp13_patch_config (request_st * const r, plugin_data * const p)
75 {
76     memcpy(&p->conf, &p->defaults, sizeof(plugin_config));
77     for (int i = 1, used = p->nconfig; i < used; ++i) {
78         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
79             mod_ajp13_merge_config(&p->conf,p->cvlist + p->cvlist[i].v.u2[0]);
80     }
81 }
82 
83 
84 SETDEFAULTS_FUNC(mod_ajp13_set_defaults)
85 {
86     static const config_plugin_keys_t cpk[] = {
87       { CONST_STR_LEN("ajp13.server"),
88         T_CONFIG_ARRAY_KVARRAY,
89         T_CONFIG_SCOPE_CONNECTION }
90      ,{ CONST_STR_LEN("ajp13.balance"),
91         T_CONFIG_STRING,
92         T_CONFIG_SCOPE_CONNECTION }
93      ,{ CONST_STR_LEN("ajp13.debug"),
94         T_CONFIG_INT,
95         T_CONFIG_SCOPE_CONNECTION }
96      ,{ CONST_STR_LEN("ajp13.map-extensions"),
97         T_CONFIG_ARRAY_KVSTRING,
98         T_CONFIG_SCOPE_CONNECTION }
99      ,{ NULL, 0,
100         T_CONFIG_UNSET,
101         T_CONFIG_SCOPE_UNSET }
102     };
103 
104     plugin_data * const p = p_d;
105     if (!config_plugin_values_init(srv, p, cpk, "mod_ajp13"))
106         return HANDLER_ERROR;
107 
108     /* process and validate config directives
109      * (init i to 0 if global context; to 1 to skip empty global context) */
110     for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
111         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
112         gw_plugin_config *gw = NULL;
113         for (; -1 != cpv->k_id; ++cpv) {
114             switch (cpv->k_id) {
115               case 0:{/* ajp13.server */
116                 gw = calloc(1, sizeof(gw_plugin_config));
117                 force_assert(gw);
118                 if (!gw_set_defaults_backend(srv, p, cpv->v.a, gw, 0,
119                                              cpk[cpv->k_id].k)) {
120                     gw_plugin_config_free(gw);
121                     return HANDLER_ERROR;
122                 }
123                 cpv->v.v = gw;
124                 cpv->vtype = T_CONFIG_LOCAL;
125                 break;
126               }
127               case 1: /* ajp13.balance */
128                 cpv->v.u = (unsigned int)gw_get_defaults_balance(srv, cpv->v.b);
129                 break;
130               case 2: /* ajp13.debug */
131               case 3: /* ajp13.map-extensions */
132                 break;
133               default:/* should not happen */
134                 break;
135             }
136         }
137 
138         /* disable check-local for all exts (default enabled) */
139         if (gw && gw->exts) { /*(check after gw_set_defaults_backend())*/
140             gw_exts_clear_check_local(gw->exts);
141         }
142     }
143 
144     /* default is 0 */
145     /*p->defaults.balance = (unsigned int)gw_get_defaults_balance(srv, NULL);*/
146 
147     /* initialize p->defaults from global config context */
148     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
149         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
150         if (-1 != cpv->k_id)
151             mod_ajp13_merge_config(&p->defaults, cpv);
152     }
153 
154     return HANDLER_GO_ON;
155 }
156 
157 
158 __attribute_pure__
159 static inline uint32_t
160 ajp13_dec_uint16 (const uint8_t * const x)
161 {
162     return (x[0] << 8) | x[1];
163 }
164 
165 
166 static inline void
167 ajp13_enc_uint16_nc (uint8_t * const x, const uint32_t v)
168 {
169     /*(_nc = no check; caller must check for sufficient space in x)*/
170     x[0] = 0xFF & (v >> 8);
171     x[1] = 0xFF & (v);
172 }
173 
174 
175 static uint32_t
176 ajp13_enc_uint16 (uint8_t * const x, const uint32_t n, const uint32_t v)
177 {
178     if (n + 2 > AJP13_MAX_PACKET_SIZE) return 0;
179     ajp13_enc_uint16_nc(x+n, v);
180     return n+2;
181 }
182 
183 
184 static uint32_t
185 ajp13_enc_byte (uint8_t * const x, const uint32_t n, const uint32_t v)
186 {
187     if (n + 1 > AJP13_MAX_PACKET_SIZE) return 0;
188     x[n] = v;
189     return n+1;
190 }
191 
192 
193 static uint32_t
194 ajp13_enc_string (uint8_t * const x, uint32_t n, const char * const s, const uint32_t len)
195 {
196     /*assert(AJP13_MAX_PACKET_SIZE <= UINT16_MAX);*//*(max is 8k in practice)*/
197     if (0 == len || len == UINT16_MAX)
198         return ajp13_enc_uint16(x, n, 0xFFFF);
199 
200     if (n + 2 + len + 1 > AJP13_MAX_PACKET_SIZE) return 0;
201     ajp13_enc_uint16_nc(x+n, len);
202     n += 2;
203     memcpy(x+n, s, len);
204     n += len;
205     x[n] = '\0';
206     return n+1;
207 }
208 
209 
210 static handler_t
211 ajp13_stdin_append (handler_ctx * const hctx)
212 {
213     chunkqueue * const req_cq = &hctx->r->reqbody_queue;
214     const off_t req_cqlen = chunkqueue_length(req_cq);
215     const off_t max_bytes = hctx->request_id < req_cqlen
216       ? hctx->request_id < MAX_WRITE_LIMIT ? hctx->request_id : MAX_WRITE_LIMIT
217       : req_cqlen;
218     off_t sent = 0;
219     uint8_t hdr[4] = { 0x12, 0x34, 0, 0 };
220 
221     for (off_t dlen; sent < max_bytes; sent += dlen) {
222         dlen = max_bytes - sent > AJP13_MAX_PACKET_SIZE - 4
223           ? AJP13_MAX_PACKET_SIZE - 4
224           : max_bytes - sent;
225 
226         if (-1 != hctx->wb_reqlen) {
227             if (hctx->wb_reqlen >= 0)
228                 hctx->wb_reqlen += sizeof(hdr);
229             else
230                 hctx->wb_reqlen -= sizeof(hdr);
231         }
232 
233         ajp13_enc_uint16_nc(hdr+2, (uint32_t)dlen);
234         (chunkqueue_is_empty(&hctx->wb) || hctx->wb.first->type == MEM_CHUNK)
235                                            /* else FILE_CHUNK for temp file */
236           ? chunkqueue_append_mem(&hctx->wb, (char *)&hdr, sizeof(hdr))
237           : chunkqueue_append_mem_min(&hctx->wb, (char *)&hdr, sizeof(hdr));
238         chunkqueue_steal(&hctx->wb, req_cq, dlen);
239         /*(hctx->wb_reqlen already includes reqbody_length)*/
240     }
241 
242     hctx->request_id -= (int)sent;
243     return HANDLER_GO_ON;
244 }
245 
246 
247 static void
248 ajp13_stdin_append_n (handler_ctx * const hctx, const uint32_t n)
249 {
250     if (hctx->wb.bytes_in == hctx->wb_reqlen) {
251         /*(no additional request body to be sent; send empty packet)*/
252         uint8_t hdr[4] = { 0x12, 0x34, 0, 0 };
253         hctx->wb_reqlen += sizeof(hdr);
254         chunkqueue_append_mem(&hctx->wb, (char *)hdr, sizeof(hdr));
255     }
256 
257     /* AJP13 connections can be reused, so server and backend must agree on how
258      * much data is sent for each serialized request, especially if backend
259      * chooses not to read (and use or discard) entire request body from server.
260      * If server sent excess data, data might be interpreted as a subsequent
261      * request, which might be abused for request smuggling (security). */
262 
263     /* overload hctx->request_id to track bytes requested by backend.
264      * Value must stay >= 0, since -1 is used to flag end of request */
265     if (n <= (uint32_t)(INT_MAX - hctx->request_id))
266         hctx->request_id += (int)n;
267     else /* unexpected; misbehaving backend sent MANY Get Body Chunk requests */
268         hctx->request_id = INT_MAX; /*(limitation of overloaded struct member)*/
269 
270     ajp13_stdin_append(hctx);
271 }
272 
273 
274 __attribute_pure__
275 static uint8_t
276 ajp13_method_byte (const http_method_t m)
277 {
278     /* map lighttpd http_method_t to ajp13 method byte */
279 
280   #if (defined(__STDC_VERSION__) && __STDC_VERSION__-0 >= 199901L) /* C99 */
281 
282     static const uint8_t ajp13_methods[] = {
283         [HTTP_METHOD_GET]              = 2,
284         [HTTP_METHOD_HEAD]             = 3,
285         [HTTP_METHOD_POST]             = 4,
286         [HTTP_METHOD_PUT]              = 5,
287         [HTTP_METHOD_DELETE]           = 6,
288         [HTTP_METHOD_OPTIONS]          = 1,
289         [HTTP_METHOD_TRACE]            = 7,
290         [HTTP_METHOD_ACL]              = 15,
291         [HTTP_METHOD_BASELINE_CONTROL] = 26,
292         [HTTP_METHOD_CHECKIN]          = 18,
293         [HTTP_METHOD_CHECKOUT]         = 19,
294         [HTTP_METHOD_COPY]             = 11,
295         [HTTP_METHOD_LABEL]            = 24,
296         [HTTP_METHOD_LOCK]             = 13,
297         [HTTP_METHOD_MERGE]            = 25,
298         [HTTP_METHOD_MKACTIVITY]       = 27,
299         [HTTP_METHOD_MKCOL]            = 10,
300         [HTTP_METHOD_MKWORKSPACE]      = 22,
301         [HTTP_METHOD_MOVE]             = 12,
302         [HTTP_METHOD_PROPFIND]         = 8,
303         [HTTP_METHOD_PROPPATCH]        = 9,
304         [HTTP_METHOD_REPORT]           = 16,
305         [HTTP_METHOD_SEARCH]           = 21,
306         [HTTP_METHOD_UNCHECKOUT]       = 20,
307         [HTTP_METHOD_UNLOCK]           = 14,
308         [HTTP_METHOD_UPDATE]           = 23,
309         [HTTP_METHOD_VERSION_CONTROL]  = 17
310     };
311 
312     return m >= 0 && m < (http_method_t)sizeof(ajp13_methods)
313       ? ajp13_methods[m]
314       : 0;
315 
316   #else /*(array position is ajp13 method identifier byte)*/
317 
318     static const uint8_t ajp13_methods[] = {
319         0,
320         HTTP_METHOD_OPTIONS,
321         HTTP_METHOD_GET,
322         HTTP_METHOD_HEAD,
323         HTTP_METHOD_POST,
324         HTTP_METHOD_PUT,
325         HTTP_METHOD_DELETE,
326         HTTP_METHOD_TRACE,
327         HTTP_METHOD_PROPFIND,
328         HTTP_METHOD_PROPPATCH,
329         HTTP_METHOD_MKCOL,
330         HTTP_METHOD_COPY,
331         HTTP_METHOD_MOVE,
332         HTTP_METHOD_LOCK,
333         HTTP_METHOD_UNLOCK,
334         HTTP_METHOD_ACL,
335         HTTP_METHOD_REPORT,
336         HTTP_METHOD_VERSION_CONTROL,
337         HTTP_METHOD_CHECKIN,
338         HTTP_METHOD_CHECKOUT,
339         HTTP_METHOD_UNCHECKOUT,
340         HTTP_METHOD_SEARCH,
341         HTTP_METHOD_MKWORKSPACE,
342         HTTP_METHOD_UPDATE,
343         HTTP_METHOD_LABEL,
344         HTTP_METHOD_MERGE,
345         HTTP_METHOD_BASELINE_CONTROL,
346         HTTP_METHOD_MKACTIVITY
347     };
348 
349     uint8_t method;
350     for (method = 1; method < sizeof(ajp13_methods); ++method) {
351         if (ajp13_methods[method] == m) break;
352     }
353     return (method < sizeof(ajp13_methods)) ? method : 0;
354 
355   #endif
356 }
357 
358 
359 static uint32_t
360 ajp13_enc_request_headers (uint8_t * const x, uint32_t n, const request_st * const r)
361 {
362     const array * const rqst_headers = &r->rqst_headers;
363     const int add_content_length =
364       (!light_btst(r->rqst_htags, HTTP_HEADER_CONTENT_LENGTH));
365     /* num_headers */
366     n = ajp13_enc_uint16(x, n, rqst_headers->used + add_content_length);
367     if (0 == n) return n;
368     /* request_headers */
369     if (add_content_length) {
370         /* (gw_backend.c sends 411 Length Required if Content-Length not
371          *  provided and request body is being streamed to backend.  Add
372          *  Content-Length if not provided and request body was collected.) */
373         n = ajp13_enc_uint16(x, n, 0xA008);
374         if (0 == n) return n;
375         char buf[LI_ITOSTRING_LENGTH];
376         n = ajp13_enc_string(x, n, buf,
377                              li_itostrn(buf, sizeof(buf), r->reqbody_length));
378         if (0 == n) return n;
379     }
380     for (uint32_t i = 0, num = rqst_headers->used; i < num; ++i) {
381         const data_string * const ds = (data_string *)rqst_headers->data[i];
382         uint8_t code = 0x00;
383         switch (ds->ext) { /* map request header to ajp13 SC_REQ_* code */
384           case HTTP_HEADER_ACCEPT:          code = 0x01; break;
385           case HTTP_HEADER_ACCEPT_ENCODING: code = 0x03; break;
386           case HTTP_HEADER_ACCEPT_LANGUAGE: code = 0x04; break;
387           case HTTP_HEADER_AUTHORIZATION:   code = 0x05; break;
388           case HTTP_HEADER_CONNECTION:      code = 0x06; break;
389           case HTTP_HEADER_CONTENT_TYPE:    code = 0x07; break;
390           case HTTP_HEADER_CONTENT_LENGTH:  code = 0x08; break;
391           case HTTP_HEADER_COOKIE:          code = 0x09; break;
392           case HTTP_HEADER_HOST:            code = 0x0B; break;
393           case HTTP_HEADER_PRAGMA:          code = 0x0C; break;
394           case HTTP_HEADER_REFERER:         code = 0x0D; break;
395           case HTTP_HEADER_USER_AGENT:      code = 0x0E; break;
396           case HTTP_HEADER_OTHER:
397             if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Accept-Charset")))
398                 code = 0x02;
399             else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Cookie2")))
400                 code = 0x0A;
401             break;
402           default:
403             break;
404         }
405 
406         n = (code)
407           ? ajp13_enc_uint16(x, n, 0xA000 | code)
408           : ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->key));
409         if (0 == n) return n;
410         n = ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->value));
411         if (0 == n) return n;
412     }
413     return n;
414 }
415 
416 
417 #if 0
418 static uint32_t
419 ajp13_enc_req_attribute (uint8_t * const x, uint32_t n, const char * const k, const uint32_t klen, const char * const v, const uint32_t vlen)
420 {
421     n = ajp13_enc_byte(x, n, 0x0A);
422     if (0 == n) return n;
423     n = ajp13_enc_string(x, n, k, klen);
424     if (0 == n) return n;
425     return ajp13_enc_string(x, n, v, vlen);
426 }
427 #endif
428 
429 
430 static uint32_t
431 ajp13_enc_attribute (uint8_t * const x, uint32_t n, const buffer * const b, uint8_t code)
432 {
433     if (NULL == b) return n;
434     n = ajp13_enc_byte(x, n, code);
435     if (0 == n) return n;
436     return ajp13_enc_string(x, n, BUF_PTR_LEN(b));
437 }
438 
439 
440 static uint32_t
441 ajp13_enc_attributes (uint8_t * const x, uint32_t n, request_st * const r)
442 {
443     const buffer *vb;
444 
445     vb = http_header_env_get(r, CONST_STR_LEN("REMOTE_USER"));
446     n = ajp13_enc_attribute(x, n, vb, 0x03);
447     if (0 == n) return n;
448     vb = http_header_env_get(r, CONST_STR_LEN("AUTH_TYPE"));
449     n = ajp13_enc_attribute(x, n, vb, 0x04);
450     if (0 == n) return n;
451 
452     if (!buffer_is_blank(&r->uri.query)) {
453         n = ajp13_enc_attribute(x, n, &r->uri.query, 0x05);
454         if (0 == n) return n;
455     }
456 
457     if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https"))) {
458         /* XXX: might have config to avoid this overhead if not needed */
459 
460         r->con->srv->request_env(r);
461 
462         vb = http_header_env_get(r, CONST_STR_LEN("SSL_CLIENT_CERT"));
463         n = ajp13_enc_attribute(x, n, vb, 0x07);
464         if (0 == n) return n;
465         vb = http_header_env_get(r, CONST_STR_LEN("SSL_CIPHER"));
466         n = ajp13_enc_attribute(x, n, vb, 0x08);
467         if (0 == n) return n;
468         vb = http_header_env_get(r, CONST_STR_LEN("SSL_CIPHER_USE_KEYSIZE"));
469         n = ajp13_enc_attribute(x, n, vb, 0x0B);
470         if (0 == n) return n;
471     }
472 
473   #if 0
474     /* req_attribute */ /*(what is often included by convention?)*/
475     n = ajp13_enc_req_attribute(x, n, CONST_STR_LEN("REDIRECT_URI"),
476                                       BUF_PTR_LEN(&r->target_orig));
477     if (0 == n) return n;
478     if (!buffer_is_equal(&r->target, &r->target_orig)) {
479         n = ajp13_enc_req_attribute(x, n, CONST_STR_LEN("REDIRECT_URI"),
480                                           BUF_PTR_LEN(&r->target));
481         if (0 == n) return n;
482     }
483     /* Note: if this is extended to pass all env; must not pass HTTP_PROXY */
484   #endif
485 
486   #if 1 /*(experimental) (???) (XXX: create separate config option?)*/
487     /*(use mod_setenv to set value)*/
488     vb = http_header_env_get(r, CONST_STR_LEN("AJP13_SECRET"));
489     n = ajp13_enc_attribute(x, n, vb, 0x0C);
490     if (0 == n) return n;
491   #endif
492 
493     return n;
494 }
495 
496 
497 static uint32_t
498 ajp13_enc_server_name (uint8_t * const x, const uint32_t n, const request_st * const r)
499 {
500   #if 0
501     const data_string * const ds =
502       array_get_element_klen(cgienv, CONST_STR_LEN("SERVER_NAME"));
503     return (ds)
504       ? ajp13_enc_string(x, n, BUF_PTR_LEN(&ds->value))
505       : ajp13_enc_string(x, n, NULL, 0);
506   #else
507     /* copied and modified from http_cgi.c:http_cgi_headers() */
508     uint32_t len = buffer_clen(r->server_name);
509     if (len) {
510         const char * const ptr = r->server_name->ptr;
511         if (ptr[0] == '[') {
512             const char *colon = strstr(ptr, "]:");
513             if (colon) len = (colon + 1) - ptr;
514         }
515         else {
516             const char *colon = strchr(ptr, ':');
517             if (colon) len = colon - ptr;
518         }
519         return ajp13_enc_string(x, n, ptr, len);
520     }
521     else {
522         /* SERVER_ADDR is generated in http_cgi_headers()
523          * if the listen addr is, for example, a wildcard addr.
524          * XXX: For now, just send an empty string in this case
525          * instead of duplicating that code */
526         return ajp13_enc_string(x, n, NULL, 0);
527     }
528   #endif
529 }
530 
531 
532 #if 0
533 static int
534 ajp13_env_add (void *venv, const char *k, size_t klen, const char *v, size_t vlen)
535 {
536     /*(might be more efficient to store list rather than lighttpd array)*/
537     array_set_key_value((array *)venv, k, klen, v, vlen);
538     return 0;
539 }
540 #endif
541 
542 
543 static handler_t
544 ajp13_create_env (handler_ctx * const hctx)
545 {
546     request_st * const r = hctx->r;
547     /* AJP13_MAX_PACKET_SIZE currently matches default 8k chunk_buf_sz */
548     buffer * const b =
549       chunkqueue_prepend_buffer_open_sz(&hctx->wb, AJP13_MAX_PACKET_SIZE);
550 
551   #if 0 /*(elide if used only for SERVER_NAME, as is current case)*/
552     /* Note: while it might be slightly more efficient to special-case ajp13
553      * request creation here (reduce string copy), it is not worth duplicating
554      * the logic centralized in http-header-glue.c:http_cgi_headers() */
555     array * const cgienv = array_init(64);
556   #endif
557 
558     do {
559       #if 0
560       #if 0 /* XXX: potential future extension */
561         gw_host * const host = hctx->host;
562         http_cgi_opts opts = {
563           (hctx->gw_mode == FCGI_AUTHORIZER),
564           host->break_scriptfilename_for_php,
565           host->docroot,
566           host->strip_request_uri
567         };
568       #else
569         http_cgi_opts opts = { 0, 0, NULL, NULL };
570       #endif
571         if (0 != http_cgi_headers(r, &opts, ajp13_env_add, cgienv)) break;
572       #endif
573 
574         uint32_t n = 6;
575         uint8_t * const x = (uint8_t *)b->ptr;
576 
577         x[0] = 0x12;
578         x[1] = 0x34;
579         x[2] = 0;
580         x[3] = 0;
581         x[4] = 0x02; /* JK_AJP13_FORWARD_REQUEST */
582         /* method */
583         const uint8_t method_byte = ajp13_method_byte(r->http_method);
584         if (0 == method_byte) break;
585         x[5] = method_byte;
586         /* protocol */
587         const char * const proto = get_http_version_name(r->http_version);
588         n = ajp13_enc_string(x, n, proto, strlen(proto));
589         if (0 == n) break;
590         /* req_uri */
591         n = ajp13_enc_string(x, n, BUF_PTR_LEN(&r->uri.path));
592         if (0 == n) break;
593         /* remote_addr */
594         n = ajp13_enc_string(x, n, BUF_PTR_LEN(&r->con->dst_addr_buf));
595         if (0 == n) break;
596         /* remote_host *//*(skip DNS lookup)*/
597         n = ajp13_enc_string(x, n, NULL, 0);
598         if (0 == n) break;
599         /* server_name */
600         n = ajp13_enc_server_name(x, n, r);
601         if (0 == n) break;
602         /* server_port */
603         unsigned short port = sock_addr_get_port(&r->con->srv_socket->addr);
604         n = ajp13_enc_uint16(x, n, port);
605         if (0 == n) break;
606         /* is_ssl */
607         n = ajp13_enc_byte(x,n,buffer_is_equal_string(&r->uri.scheme,
608                                                       CONST_STR_LEN("https")));
609         if (0 == n) break;
610         /* num_headers */
611         /* request_headers */
612         n = ajp13_enc_request_headers(x, n, r);
613         if (0 == n) break;
614         /* attributes */
615         n = ajp13_enc_attributes(x, n, r);
616         if (0 == n) break;
617         /* request_terminator */
618         n = ajp13_enc_byte(x, n, 0xFF);
619         if (0 == n) break;
620         /* payload length (overwrite in header) */
621         ajp13_enc_uint16_nc(x+2, n-4);
622 
623       #if 0
624         array_free(cgienv);
625       #endif
626 
627         /* (buffer is reallocated only if n is exactly AJP13_MAX_PACKET_SIZE) */
628         /* (could check for one-off; limit to 8k-1 to avoid resizing buffer) */
629         buffer_extend(b, n);/*(buffer_commit but extend +1 for '\0' as needed)*/
630         chunkqueue_prepend_buffer_commit(&hctx->wb);
631         hctx->wb_reqlen = (off_t)n;
632 
633         if (r->reqbody_length) {
634             /*chunkqueue_append_chunkqueue(&hctx->wb, &r->reqbody_queue);*/
635             if (r->reqbody_length > 0)
636                 hctx->wb_reqlen += r->reqbody_length;
637                 /* (eventual) (minimal) total request size, not necessarily
638                  * including all ajp13 framing around content length yet */
639             else /* as-yet-unknown total rqst sz (Transfer-Encoding: chunked)*/
640                 hctx->wb_reqlen = -hctx->wb_reqlen;
641         }
642         /* send single data packet, then wait for Get Body Chunk from backend */
643         ajp13_stdin_append_n(hctx, AJP13_MAX_PACKET_SIZE-4);
644         hctx->request_id = 0; /* overloaded value; see ajp13_stdin_append_n() */
645 
646         plugin_stats_inc("ajp13.requests");
647         return HANDLER_GO_ON;
648     } while (0);
649 
650   #if 0
651     array_free(cgienv);
652   #endif
653 
654     r->http_status = 400;
655     r->handler_module = NULL;
656     buffer_clear(b);
657     chunkqueue_remove_finished_chunks(&hctx->wb);
658     return HANDLER_FINISHED;
659 }
660 
661 
662 static void
663 ajp13_expand_headers (buffer * const b, handler_ctx * const hctx, uint32_t plen)
664 {
665     /* hctx->rb must contain at least plen content
666      * and all chunks expected to be MEM_CHUNK */
667     chunkqueue_compact_mem(hctx->rb, plen);
668 
669     /* expect all headers in single AJP13 packet;
670      * not handling multiple AJP13_SEND_HEADERS packets
671      * (expecting single MEM_CHUNK <= 8k with AJP13 headers) */
672 
673     chunk * const c = hctx->rb->first;
674     uint8_t *ptr =
675       (uint8_t *)c->mem->ptr + c->offset + 5; /* +5 for (4 hdr + 1 type) */
676     plen -= 5;
677 
678     /* expand headers into buffer to be parsed by common code for responses
679      * (parsing might be slightly faster if AJP13-specific, but then would have
680      *  to duplicate all http_response_parse_headers() policy)*/
681 
682     do {
683         uint32_t len;
684         if (plen < 2) break;
685         plen -= 2;
686         buffer_append_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
687         buffer_append_int(b, ajp13_dec_uint16(ptr));
688         ptr += 2;
689 
690         if (plen < 2) break;
691         plen -= 2;
692         len = ajp13_dec_uint16(ptr);
693         ptr += 2;
694         if (plen < len+1) break;
695         plen -= len+1; /* include -1 for ending '\0' */
696         buffer_append_char(b, ' ');
697         if (len) buffer_append_string_len(b, (char *)ptr, len);
698         ptr += len+1;
699 
700         if (plen < 2) break;
701         plen -= 2;
702         ptr += 2;
703         for (uint32_t nhdrs = ajp13_dec_uint16(ptr); nhdrs; --nhdrs) {
704             if (plen < 2) break;
705             plen -= 2;
706             len = ajp13_dec_uint16(ptr);
707             ptr += 2;
708             if (len >= 0xA000) {
709                 if (len == 0xA000 || len > 0xA00B) break;
710                 static const struct {
711                   const char *h;
712                   uint32_t len;
713                 } hcode[] = {
714                   { CONST_STR_LEN("\nContent-Type: ")     }
715                  ,{ CONST_STR_LEN("\nContent-Language: ") }
716                  ,{ CONST_STR_LEN("\nContent-Length: ")   }
717                  ,{ CONST_STR_LEN("\nDate: ")             }
718                  ,{ CONST_STR_LEN("\nLast-Modified: ")    }
719                  ,{ CONST_STR_LEN("\nLocation: ")         }
720                  ,{ CONST_STR_LEN("\nSet-Cookie: ")       }
721                  ,{ CONST_STR_LEN("\nSet-Cookie2: ")      }
722                  ,{ CONST_STR_LEN("\nServlet-Engine: ")   }
723                  ,{ CONST_STR_LEN("\nStatus: ")           }
724                  ,{ CONST_STR_LEN("\nWWW-Authenticate: ") }
725                 };
726                 const uint32_t idx = (len & 0xF) - 1;
727                 buffer_append_string_len(b, hcode[idx].h, hcode[idx].len);
728             }
729             else {
730                 if (plen < len+1) break;
731                 plen -= len+1;
732                 buffer_append_str3(b, CONST_STR_LEN("\n"),
733                                    (char *)ptr, len,
734                                    CONST_STR_LEN(": "));
735                 ptr += len+1;
736             }
737 
738             if (plen < 2) break;
739             plen -= 2;
740             len = ajp13_dec_uint16(ptr);
741             ptr += 2;
742             if (plen < len+1) break;
743             plen -= len+1;
744             buffer_append_string_len(b, (char *)ptr, len);
745             ptr += len+1;
746         }
747     } while (0);
748 
749     buffer_append_string_len(b, CONST_STR_LEN("\n\n"));
750 }
751 
752 
753 enum {
754   AJP13_FORWARD_REQUEST = 2
755  ,AJP13_SEND_BODY_CHUNK = 3
756  ,AJP13_SEND_HEADERS    = 4
757  ,AJP13_END_RESPONSE    = 5
758  ,AJP13_GET_BODY_CHUNK  = 6
759  ,AJP13_SHUTDOWN        = 7
760  ,AJP13_PING            = 8
761  ,AJP13_CPONG_REPLY     = 9
762  ,AJP13_CPING           = 10
763 };
764 
765 
766 __attribute_cold__
767 static handler_t
768 ajp13_recv_0(const request_st * const r, const handler_ctx * const hctx)
769 {
770         if (-1 == hctx->request_id) /*(flag request ended)*/
771             return HANDLER_FINISHED;
772         if (!(fdevent_fdnode_interest(hctx->fdn) & FDEVENT_IN)
773             && !(r->conf.stream_response_body
774                  & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
775             return HANDLER_GO_ON;
776         log_error(r->conf.errh, __FILE__, __LINE__,
777           "unexpected end-of-file (perhaps the ajp13 process died):"
778           "pid: %d socket: %s",
779           hctx->proc->pid, hctx->proc->connection_name->ptr);
780 
781         return HANDLER_ERROR;
782 }
783 
784 
785 static handler_t
786 ajp13_recv_parse_loop (request_st * const r, handler_ctx * const hctx)
787 {
788     log_error_st * const errh = r->conf.errh;
789     int fin = 0;
790     do {
791         uint8_t header[7];
792         const off_t rblen = chunkqueue_length(hctx->rb);
793         if (rblen < 5)
794             break; /* incomplete packet header + min response payload */
795         char *ptr = (char *)&header;
796         uint32_t pklen = 5;
797         if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
798             break;
799         if (pklen != 5)
800             break;
801         if (ptr[0] != 'A' || ptr[1] != 'B') {
802             log_error(errh, __FILE__, __LINE__,
803               "invalid packet prefix sent from container:"
804               "pid: %d socket: %s",
805               hctx->proc->pid, hctx->proc->connection_name->ptr);
806             return HANDLER_ERROR;
807         }
808         uint32_t plen = ajp13_dec_uint16((uint8_t *)ptr+2);
809         if (plen > (unsigned int)rblen - 4)
810             break; /* incomplete packet */
811 
812         switch(ptr[4]) {
813         case AJP13_SEND_HEADERS:
814             if (0 == r->resp_body_started) {
815                 if (plen < 3) {
816                     log_error(errh, __FILE__, __LINE__,
817                       "AJP13: headers packet received with invalid length");
818                     return HANDLER_FINISHED;
819                 }
820 
821                 buffer *hdrs = hctx->response;
822                 if (NULL == hdrs) {
823                     hdrs = r->tmp_buf;
824                     buffer_clear(hdrs);
825                 }
826 
827                 ajp13_expand_headers(hdrs, hctx, 4 + plen);
828 
829                 if (HANDLER_GO_ON !=
830                     http_response_parse_headers(r, &hctx->opts, hdrs)) {
831                     hctx->send_content_body = 0;
832                     return HANDLER_FINISHED;
833                 }
834                 if (0 == r->resp_body_started) {
835                     if (!hctx->response) {
836                         hctx->response = chunk_buffer_acquire();
837                         buffer_copy_buffer(hctx->response, hdrs);
838                     }
839                 }
840                 else if (hctx->gw_mode == GW_AUTHORIZER &&
841                      (r->http_status == 0 || r->http_status == 200)) {
842                     /* authorizer approved request; ignore the content here */
843                     hctx->send_content_body = 0;
844                     hctx->opts.authorizer |= /*(save response streaming flags)*/
845                       (r->conf.stream_response_body
846                        & (FDEVENT_STREAM_RESPONSE
847                          |FDEVENT_STREAM_RESPONSE_BUFMIN)) << 1;
848                     r->conf.stream_response_body &=
849                       ~(FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN);
850                 }
851               #if 0
852                 else if ((r->conf.stream_response_body &
853                            (FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN))
854                          && (   r->http_status == 204
855                              || r->http_status == 205
856                              || r->http_status == 304
857                              || r->http_method == HTTP_METHOD_HEAD)) {
858                     /* disable streaming to wait for backend protocol to signal
859                      * end of response (prevent http_response_write_prepare()
860                      * from short-circuiting and finishing responses without
861                      * response body) */
862                     r->conf.stream_response_body &=
863                       ~(FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN);
864                 }
865               #endif
866             }
867             else {
868                 log_error(errh, __FILE__, __LINE__,
869                   "AJP13: headers received after body started");
870                 /* ignore; discard packet */
871             }
872             break;
873         case AJP13_SEND_BODY_CHUNK:
874             if (0 == r->resp_body_started) { /* header not finished */
875                 log_error(errh, __FILE__, __LINE__,
876                   "AJP13: body received before headers");
877                 return HANDLER_FINISHED;
878             }
879             else if (hctx->send_content_body) {
880                 ptr = (char *)&header;
881                 pklen = 7;
882                 if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
883                     return HANDLER_GO_ON;
884                 if (pklen != 7)
885                     return HANDLER_GO_ON;
886                 uint32_t len = ajp13_dec_uint16((uint8_t *)ptr+5);
887                 if (0 == len) break; /*(skip "flush" packet of 0-length data)*/
888                 if (len > plen - 3) {
889                     log_error(errh, __FILE__, __LINE__,
890                       "AJP13: body packet received with invalid length");
891                     return HANDLER_FINISHED;
892                 }
893                 chunkqueue_mark_written(hctx->rb, 7);
894                 if (0 == http_response_transfer_cqlen(r, hctx->rb, len)) {
895                     if (len != plen - 3)
896                         chunkqueue_mark_written(hctx->rb, plen - 3 - len);
897                     continue;
898                 }
899                 else {
900                     /* error writing to tempfile;
901                      * truncate response or send 500 if nothing sent yet */
902                     hctx->send_content_body = 0;
903                     return HANDLER_FINISHED;
904                 }
905             }
906             else {
907                 /* ignore; discard packet */
908             }
909             break;
910         case AJP13_GET_BODY_CHUNK:
911                         /*assert(3 == plen);*/
912             ptr = (char *)&header;
913             pklen = 7;
914             if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
915                 return HANDLER_GO_ON;
916             if (pklen != 7)
917                 return HANDLER_GO_ON;
918             ajp13_stdin_append_n(hctx, ajp13_dec_uint16((uint8_t *)ptr+5));
919             break;
920         case AJP13_END_RESPONSE:
921                         /*assert(2 == plen);*/
922           #if 0
923             ptr = (char *)&header;
924             pklen = 6;
925             if (chunkqueue_peek_data(hctx->rb, &ptr, &pklen, errh) < 0)
926                 return HANDLER_GO_ON;
927             if (pklen != 6)
928                 return HANDLER_GO_ON;
929             if (ptr[5]) {
930                 /* future: add connection to pool if 'reuse' flag is set */
931             }
932           #endif
933             hctx->request_id = -1; /*(flag request ended)*/
934             fin = 1;
935             break;
936         case AJP13_CPONG_REPLY:
937                         /*assert(1 == plen);*/
938             break;
939         default:
940             log_error(errh, __FILE__, __LINE__,
941               "AJP13: packet type not handled: %d", ptr[4]);
942             /* discard packet */
943             break;
944         }
945 
946         chunkqueue_mark_written(hctx->rb, 4 + plen);
947     } while (0 == fin);
948 
949     return 0 == fin ? HANDLER_GO_ON : HANDLER_FINISHED;
950 }
951 
952 
953 static handler_t
954 ajp13_recv_parse (request_st * const r, struct http_response_opts_t * const opts, buffer * const b, size_t n)
955 {
956     handler_ctx * const hctx = (handler_ctx *)opts->pdata;
957     if (0 == n) return ajp13_recv_0(r, hctx);
958     /* future: might try to elide copying if buffer contains full packet(s)
959      *         and prior read did not end in a partial packet */
960     chunkqueue_append_buffer(hctx->rb, b);
961     return ajp13_recv_parse_loop(r, hctx);
962 }
963 
964 
965 static handler_t
966 ajp13_check_extension (request_st * const r, void *p_d)
967 {
968     if (NULL != r->handler_module) return HANDLER_GO_ON;
969 
970     plugin_data * const p = p_d;
971     mod_ajp13_patch_config(r, p);
972     if (NULL == p->conf.exts) return HANDLER_GO_ON;
973 
974     handler_t rc = gw_check_extension(r, p, 1, 0);
975     if (HANDLER_GO_ON != rc) return rc;
976 
977     if (r->handler_module == p->self) {
978         handler_ctx *hctx = r->plugin_ctx[p->id];
979         hctx->opts.backend = BACKEND_AJP13;
980         hctx->opts.parse = ajp13_recv_parse;
981         hctx->opts.pdata = hctx;
982         hctx->stdin_append = ajp13_stdin_append;
983         hctx->create_env = ajp13_create_env;
984         if (!hctx->rb)
985             hctx->rb = chunkqueue_init(NULL);
986         else
987             chunkqueue_reset(hctx->rb);
988     }
989 
990     return HANDLER_GO_ON;
991 }
992 
993 
994 __attribute_cold__
995 int mod_ajp13_plugin_init (plugin *p);
996 int mod_ajp13_plugin_init (plugin *p)
997 {
998     p->version      = LIGHTTPD_VERSION_ID;
999     p->name         = "ajp13";
1000 
1001     p->init         = gw_init;
1002     p->cleanup      = gw_free;
1003     p->set_defaults = mod_ajp13_set_defaults;
1004     p->handle_request_reset    = gw_handle_request_reset;
1005     p->handle_uri_clean        = ajp13_check_extension;
1006     p->handle_subrequest       = gw_handle_subrequest;
1007     p->handle_trigger          = gw_handle_trigger;
1008     p->handle_waitpid          = gw_handle_waitpid_cb;
1009 
1010     return 0;
1011 }
1012