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