summaryrefslogtreecommitdiff
path: root/src/mod_proxy_backend_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_proxy_backend_http.c')
-rw-r--r--src/mod_proxy_backend_http.c423
1 files changed, 0 insertions, 423 deletions
diff --git a/src/mod_proxy_backend_http.c b/src/mod_proxy_backend_http.c
deleted file mode 100644
index a56bd602..00000000
--- a/src/mod_proxy_backend_http.c
+++ /dev/null
@@ -1,423 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "configfile.h"
-#include "buffer.h"
-#include "log.h"
-#include "sys-strings.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-typedef enum {
- HTTP_CHUNK_LEN,
- HTTP_CHUNK_EXTENSION,
- HTTP_CHUNK_DATA,
- HTTP_CHUNK_END
-} http_chunk_state_t;
-
-/**
- * The protocol will use this struct for storing state variables
- * used in decoding the stream
- */
-typedef struct {
- http_chunk_state_t chunk_parse_state;
- off_t chunk_len;
- off_t chunk_offset;
- buffer *buf;
-} protocol_state_data;
-
-static protocol_state_data *protocol_state_data_init(void) {
- protocol_state_data *data;
-
- data = calloc(1, sizeof(*data));
- data->chunk_parse_state = HTTP_CHUNK_LEN;
- data->buf = buffer_init();
-
- return data;
-}
-
-static void protocol_state_data_free(protocol_state_data *data) {
- buffer_free(data->buf);
- free(data);
-}
-
-static void protocol_state_data_reset(protocol_state_data *data) {
- buffer_reset(data->buf);
- data->chunk_parse_state = HTTP_CHUNK_LEN;
-}
-
-PROXY_CONNECTION_FUNC(proxy_http_init) {
-
- UNUSED(srv);
-
- if(!proxy_con->protocol_data) {
- proxy_con->protocol_data = protocol_state_data_init();
- }
- return 1;
-}
-
-PROXY_CONNECTION_FUNC(proxy_http_cleanup) {
-
- UNUSED(srv);
-
- if(proxy_con->protocol_data) {
- protocol_state_data_free((protocol_state_data *)proxy_con->protocol_data);
- proxy_con->protocol_data = NULL;
- }
- return 1;
-}
-
-/**
- * parse the HTTP response header
- */
-static handler_t proxy_http_parse_response_headers(proxy_session *sess, chunkqueue *in) {
- data_string *ds;
-
- http_response_reset(sess->resp);
-
- /* http response parser. */
- switch(http_response_parse_cq(in, sess->resp)) {
- case PARSE_ERROR:
- /* bad gateway */
- http_response_reset(sess->resp);
- sess->have_response_headers = 1;
- sess->resp->status = 502;
- return HANDLER_ERROR;
- case PARSE_NEED_MORE:
- return HANDLER_GO_ON;
- case PARSE_SUCCESS:
- default:
- break;
- }
- /* check for Transfer-Encoding header. */
- if (NULL != (ds = (data_string *)array_get_element(sess->resp->headers, CONST_STR_LEN("Transfer-Encoding")))) {
- if (strstr(ds->value->ptr, "chunked")) {
- sess->is_chunked = 1;
- }
- }
- /* finished parsing response headers. */
- sess->have_response_headers = 1;
-
- switch (sess->resp->status) {
- case 205: /* class: header only */
- case 304:
- sess->is_request_finished = 1;
- }
- return HANDLER_FINISHED;
-}
-
-static handler_t proxy_http_parse_chunked_stream(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
- protocol_state_data *data = (protocol_state_data *)sess->proxy_con->protocol_data;
- char *err = NULL;
- off_t we_have = 0, we_want = 0;
- off_t chunk_len = 0;
- off_t offset = 0;
- buffer *b;
- chunk *c;
- char ch = '\0';
- int finished = 0;
-
- UNUSED(srv);
-
- for (c = in->first; c && !finished;) {
- if(c->mem->used == 0) {
- c = c->next;
- continue;
- }
- switch(data->chunk_parse_state) {
- case HTTP_CHUNK_LEN:
- /* parse chunk len. */
- for(offset = c->offset; (size_t)(offset) < (c->mem->used - 1) ; offset++) {
- ch = c->mem->ptr[offset];
- if(!light_isxdigit(ch)) break;
- }
- if(offset > c->offset) {
- buffer_append_string_len(data->buf, (c->mem->ptr + c->offset), offset - c->offset);
- in->bytes_out += (offset - c->offset);
- c->offset = offset;
- }
- if ( (size_t)offset == c->mem->used - 1) {
- break; /* get next chunk from queue */
- }
- /* now ch is the last character, and it wasn't an xdigit */
- if (!(ch == ' ' || ch == '\r' || ch == ';')) {
- /* protocol error. bad http-chunk len */
- return HANDLER_ERROR;
- }
- data->chunk_len = strtol(BUF_STR(data->buf), &err, 16);
- data->chunk_offset = 0;
- buffer_reset(data->buf);
- data->chunk_parse_state = HTTP_CHUNK_EXTENSION;
- case HTTP_CHUNK_EXTENSION:
- /* find CRLF. discard chunk-extension */
- for(ch = 0; (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
- ch = c->mem->ptr[c->offset];
- c->offset++;
- in->bytes_out++;
- }
- if(ch != '\n') {
- /* get next chunk from queue */
- break;
- }
- if(data->chunk_len > 0) {
- data->chunk_parse_state = HTTP_CHUNK_DATA;
- } else {
- data->chunk_parse_state = HTTP_CHUNK_END;
- }
- case HTTP_CHUNK_DATA:
- chunk_len = data->chunk_len - data->chunk_offset;
- /* copy chunk_len bytes from in queue to out queue. */
- we_have = c->mem->used - c->offset - 1;
- we_want = chunk_len > we_have ? we_have : chunk_len;
-
- if (c->offset == 0 && we_want == we_have) {
- /* we are copying the whole buffer, just steal it */
- chunkqueue_steal_chunk(out, c);
- /* c is an empty chunk now */
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
- c->offset += we_want;
- }
-
- chunk_len -= we_want;
- out->bytes_in += we_want;
- in->bytes_out += we_want;
- data->chunk_offset += we_want;
- if(chunk_len > 0) {
- /* get next chunk from queue */
- break;
- }
- data->chunk_offset = 0;
- data->chunk_parse_state = HTTP_CHUNK_END;
- case HTTP_CHUNK_END:
- /* discard CRLF.*/
- for(ch = 0; c->mem->used > 0 && (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
- ch = c->mem->ptr[c->offset];
- c->offset++;
- in->bytes_out++;
- }
- if(ch != '\n') {
- /* get next chunk from queue */
- break;
- }
- /* final chunk */
- if(data->chunk_len == 0) {
- finished = 1;
- }
- /* finished http-chunk. reset and parse next chunk. */
- protocol_state_data_reset(data);
- break;
- }
- if((size_t)(c->offset) == c->mem->used - 1) {
- c = c->next;
- }
- }
- chunkqueue_remove_finished_chunks(in);
- if (finished) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
- /* ran out of data. */
- return HANDLER_GO_ON;
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_http_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- chunk *c;
-
- if (in->first == NULL) {
- if ((sess->content_length >= 0 && sess->bytes_read == sess->content_length) || in->is_closed) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
- }
-
- /* parse response headers. */
- if (!sess->have_response_headers) {
- handler_t rc = proxy_http_parse_response_headers(sess, in);
- if (rc != HANDLER_FINISHED) return rc;
- }
-
- if (sess->is_request_finished) return HANDLER_FINISHED;
-
- if (sess->is_chunked) {
- return proxy_http_parse_chunked_stream(srv, sess, in, out);
- } else {
- /* no chunked encoding, ok, perhaps a content-length ? */
-
- chunkqueue_remove_finished_chunks(in);
- for (c = in->first; c; c = c->next) {
- buffer *b;
-
- if (c->mem->used == 0) continue;
-
- out->bytes_in += c->mem->used - c->offset - 1;
- in->bytes_out += c->mem->used - c->offset - 1;
-
- sess->bytes_read += c->mem->used - c->offset - 1;
-
- if (c->offset == 0) {
- /* we are copying the whole buffer, just steal it */
-
- chunkqueue_steal_chunk(out, c);
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1; /* marks is read */
- }
-
- if (sess->bytes_read == sess->content_length) {
- break;
- }
- }
-
- if (in->is_closed || sess->bytes_read == sess->content_length) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED; /* finished */
- }
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * transform the content-stream into a valid HTTP-content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_http_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- int we_have = 0;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- /* encode all request content data into output queue. */
- we_have = chunkqueue_steal_all_chunks(out, in);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- out->is_closed = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * generate a HTTP/1.1 proxy request from the set of request-headers
- *
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_http_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- connection *con = sess->remote_con;
- buffer *b;
- size_t i;
-
- UNUSED(srv);
- UNUSED(in);
-
- b = chunkqueue_get_append_buffer(out);
-
- /* request line */
- buffer_copy_string(b, get_http_method_name(con->request.http_method));
- buffer_append_string_len(b, CONST_STR_LEN(" "));
-
- /* request uri */
- buffer_append_string_buffer(b, sess->request_uri);
-
- if (con->request.http_version == HTTP_VERSION_1_1) {
- buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
- } else {
- buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
- }
-
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)sess->request_headers->data[i];
-
- buffer_append_string_buffer(b, ds->key);
- buffer_append_string_len(b, CONST_STR_LEN(": "));
- buffer_append_string_buffer(b, ds->value);
- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
- }
-
- buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
-
- out->bytes_in += b->used - 1;
-
- return HANDLER_FINISHED;
-}
-
-INIT_FUNC(mod_proxy_backend_http_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)("http");
-
- p->protocol->proxy_stream_init = proxy_http_init;
- p->protocol->proxy_stream_cleanup = proxy_http_cleanup;
- p->protocol->proxy_stream_decoder = proxy_http_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_http_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_http_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_http_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_http_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_http_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_http");
-
- p->init = mod_proxy_backend_http_init;
- p->cleanup = mod_proxy_backend_http_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;
-}
-
-