/* ** Licensed to the Apache Software Foundation (ASF) under one or more ** contributor license agreements. See the NOTICE file distributed with ** this work for additional information regarding copyright ownership. ** The ASF licenses this file to You under the Apache License, Version 2.0 ** (the "License"); you may not use this file except in compliance with ** the License. You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include "apr_strings.h" #include "apreq_module.h" #include "apreq_error.h" #include "apreq_util.h" #define READ_BYTES (64 * 1024) struct custom_handle { struct apreq_handle_t handle; apr_table_t *jar, *args, *body; apr_status_t jar_status, args_status, body_status; apreq_parser_t *parser; apr_uint64_t read_limit; apr_uint64_t bytes_read; apr_bucket_brigade *in; apr_bucket_brigade *tmpbb; }; static apr_status_t custom_parse_brigade(apreq_handle_t *handle, apr_uint64_t bytes) { struct custom_handle *req = (struct custom_handle *)handle; apr_status_t s; apr_bucket *e; if (req->body_status != APR_INCOMPLETE) return req->body_status; switch (s = apr_brigade_partition(req->in, bytes, &e)) { apr_off_t len; case APR_SUCCESS: apreq_brigade_move(req->tmpbb, req->in, e); req->bytes_read += bytes; if (req->bytes_read > req->read_limit) { req->body_status = APREQ_ERROR_OVERLIMIT; break; } req->body_status = apreq_parser_run(req->parser, req->body, req->tmpbb); apr_brigade_cleanup(req->tmpbb); break; case APR_INCOMPLETE: apreq_brigade_move(req->tmpbb, req->in, e); s = apr_brigade_length(req->tmpbb, 1, &len); if (s != APR_SUCCESS) { req->body_status = s; break; } req->bytes_read += len; if (req->bytes_read > req->read_limit) { req->body_status = APREQ_ERROR_OVERLIMIT; break; } req->body_status = apreq_parser_run(req->parser, req->body, req->tmpbb); apr_brigade_cleanup(req->tmpbb); break; default: req->body_status = s; } return req->body_status; } static apr_status_t custom_jar(apreq_handle_t *handle, const apr_table_t **t) { struct custom_handle *req = (struct custom_handle *)handle; *t = req->jar; return req->jar_status; } static apr_status_t custom_args(apreq_handle_t *handle, const apr_table_t **t) { struct custom_handle *req = (struct custom_handle*)handle; *t = req->args; return req->args_status; } static apr_status_t custom_body(apreq_handle_t *handle, const apr_table_t **t) { struct custom_handle *req = (struct custom_handle*)handle; while (req->body_status == APR_INCOMPLETE) custom_parse_brigade(handle, READ_BYTES); *t = req->body; return req->body_status; } static apreq_cookie_t *custom_jar_get(apreq_handle_t *handle, const char *name) { struct custom_handle *req = (struct custom_handle*)handle; const char *val; if (req->jar == NULL || name == NULL) return NULL; val = apr_table_get(req->jar, name); if (val == NULL) return NULL; return apreq_value_to_cookie(val); } static apreq_param_t *custom_args_get(apreq_handle_t *handle, const char *name) { struct custom_handle *req = (struct custom_handle*)handle; const char *val; if (req->args == NULL || name == NULL) return NULL; val = apr_table_get(req->args, name); if (val == NULL) return NULL; return apreq_value_to_param(val); } static apreq_param_t *custom_body_get(apreq_handle_t *handle, const char *name) { struct custom_handle *req = (struct custom_handle*)handle; const char *val; if (req->body == NULL || name == NULL) return NULL; while (1) { *(const char **)&val = apr_table_get(req->body, name); if (val != NULL) break; if (req->body_status == APR_INCOMPLETE) custom_parse_brigade(handle, READ_BYTES); else return NULL; } return apreq_value_to_param(val); } static apr_status_t custom_parser_get(apreq_handle_t *handle, const apreq_parser_t **parser) { struct custom_handle *req = (struct custom_handle*)handle; *parser = req->parser; return APR_SUCCESS; } static apr_status_t custom_parser_set(apreq_handle_t *handle, apreq_parser_t *parser) { (void)handle; (void)parser; return APR_ENOTIMPL; } static apr_status_t custom_hook_add(apreq_handle_t *handle, apreq_hook_t *hook) { struct custom_handle *req = (struct custom_handle*)handle; apreq_parser_add_hook(req->parser, hook); return APR_SUCCESS; } static apr_status_t custom_brigade_limit_get(apreq_handle_t *handle, apr_size_t *bytes) { struct custom_handle *req = (struct custom_handle*)handle; *bytes = req->parser->brigade_limit; return APR_SUCCESS; } static apr_status_t custom_brigade_limit_set(apreq_handle_t *handle, apr_size_t bytes) { (void)handle; (void)bytes; return APR_ENOTIMPL; } static apr_status_t custom_read_limit_get(apreq_handle_t *handle, apr_uint64_t *bytes) { struct custom_handle *req = (struct custom_handle*)handle; *bytes = req->read_limit; return APR_SUCCESS; } static apr_status_t custom_read_limit_set(apreq_handle_t *handle, apr_uint64_t bytes) { (void)handle; (void)bytes; return APR_ENOTIMPL; } static apr_status_t custom_temp_dir_get(apreq_handle_t *handle, const char **path) { struct custom_handle *req = (struct custom_handle*)handle; *path = req->parser->temp_dir; return APR_SUCCESS; } static apr_status_t custom_temp_dir_set(apreq_handle_t *handle, const char *path) { (void)handle; (void)path; return APR_ENOTIMPL; } static APREQ_MODULE(custom, 20070428); APREQ_DECLARE(apreq_handle_t *)apreq_handle_custom(apr_pool_t *pool, const char *query_string, const char *cookie, apreq_parser_t *parser, apr_uint64_t read_limit, apr_bucket_brigade *in) { struct custom_handle *req; req = apr_palloc(pool, sizeof(*req)); req->handle.module = &custom_module; req->handle.pool = pool; req->handle.bucket_alloc = in->bucket_alloc; req->read_limit = read_limit; req->bytes_read = 0; req->parser = parser; req->in = apr_brigade_create(pool, in->bucket_alloc); req->tmpbb = apr_brigade_create(pool, in->bucket_alloc); req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS); req->body_status = APR_INCOMPLETE; APR_BRIGADE_CONCAT(req->in, in); if (cookie != NULL) { req->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS); req->jar_status = apreq_parse_cookie_header(pool, req->jar, cookie); } else { req->jar = NULL; req->jar_status = APREQ_ERROR_NODATA; } if (query_string != NULL) { req->args = apr_table_make(pool, APREQ_DEFAULT_NELTS); req->args_status = apreq_parse_query_string(pool, req->args, query_string); } else { req->args = NULL; req->args_status = APREQ_ERROR_NODATA; } if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(req->in))) { apr_bucket *eos = apr_bucket_eos_create(in->bucket_alloc); APR_BRIGADE_INSERT_TAIL(req->in, eos); } return &req->handle; }