summaryrefslogtreecommitdiff
path: root/src/mod_proxy_backend_ajp13.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_proxy_backend_ajp13.c')
-rw-r--r--src/mod_proxy_backend_ajp13.c836
1 files changed, 0 insertions, 836 deletions
diff --git a/src/mod_proxy_backend_ajp13.c b/src/mod_proxy_backend_ajp13.c
deleted file mode 100644
index 1c674f8f..00000000
--- a/src/mod_proxy_backend_ajp13.c
+++ /dev/null
@@ -1,836 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#include "inet_ntop_cache.h"
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "buffer.h"
-#include "log.h"
-#include "array.h"
-#include "keyvalue.h"
-#include "ajp13.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- http_method_t http;
- ajp13_method_t ajp13;
-} http_method_map;
-
-static http_method_map http_methods[] = {
- { HTTP_METHOD_GET, AJP13_METHOD_GET },
- { HTTP_METHOD_POST, AJP13_METHOD_POST },
- { HTTP_METHOD_HEAD, AJP13_METHOD_HEAD },
- { HTTP_METHOD_OPTIONS, AJP13_METHOD_OPTIONS },
- { HTTP_METHOD_PROPFIND, AJP13_METHOD_PROPFIND },
- { HTTP_METHOD_MKCOL, AJP13_METHOD_MKCOL },
- { HTTP_METHOD_PUT, AJP13_METHOD_PUT },
- { HTTP_METHOD_DELETE, AJP13_METHOD_DELETE },
- { HTTP_METHOD_COPY, AJP13_METHOD_COPY },
- { HTTP_METHOD_MOVE, AJP13_METHOD_MOVE },
- { HTTP_METHOD_PROPPATCH, AJP13_METHOD_PROPPATCH },
- { HTTP_METHOD_REPORT, AJP13_METHOD_REPORT },
- { HTTP_METHOD_CHECKOUT, AJP13_METHOD_CHECKOUT },
- { HTTP_METHOD_CHECKIN, AJP13_METHOD_CHECKIN },
- { HTTP_METHOD_VERSION_CONTROL, AJP13_METHOD_VERSION_CONTROL },
- { HTTP_METHOD_UNCHECKOUT, AJP13_METHOD_UNCHECKOUT },
- { HTTP_METHOD_MKACTIVITY, AJP13_METHOD_MKACTIVITY },
- { HTTP_METHOD_MERGE, AJP13_METHOD_MERGE },
- { HTTP_METHOD_LOCK, AJP13_METHOD_LOCK },
- { HTTP_METHOD_UNLOCK, AJP13_METHOD_UNLOCK },
- { HTTP_METHOD_LABEL, AJP13_METHOD_LABEL },
- { HTTP_METHOD_CONNECT, AJP13_METHOD_UNKNOWN },
- { HTTP_METHOD_UNSET, AJP13_METHOD_UNKNOWN }
-};
-
-static ajp13_method_t ajp13_convert_http_method(http_method_t http_method) {
- int i;
- /* try fast lookup. if http_methods[] is sorted, we will find it this way. */
- if(http_method != HTTP_METHOD_UNSET) {
- if(http_methods[http_method].http == http_method) {
- return http_methods[http_method].ajp13;
- }
- }
- /* walk the list to find ajp13 method. */
- for(i = 0; http_methods[i].http != HTTP_METHOD_UNSET; i++) {
- if(http_methods[i].http == http_method) return http_methods[i].http;
- }
- return AJP13_METHOD_UNKNOWN;
-}
-
-/*
- * request header keyvalue map.
- *
- * Note: The strings have to be uppercase
- */
-static keyvalue request_headers[] = {
- { AJP13_REQ_ACCEPT, "ACCEPT" },
- { AJP13_REQ_ACCEPT_CHARSET, "ACCEPT-CHARSET" },
- { AJP13_REQ_ACCEPT_ENCODING, "ACCEPT-ENCODING" },
- { AJP13_REQ_ACCEPT_LANGUAGE, "ACCEPT-LANGUAGE" },
- { AJP13_REQ_AUTHORIZATION, "AUTHORIZATION" },
- { AJP13_REQ_CONNECTION, "CONNECTION" },
- { AJP13_REQ_CONTENT_TYPE, "CONTENT-TYPE" },
- { AJP13_REQ_CONTENT_LENGTH, "CONTENT-LENGTH" },
- { AJP13_REQ_COOKIE, "COOKIE" },
- { AJP13_REQ_COOKIE2, "COOKIE2" },
- { AJP13_REQ_HOST, "HOST" },
- { AJP13_REQ_PRAGMA, "PRAGMA" },
- { AJP13_REQ_REFERER, "REFERER" },
- { AJP13_REQ_USER_AGENT, "USER-AGENT" },
-
- { -1, NULL }
-};
-
-/*
- * response header keyvalue map
- *
- * Note: The strings don't have to be all uppercase here
- */
-static keyvalue response_headers[] = {
- { AJP13_RESP_CONTENT_TYPE, "Content-Type" },
- { AJP13_RESP_CONTENT_LANGUAGE, "Content-Language" },
- { AJP13_RESP_CONTENT_LENGTH, "Content-Length" },
- { AJP13_RESP_DATE, "Date" },
- { AJP13_RESP_LAST_MODIFIED, "Last-Modified" },
- { AJP13_RESP_LOCATION, "Location" },
- { AJP13_RESP_SET_COOKIE, "Set-Cookie" },
- { AJP13_RESP_SET_COOKIE2, "Set-Cookie2" },
- { AJP13_RESP_SERVLET_ENGINE, "Servlet-Engine" },
- { AJP13_RESP_STATUS, "Status" },
- { AJP13_RESP_WWW_AUTHENTICATE, "WWW-Authenticate" },
- { -1, NULL }
-};
-
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-typedef struct {
- size_t len;
- off_t offset;
- int type;
-} ajp13_packet;
-
-typedef struct {
- unsigned char magicB0;
- unsigned char magicB1;
- unsigned char lengthB0;
- unsigned char lengthB1;
- unsigned char type;
-} AJP13_Header;
-
-/**
- * init the AJP13_header
- */
-static int ajp13_header(char *ptr, int length) {
- AJP13_Header * header = (AJP13_Header *)ptr;
- header->magicB0 = (AJP13_SERVER_MAGIC >> 8) & 0xff;
- header->magicB1 = (AJP13_SERVER_MAGIC ) & 0xff;
- header->lengthB0 = (length >> 8) & 0xff;
- header->lengthB1 = (length ) & 0xff;
- return AJP13_HEADER_LEN;
-}
-
-/**
- * The ajp13 protocol decoder will use this struct for storing state variables
- * used in decoding the stream
- */
-typedef struct {
- buffer *buf; /* holds raw header bytes or used to buffer STDERR */
- off_t offset; /* parse offset into buffer. */
- ajp13_packet packet; /* parsed info about current packet. */
- size_t chunk_len; /* chunk length */
- size_t requested_bytes; /* backend requested we send this many bytes of the request content. */
-} ajp13_state_data;
-
-static ajp13_state_data *ajp13_state_data_init(void) {
- ajp13_state_data *data;
-
- data = calloc(1, sizeof(*data));
- data->buf = buffer_init();
-
- return data;
-}
-
-static void ajp13_state_data_free(ajp13_state_data *data) {
- buffer_free(data->buf);
- free(data);
-}
-
-static void ajp13_state_data_reset(ajp13_state_data *data) {
- buffer_reset(data->buf);
- data->packet.len = 0;
- data->packet.offset = 0;
- data->packet.type = 0;
- data->offset = 0;
- data->chunk_len = 0;
-}
-
-/**
- * encode ajp13 byte/boolean
- */
-static int ajp13_encode_byte(buffer *buf, int val) {
-
- /* format : 2 bytes integer */
- buffer_prepare_append(buf, 1);
-
- buf->ptr[buf->used++] = val;
-
- return 1;
-}
-
-/**
- * encode ajp13 integer (2 bytes)
- */
-static int ajp13_encode_int(buffer *buf, int val) {
-
- /* format : 2 bytes integer */
- buffer_prepare_append(buf, 2);
-
- buf->ptr[buf->used++] = (val >> 8) & 0xff;
- buf->ptr[buf->used++] = (val >> 0) & 0xff;
-
- return 2;
-}
-
-/**
- * encode ajp13 string.
- */
-static int ajp13_encode_string(buffer *buf, const char *str, size_t str_len) {
- size_t len = 0;
-
- if (!str || str_len == 0) {
- return ajp13_encode_int(buf,0xFFFF);
- }
-
- /* format : 2 byte string length : string : null */
- len = 2 + str_len + 1;
-
- buffer_prepare_append(buf, len);
-
- ajp13_encode_int(buf,str_len);
- /* include the NUL */
- buffer_append_memory(buf, str, str_len + 1);
-
- return len;
-}
-
-/**
- * add a key-value pair to the ajp13-buffer
- */
-#define MAX_KEY_LEN 16
-static int ajp13_env_add(buffer *buf, const char *key, size_t key_len, const char *val, size_t val_len) {
- char uppercase_key[MAX_KEY_LEN];
- size_t len = 0;
- int code = -1;
- size_t i;
-
- if (!key || !val) return -1;
-
- if(key_len < MAX_KEY_LEN) {
- /* convert key to uppercase */
- for(i=0;i <key_len;i++) {
- uppercase_key[i] = toupper(key[i]);
- }
- uppercase_key[key_len] = '\0';
- code = keyvalue_get_key(request_headers, uppercase_key);
- }
- if(code >= 0) {
- len += ajp13_encode_int(buf, AJP13_COMMON_HEADER_CODE + code);
- } else {
- len += ajp13_encode_string(buf, key, key_len);
- }
- len += ajp13_encode_string(buf, val, val_len);
-
- return len;
-}
-
-/**
- * decode ajp13 integer (2 bytes)
- */
-static int ajp13_decode_int(ajp13_state_data *data) {
- int val = 0;
-
- if ((data->buf->used - data->offset) <= 2) return -1;
-
- val = (unsigned char)data->buf->ptr[data->offset++];
- val <<= 8;
- val |= (unsigned char)data->buf->ptr[data->offset++];
-
- return val;
-}
-
-/**
- * decode ajp13 string.
- */
-static int ajp13_decode_string(buffer *str, ajp13_state_data *data, int is_header) {
- size_t len = 0;
- const char *p = NULL;
-
- if (!str) {
- return len;
- }
-
- /* string length */
- len = ajp13_decode_int(data);
- if ((ssize_t)len == -1) {
- ERROR("ajp13_decode_int() returned invalid len: %zu", len);
- return len;
- }
-#ifdef AJP13_DEBUG
- TRACE("ajp13_decode_string() string-len: %zu (is_header: %d, common-header: %zd)", len, is_header, (len & AJP13_COMMON_HEADER_CODE));
-#endif
-
- /* if string is header, check for common header code. */
- if (is_header && (len & AJP13_COMMON_HEADER_CODE)) {
- p = keyvalue_get_value(response_headers, len & ~AJP13_COMMON_HEADER_CODE);
- if (p) {
- len = strlen(p);
- } else {
- ERROR("ajp13_decode_string() can't resolve common-header: %zd", len & ~AJP13_COMMON_HEADER_CODE);
-
- return -1;
- }
- }
- /* copy string from buffer. */
- if (p == NULL) {
- if ((data->buf->used - data->offset) <= (len + 1)) {
- ERROR("we have %jd bytes, but a partial-string wants %zu. no way", (intmax_t) (data->buf->used - data->offset), len);
- return -1;
- }
- p = data->buf->ptr + data->offset;
- data->offset += len + 1;
- }
- buffer_copy_string_len(str, p, len);
-
- return len;
-}
-
-/**
- * decode ajp13 response headers
- */
-static int ajp13_decode_response_headers(http_resp *resp, ajp13_state_data *data) {
- buffer *key, *value;
- int key_len, value_len;
- int i,num;
-
- resp->protocol = HTTP_VERSION_UNSET;
- resp->status = ajp13_decode_int(data);
-
- if (resp->status == -1) {
- ERROR("parsing AJP13 response-status failed, got %d", resp->status);
- return -1;
- }
-
- if (ajp13_decode_string(resp->reason, data, 0) == -1) {
- ERROR("parsing AJP13 response-reason failed: %s", "...");
- return -1;
- }
-
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header-status: %d", resp->status);
- TRACE("ajp13: header-reason: %s", resp->reason->ptr);
-#endif
-
- /* leave if we have no headers to decode */
- num = ajp13_decode_int(data);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header-count: %d", num);
-#endif
-
- if (0 == num) return 0;
-
- key = buffer_init();
- value = buffer_init();
- for(i = 0; i < num; i++) {
- key_len = ajp13_decode_string(key, data, 1);
- value_len = ajp13_decode_string(value, data, 1);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header[%d]: key-len: %d, value-len: %d", i, key_len, value_len);
-#endif
-
- if (key_len > 0 && value_len >= 0) {
- data_string *HDR;
- if (NULL == (HDR = (data_string *)array_get_unused_element(resp->headers, TYPE_STRING))) {
- HDR = data_response_init();
- }
-
- buffer_copy_string_len(HDR->key, key->ptr, key_len);
- buffer_copy_string_len(HDR->value, value->ptr, value_len);
-
- array_insert_unique(resp->headers, (data_unset *)HDR);
-#ifdef AJP13_DEBUG
- TRACE("ajp13: header[%d]: %s = %s", i, key->ptr, value->ptr);
-#endif
- } else {
- ERROR("ajp13: response-headers skipped: key-len = %d, val-len = %d", key_len, value_len);
- }
- }
- buffer_free(key);
- buffer_free(value);
-
- return 0;
-}
-
-PROXY_CONNECTION_FUNC(proxy_ajp13_init) {
- UNUSED(srv);
-
- if(!proxy_con->protocol_data) {
- proxy_con->protocol_data = ajp13_state_data_init();
- }
- return 1;
-}
-
-PROXY_CONNECTION_FUNC(proxy_ajp13_cleanup) {
- UNUSED(srv);
-
- if(proxy_con->protocol_data) {
- ajp13_state_data_free((ajp13_state_data *)proxy_con->protocol_data);
- proxy_con->protocol_data = NULL;
- }
- return 1;
-}
-
-static int proxy_ajp13_forward_request(server *srv, connection *con, proxy_session *sess, buffer *packet) {
- char buf[32];
- const char *str;
- server_socket *srv_sock = con->srv_socket;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
- int len = 0,port = 0;
- size_t i;
-
- /* prefix_code */
- len += ajp13_encode_byte(packet, AJP13_TYPE_FORWARD_REQUEST);
-
- /* http method */
- len += ajp13_encode_byte(packet, ajp13_convert_http_method(con->request.http_method));
-
- /* protocol */
- str = get_http_version_name(con->request.http_version);
- len += ajp13_encode_string(packet, str, strlen(str));
-
- /* request uri
- *
- * the docs where unspecific here, but it looks like tomcat wants to get
- * the uri without the query-string here */
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->uri.path));
-
- /* remote address */
- str = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- len += ajp13_encode_string(packet, str, strlen(str));
-
- /* remote host */
- len += ajp13_encode_string(packet, CONST_STR_LEN(""));
-
- /* server name */
- if (con->server_name->used) {
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->server_name));
- } else {
-#ifdef HAVE_IPV6
- str = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- str = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
-#endif
- len += ajp13_encode_string(packet, str, strlen(str));
- }
-
- /* server port */
-#ifdef HAVE_IPV6
- port = ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port);
-#else
- port = ntohs(srv_sock->addr.ipv4.sin_port);
-#endif
- len += ajp13_encode_int(packet, port);
-
- /* is_ssl */
-#ifdef USE_OPENSSL
- len += ajp13_encode_byte(packet, srv_sock->is_ssl);
-#else
- len += ajp13_encode_byte(packet, 0);
-#endif
-
- /* make sure we have content-length header */
- if(con->request.content_length > 0) {
- LI_ltostr(buf, con->request.content_length);
- array_set_key_value(sess->request_headers, CONST_STR_LEN("Content-Length"), buf, strlen(buf));
- } else {
- array_set_key_value(sess->request_headers, CONST_STR_LEN("Content-Length"), CONST_STR_LEN("0"));
- }
-
- /* request headers count */
- len += ajp13_encode_int(packet, sess->request_headers->used);
-
- /* request headers */
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
- ds = (data_string *)sess->request_headers->data[i];
- len += ajp13_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
- }
-
- /* remote user */
- if (!buffer_is_empty(con->authed_user)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_REMOTE_USER);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->authed_user));
- }
-
- /* query string */
- if (!buffer_is_empty(con->uri.query)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_QUERY_STRING);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(con->uri.query));
- }
-
- /* jvm_route */
- if (!buffer_is_empty(sess->proxy_con->address->name)) {
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_JVM_ROUTE);
- len += ajp13_encode_string(packet, CONST_BUF_LEN(sess->proxy_con->address->name));
- }
-
- /* request terminator */
- len += ajp13_encode_byte(packet, AJP13_ATTRIBUTE_ARE_DONE);
-
- return len;
-}
-
-PROXY_STREAM_ENCODER_FUNC(proxy_ajp13_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *out = proxy_con->send;
- connection *con = sess->remote_con;
- buffer *packet;
- size_t len;
-
- UNUSED(srv);
- UNUSED(in);
-
- packet = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(packet, 1024);
-
- /* reserve bytes for header. Will over right header when we know packet length. */
- packet->used += AJP13_HEADER_LEN;
-
- /* send AJP13_TYPE_FORWARD_REQUEST */
- len = proxy_ajp13_forward_request(srv, con, sess, packet);
- packet->used++; /* this is needed because the network will only write "used - 1" bytes */
- out->bytes_in += packet->used - 1;
-
- /* rewrite packet header with correct length. */
- ajp13_header(packet->ptr, len);
-
- if(con->request.content_length > AJP13_MAX_BODY_PACKET_SIZE) {
- data->requested_bytes = AJP13_MAX_BODY_PACKET_SIZE;
- } else if(con->request.content_length > 0) {
- data->requested_bytes = con->request.content_length;
- } else {
- data->requested_bytes = 0;
- }
-
- return HANDLER_FINISHED;
-}
-
-/*
- * copy len bytes from chunk-chain into buffer
- */
-static int proxy_ajp13_fill_buffer(ajp13_state_data *data, chunkqueue *in, size_t len) {
- off_t we_have = 0, we_need = len;
- chunk *c;
-
- buffer_prepare_append(data->buf, we_need);
- for (c = in->first; c && we_need > 0; c = c->next) {
- if(c->mem->used == 0) continue;
-
- we_have = c->mem->used - c->offset - 1;
- if (we_have == 0) continue;
- if (we_have > we_need) we_have = we_need;
-
- buffer_append_string_len(data->buf, c->mem->ptr + c->offset, we_have);
- data->packet.offset += we_have;
- c->offset += we_have;
- in->bytes_out += we_have;
- we_need -= we_have;
- }
- return we_need;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_ajp13_stream_decoder_internal) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *in = proxy_con->recv;
- AJP13_Header *header;
- size_t we_parsed = 0, we_need = 0;
- handler_t rc = HANDLER_GO_ON;
- int magic = 0;
- int reuse = 0;
-
- UNUSED(srv);
-
- /* no data ? */
- if (!in->first) return HANDLER_WAIT_FOR_EVENT;
-
- /* parse the packet header. */
- if(data->packet.offset < AJP13_FULL_HEADER_LEN) {
- we_need = (AJP13_FULL_HEADER_LEN - data->packet.offset);
- /* copy ajp13 header to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- /* make sure we have the full ajp13 header. */
- if(we_need > 0) {
- /* we need more data to parse the header. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- /* parse raw header. */
- header = (AJP13_Header *)(data->buf->ptr);
-
- data->packet.len = ((header->lengthB0 << 8) | header->lengthB1);
- data->packet.len--; /* packet type byte already parsed. */
- data->packet.type = header->type;
- magic = ((header->magicB0 << 8) | header->magicB1);
- if (magic != AJP13_CONTAINER_MAGIC) {
- ERROR("%s", "bad ajp13 magic code, invalid protocl stream");
- return HANDLER_ERROR;
- }
-
- /* Finished parsing raw header bytes. */
- buffer_reset(data->buf);
- }
-
- /* for most packet types copy the content into the data buffer */
- if (data->packet.type != AJP13_TYPE_SEND_BODY_CHUNK) {
- we_need = data->packet.len - (data->packet.offset - AJP13_FULL_HEADER_LEN);
- if(we_need > 0) {
- /* copy ajp13 packet contents to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- /* make sure we have the full ajp13 packet content. */
- if(we_need > 0) {
- /* we need more data to parse the content. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- }
- }
-
- switch (data->packet.type) {
- case AJP13_TYPE_GET_BODY_CHUNK:
- data->requested_bytes = ajp13_decode_int(data);
- break;
- case AJP13_TYPE_SEND_HEADERS:
- if (ajp13_decode_response_headers(sess->resp, data) == -1) {
- ERROR("%s", "Error parsing response_headers");
- rc = HANDLER_ERROR;
- }
- sess->have_response_headers = 1;
- break;
- case AJP13_TYPE_SEND_BODY_CHUNK:
- /* parse chunk length */
- we_parsed = (data->packet.offset - AJP13_FULL_HEADER_LEN);
- if (we_parsed < 2) {
- we_need = 2 - we_parsed;
- /* copy chunk length bytes to buffer */
- we_need = proxy_ajp13_fill_buffer(data, in, we_need);
- if(we_need > 0) {
- /* we need more data to parse the chunk length. */
- return HANDLER_WAIT_FOR_EVENT;
- }
- /* parse chunk length */
- data->chunk_len = ajp13_decode_int(data);
- }
- /* parse chunk data. */
- we_parsed = (data->packet.offset - 2 - AJP13_FULL_HEADER_LEN);
- if(we_parsed < data->chunk_len) {
- we_need = data->chunk_len - we_parsed;
- /* copy chunk data */
- we_parsed = chunkqueue_steal_chunks_len(out, in->first, we_need);
- data->packet.offset += we_parsed;
- we_need -= we_parsed;
- in->bytes_out += we_parsed;
- out->bytes_in += we_parsed;
- }
- we_need = data->packet.len - (data->packet.offset - AJP13_FULL_HEADER_LEN);
- /* ignore padding */
- if(we_need > 0) {
- we_parsed = chunkqueue_skip(in, we_need);
- data->packet.offset += we_parsed;
- we_need -= we_parsed;
- in->bytes_out += we_parsed;
- }
- rc = HANDLER_GO_ON;
- break;
- case AJP13_TYPE_END_RESPONSE:
- if(data->buf->used >= 1) {
- reuse = data->buf->ptr[0];
- }
- if(reuse != 1) {
- sess->is_closing = 1;
- }
- sess->is_request_finished = 1;
- /* close the queues. no more data to decode. */
- in->is_closed = 1;
- out->is_closed = 1;
- /* make sure the send queue is closed, since we can't send any more request content. */
- proxy_con->send->is_closed = 1;
- rc = HANDLER_FINISHED;
- break;
- default:
- TRACE("unknown packet.type: %d", data->packet.type);
- rc = HANDLER_ERROR;
- break;
- }
-
- if(we_need == 0) {
- /* packet finished, reset state for next packet */
- ajp13_state_data_reset(data);
- }
-
- chunkqueue_remove_finished_chunks(in);
-
- return rc;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_ajp13_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- int res;
-
- if(out->is_closed) return 1;
- /* decode the whole packet stream */
- do {
- /* decode the packet */
- res = proxy_ajp13_stream_decoder_internal(srv, sess, out);
- } while (in->first && res == HANDLER_GO_ON);
-
- if (res == HANDLER_WAIT_FOR_EVENT) {
- if (in->is_closed) return HANDLER_ERROR;
- return HANDLER_GO_ON;
- }
-
- return res;
-}
-
-/**
- * transform the content-stream into a valid FastCGI STDIN content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_ajp13_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- ajp13_state_data *data = (ajp13_state_data *)proxy_con->protocol_data;
- chunkqueue *out = proxy_con->send;
- size_t we_need = 0, we_have = 0;
- buffer *b;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- if (data->requested_bytes == 0) {
- /* backend needs to send a request for more content before we can encode more. */
- return HANDLER_GO_ON;
- }
-
- /* calculate how many bytes we can encode. */
- if (in->bytes_in > in->bytes_out) {
- we_need = in->bytes_in - in->bytes_out;
- if (we_need > AJP13_MAX_BODY_PACKET_SIZE) we_need = AJP13_MAX_BODY_PACKET_SIZE;
- if (we_need > data->requested_bytes) we_need = data->requested_bytes;
-
- data->requested_bytes = 0;
- }
- /*
- * write ajp13 header
- */
- b = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(b, AJP13_HEADER_LEN);
- b->used += AJP13_HEADER_LEN;
- if (we_need > 0) {
- ajp13_header(b->ptr, we_need + 2);
- ajp13_encode_int(b, we_need);
- } else {
- /* empty body packet to mark EOF, if the backend requested data beyond
- * the end of the request content.
- */
- ajp13_header(b->ptr, we_need);
- }
- out->bytes_in += b->used;
- b->used++;
-
- we_have = chunkqueue_steal_chunks_len(out, in->first, we_need);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- /* We are finished encoding the request content,
- * but we can't close the send queue here since the backend might
- * try to request more request content then is available and
- * we will have to response with a 0 length body packet.
- */
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-INIT_FUNC(mod_proxy_backend_ajp13_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = core_data->proxy_register_protocol("ajp13");
-
- p->protocol->proxy_stream_init = proxy_ajp13_init;
- p->protocol->proxy_stream_cleanup = proxy_ajp13_cleanup;
- p->protocol->proxy_stream_decoder = proxy_ajp13_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_ajp13_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_ajp13_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_ajp13_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_ajp13_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_ajp13_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_ajp13");
-
- p->init = mod_proxy_backend_ajp13_init;
- p->cleanup = mod_proxy_backend_ajp13_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-