/* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "apr_thread_proc.h"
#include "apr_hash.h"
#include "apr_user.h"
+#include "apr_lib.h"
+#include "apr_optional.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
#define CORE_PRIVATE
#include "util_filter.h"
#include "httpd.h"
#include "http_config.h"
+#include "http_core.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "util_script.h"
#include "http_core.h"
-#include "apr_optional.h"
#include "mod_include.h"
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
#include "util_ebcdic.h"
-
+module AP_MODULE_DECLARE_DATA include_module;
static apr_hash_t *include_hash;
static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
+#define BYTE_COUNT_THRESHOLD AP_MIN_BYTES_TO_WRITE
/* ------------------------ Environment function -------------------------- */
const char *c;
const char *buf;
const char *str = STARTING_SEQUENCE;
+ apr_bucket *tmp_bkt;
+ apr_size_t start_index;
*do_cleanup = 0;
if (APR_BUCKET_IS_EOS(dptr)) {
break;
}
- apr_bucket_read(dptr, &buf, &len, 0);
+ apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
/* XXX handle retcodes */
if (len == 0) { /* end of pipe? */
break;
}
c = buf;
- while (c - buf != len) {
+ while (c < buf + len) {
+ if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
+ apr_bucket *start_bucket;
+
+ if (ctx->head_start_index > 0) {
+ start_index = ctx->head_start_index;
+ start_bucket = ctx->head_start_bucket;
+ }
+ else {
+ start_index = (c - buf);
+ start_bucket = dptr;
+ }
+ apr_bucket_split(start_bucket, start_index);
+ tmp_bkt = APR_BUCKET_NEXT(start_bucket);
+ if (ctx->head_start_index > 0) {
+ ctx->head_start_index = 0;
+ ctx->head_start_bucket = tmp_bkt;
+ ctx->parse_pos = 0;
+ ctx->state = PRE_HEAD;
+ }
+
+ return tmp_bkt;
+ }
+
if (*c == str[ctx->parse_pos]) {
if (ctx->state == PRE_HEAD) {
ctx->state = PARSE_HEAD;
}
else {
if (str[ctx->parse_pos] == '\0') {
- apr_bucket *tmp_bkt;
- apr_size_t start_index;
-
/* We want to split the bucket at the '<'. */
+ ctx->bytes_parsed++;
ctx->state = PARSE_DIRECTIVE;
ctx->tag_length = 0;
ctx->parse_pos = 0;
}
}
c++;
+ ctx->bytes_parsed++;
}
dptr = APR_BUCKET_NEXT(dptr);
} while (dptr != APR_BRIGADE_SENTINEL(bb));
if (APR_BUCKET_IS_EOS(dptr)) {
break;
}
- apr_bucket_read(dptr, &buf, &len, 0);
+ apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
/* XXX handle retcodes */
if (len == 0) { /* end of pipe? */
break;
else {
c = buf;
}
- while (c - buf != len) {
+ while (c < buf + len) {
+ if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
+ if (ctx->state == PARSE_DIRECTIVE) {
+ /* gonna start over parsing the directive next time through */
+ ctx->directive_length = 0;
+ ctx->tag_length = 0;
+ }
+ return dptr;
+ }
+
if (*c == str[ctx->parse_pos]) {
if (ctx->state != PARSE_TAIL) {
ctx->state = PARSE_TAIL;
* end of the END_SEQUENCE is in the current bucket.
* The beginning might be in a previous bucket.
*/
+ ctx->bytes_parsed++;
ctx->state = PARSED;
if ((c - buf) > 0) {
apr_bucket_split(dptr, c - buf);
}
}
c++;
+ ctx->bytes_parsed++;
}
dptr = APR_BUCKET_NEXT(dptr);
} while (dptr != APR_BRIGADE_SENTINEL(bb));
static apr_status_t get_combined_directive (include_ctx_t *ctx,
request_rec *r,
apr_bucket_brigade *bb,
- char *tmp_buf, int tmp_buf_size)
+ char *tmp_buf,
+ apr_size_t tmp_buf_size)
{
- int done = 0;
- apr_bucket *dptr;
+ int done = 0;
+ apr_bucket *dptr;
const char *tmp_from;
apr_size_t tmp_from_len;
}
}
} while ((!done) &&
- ((ctx->curr_tag_pos - ctx->combined_tag) < ctx->tag_length));
+ (ctx->curr_tag_pos < ctx->combined_tag + ctx->tag_length));
ctx->combined_tag[ctx->tag_length] = '\0';
ctx->curr_tag_pos = ctx->combined_tag;
}
}
- *c++ = '\0'; /* Overwrites delimiter (term or WS) with NULL. */
- ctx->curr_tag_pos = c;
+ *(c-shift_val) = '\0'; /* Overwrites delimiter (term or WS) with NULL. */
+ ctx->curr_tag_pos = ++c;
if (dodecode) {
decodehtml(*tag_val);
}
for (p = r; p != NULL && !founddupe; p = p->main) {
request_rec *q;
for (q = p; q != NULL; q = q->prev) {
- if ( (strcmp(q->filename, rr->filename) == 0) ||
- (strcmp(q->uri, rr->uri) == 0) ){
+ if ((q->filename && rr->filename && (strcmp(q->filename, rr->filename) == 0)) ||
+ (strcmp(q->uri, rr->uri) == 0)) {
founddupe = 1;
break;
}
/* Basically, it puts a bread crumb in here, then looks */
/* for the crumb later to see if its been here. */
if (rr)
- ap_set_module_config(rr->request_config, &includes_module, r);
+ ap_set_module_config(rr->request_config, &include_module, r);
if (!error_fmt) {
SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
/* destroy the sub request if it's not a nested include (crumb) */
if (rr != NULL
- && ap_get_module_config(rr->request_config, &includes_module)
+ && ap_get_module_config(rr->request_config, &include_module)
!= NESTED_INCLUDE_MAGIC) {
ap_destroy_sub_req(rr);
}
}
if (!strcmp(tag, "var")) {
const char *val = apr_table_get(r->subprocess_env, tag_val);
- int b_copy = 0;
if (val) {
switch(encode) {
- case E_NONE: echo_text = val; b_copy = 1; break;
+ case E_NONE: echo_text = val; break;
case E_URL: echo_text = ap_escape_uri(r->pool, val); break;
case E_ENTITY: echo_text = ap_escape_html(r->pool, val); break;
}
e_len = strlen(echo_text);
- tmp_buck = apr_bucket_create_heap(echo_text, e_len, 1, &e_wrt);
+ tmp_buck = apr_bucket_heap_create(echo_text, e_len, 1, &e_wrt);
}
else {
- tmp_buck = apr_bucket_create_immortal("(none)", sizeof("none"));
+ tmp_buck = apr_bucket_immortal_create("(none)", sizeof("(none)")-1);
}
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
}
}
-#define NEG_SIGN " -"
-#define ZERO_K " 0k"
-#define ONE_K " 1k"
-
-static void generate_size(apr_ssize_t size, char *buff, apr_size_t buff_size)
-{
- /* XXX: this -1 thing is a gross hack */
- if (size == (apr_ssize_t)-1) {
- memcpy (buff, NEG_SIGN, sizeof(NEG_SIGN)+1);
- }
- else if (!size) {
- memcpy (buff, ZERO_K, sizeof(ZERO_K)+1);
- }
- else if (size < 1024) {
- memcpy (buff, ONE_K, sizeof(ONE_K)+1);
- }
- else if (size < 1048576) {
- apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "k", (size + 512) / 1024);
- }
- else if (size < 103809024) {
- apr_snprintf(buff, buff_size, "%4.1fM", size / 1048576.0);
- }
- else {
- apr_snprintf(buff, buff_size, "%4" APR_SSIZE_T_FMT "M", (size + 524288) / 1048576);
- }
-}
-
static int handle_fsize(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char buff[50];
if (!(ctx->flags & FLAG_SIZE_IN_BYTES)) {
- generate_size(finfo.size, buff, sizeof(buff));
+ apr_strfsize(finfo.size, buff);
s_len = strlen (buff);
}
else {
s_len = pos;
}
- tmp_buck = apr_bucket_create_heap(buff, s_len, 1, &s_wrt);
+ tmp_buck = apr_bucket_heap_create(buff, s_len, 1, &s_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
*inserted_head = tmp_buck;
t_val = ap_ht_time(r->pool, finfo.mtime, ctx->time_str, 0);
t_len = strlen(t_val);
- tmp_buck = apr_bucket_create_heap(t_val, t_len, 1, &t_wrt);
+ tmp_buck = apr_bucket_heap_create(t_val, t_len, 1, &t_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
*inserted_head = tmp_buck;
return (0);
}
root = current = (struct parse_node *) NULL;
- if (apr_create_pool(&expr_pool, r->pool) != APR_SUCCESS)
+ if (apr_pool_create(&expr_pool, r->pool) != APR_SUCCESS)
return 0;
/* Create Parse Tree */
retval = (root == (struct parse_node *) NULL) ? 0 : root->value;
RETURN:
- apr_destroy_pool(expr_pool);
+ apr_pool_destroy(expr_pool);
return (retval);
}
cond_txt[31] = '1'; \
} \
memcpy(&cond_txt[5], tag_text, sizeof(tag_text)); \
- t_buck = apr_bucket_create_heap(cond_txt, sizeof(cond_txt), 1, &c_wrt); \
+ t_buck = apr_bucket_heap_create(cond_txt, sizeof(cond_txt), 1, &c_wrt); \
APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \
\
if (ins_head == NULL) { \
{ \
apr_size_t b_wrt; \
if (d_buf[0] != '\0') { \
- t_buck = apr_bucket_create_heap(d_buf, strlen(d_buf), 1, &b_wrt); \
+ t_buck = apr_bucket_heap_create(d_buf, strlen(d_buf), 1, &b_wrt); \
APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \
\
if (ins_head == NULL) { \
if (1) {
apr_size_t d_len = 0, d_wrt = 0;
d_len = sprintf(debug_buf, "**** if expr=\"%s\"\n", expr);
- tmp_buck = apr_bucket_create_heap(debug_buf, d_len, 1, &d_wrt);
+ tmp_buck = apr_bucket_heap_create(debug_buf, d_len, 1, &d_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
if (1) {
apr_size_t d_len = 0, d_wrt = 0;
d_len = sprintf(debug_buf, "**** elif expr=\"%s\"\n", expr);
- tmp_buck = apr_bucket_create_heap(debug_buf, d_len, 1, &d_wrt);
+ tmp_buck = apr_bucket_heap_create(debug_buf, d_len, 1, &d_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
v_len = strlen(val_text);
/* Key_text */
- tmp_buck = apr_bucket_create_heap(key_text, k_len, 1, &t_wrt);
+ tmp_buck = apr_bucket_heap_create(key_text, k_len, 1, &t_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
*inserted_head = tmp_buck;
}
/* = */
- tmp_buck = apr_bucket_create_immortal("=", 1);
+ tmp_buck = apr_bucket_immortal_create("=", 1);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
/* Value_text */
- tmp_buck = apr_bucket_create_heap(val_text, v_len, 1, &t_wrt);
+ tmp_buck = apr_bucket_heap_create(val_text, v_len, 1, &t_wrt);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
/* newline... */
- tmp_buck = apr_bucket_create_immortal("\n", 1);
+ tmp_buck = apr_bucket_immortal_create("\n", 1);
APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
}
return 0;
return 0;
}
-
/* -------------------------- The main function --------------------------- */
-static void send_parsed_content(apr_bucket_brigade **bb, request_rec *r,
- ap_filter_t *f)
+static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
+ request_rec *r, ap_filter_t *f)
{
include_ctx_t *ctx = f->ctx;
apr_bucket *dptr = APR_BRIGADE_FIRST(*bb);
apr_bucket *tmp_dptr;
apr_bucket_brigade *tag_and_after;
int ret;
+ apr_status_t rv;
if (r->args) { /* add QUERY stuff to env cause it ain't yet */
char *arg_copy = apr_pstrdup(r->pool, r->args);
if ((do_cleanup) && (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade))) {
apr_bucket *tmp_bkt;
- tmp_bkt = apr_bucket_create_immortal(STARTING_SEQUENCE, cleanup_bytes);
+ tmp_bkt = apr_bucket_immortal_create(STARTING_SEQUENCE,
+ cleanup_bytes);
APR_BRIGADE_INSERT_HEAD(*bb, tmp_bkt);
-
- while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
- }
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
/* If I am inside a conditional (if, elif, else) that is false
apr_bucket *free_bucket = dptr;
dptr = APR_BUCKET_NEXT (dptr);
- APR_BUCKET_REMOVE(free_bucket);
- apr_bucket_destroy(free_bucket);
+ apr_bucket_delete(free_bucket);
}
}
dptr = APR_BRIGADE_SENTINEL(*bb);
}
}
+ else if ((tmp_dptr != NULL) && (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) {
+ /* Send the large chunk of pre-tag bytes... */
+ tag_and_after = apr_brigade_split(*bb, tmp_dptr);
+ rv = ap_pass_brigade(f->next, *bb);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ *bb = tag_and_after;
+ dptr = tmp_dptr;
+ ctx->bytes_parsed = 0;
+ }
else if (tmp_dptr == NULL) { /* There was no possible SSI tag in the */
dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
}
APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
*bb = tag_and_after;
}
+ else if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
+ SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+ }
}
else {
dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
/* DO CLEANUP HERE!!!!! */
tmp_dptr = ctx->head_start_bucket;
if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
- }
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
else {
do {
tmp_bkt = tmp_dptr;
tmp_dptr = APR_BUCKET_NEXT (tmp_dptr);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
+ apr_bucket_delete(tmp_bkt);
} while ((tmp_dptr != dptr) &&
(tmp_dptr != APR_BRIGADE_SENTINEL(*bb)));
}
- return;
+ return APR_SUCCESS;
}
- /* Even if I don't generate any content, I know at this point that
- * I will at least remove the discovered SSI tag, thereby making
- * the content shorter than it was. This is the safest point I can
- * find to unset this field.
- */
- apr_table_unset(f->r->headers_out, "Content-Length");
-
/* Can't destroy the tag buckets until I'm done processing
* because the combined_tag might just be pointing to
* the contents of a single bucket!
ctx->curr_tag_pos = &ctx->combined_tag[ctx->directive_length+1];
handle_func =
- (int (*)(include_ctx_t *, apr_bucket_brigade **, request_rec *,
- ap_filter_t *, apr_bucket *, apr_bucket **))
- apr_hash_get(include_hash, ctx->combined_tag, ctx->directive_length+1);
+ (include_handler_fn_t *)apr_hash_get(include_hash,
+ ctx->combined_tag,
+ ctx->directive_length+1);
if (handle_func != NULL) {
ret = (*handle_func)(ctx, bb, r, f, dptr, &content_head);
}
}
tmp_dptr = ctx->head_start_bucket;
if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
- }
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
else {
do {
tmp_bkt = tmp_dptr;
tmp_dptr = APR_BUCKET_NEXT (tmp_dptr);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
+ apr_bucket_delete(tmp_bkt);
} while ((tmp_dptr != content_head) &&
(tmp_dptr != APR_BRIGADE_SENTINEL(*bb)));
}
ctx->directive_length = 0;
if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = APR_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- APR_BUCKET_REMOVE(tmp_bkt);
- apr_bucket_destroy(tmp_bkt);
- }
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
ctx->state = PRE_HEAD;
do {
free_bucket = dptr;
dptr = APR_BUCKET_NEXT (dptr);
- APR_BUCKET_REMOVE(free_bucket);
- apr_bucket_destroy(free_bucket);
+ apr_bucket_delete(free_bucket);
} while (dptr != APR_BRIGADE_SENTINEL(*bb));
}
else { /* Otherwise pass it along... */
- ap_pass_brigade(f->next, *bb); /* No SSI tags in this brigade... */
+ rv = ap_pass_brigade(f->next, *bb); /* No SSI tags in this brigade... */
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ ctx->bytes_parsed = 0;
}
}
else if (ctx->state == PARSED) { /* Invalid internal condition... */
}
/* Set aside tag, pass pre-tag... */
tag_and_after = apr_brigade_split(*bb, ctx->head_start_bucket);
- ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after);
- ap_pass_brigade(f->next, *bb);
+ ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after, r->pool);
+ rv = ap_pass_brigade(f->next, *bb);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ ctx->bytes_parsed = 0;
}
}
+ return APR_SUCCESS;
}
/*****************************************************************
* option only changes the default.
*/
-module includes_module;
+module include_module;
enum xbithack {
xbithack_off, xbithack_on, xbithack_full
};
+typedef struct {
+ char *default_error_msg;
+ char *default_time_fmt;
+ enum xbithack *xbithack;
+} include_dir_config;
+
#ifdef XBITHACK
#define DEFAULT_XBITHACK xbithack_full
#else
static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
{
- enum xbithack *result = (enum xbithack *) apr_palloc(p, sizeof(enum xbithack));
- *result = DEFAULT_XBITHACK;
+ include_dir_config *result =
+ (include_dir_config *)apr_palloc(p, sizeof(include_dir_config));
+ enum xbithack *xbh = (enum xbithack *) apr_palloc(p, sizeof(enum xbithack));
+ *xbh = DEFAULT_XBITHACK;
+ result->default_error_msg = DEFAULT_ERROR_MSG;
+ result->default_time_fmt = DEFAULT_TIME_FORMAT;
+ result->xbithack = xbh;
return result;
}
static const char *set_xbithack(cmd_parms *cmd, void *xbp, const char *arg)
{
- enum xbithack *state = (enum xbithack *) xbp;
+ include_dir_config *conf = (include_dir_config *)xbp;
if (!strcasecmp(arg, "off")) {
- *state = xbithack_off;
+ *conf->xbithack = xbithack_off;
}
else if (!strcasecmp(arg, "on")) {
- *state = xbithack_on;
+ *conf->xbithack = xbithack_on;
}
else if (!strcasecmp(arg, "full")) {
- *state = xbithack_full;
+ *conf->xbithack = xbithack_full;
}
else {
return "XBitHack must be set to Off, On, or Full";
return NULL;
}
-static int includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
+static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
{
request_rec *r = f->r;
include_ctx_t *ctx = f->ctx;
- enum xbithack *state =
- (enum xbithack *) ap_get_module_config(r->per_dir_config, &includes_module);
request_rec *parent;
+ apr_status_t rv;
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
if (!(ap_allow_options(r) & OPT_INCLUDES)) {
return ap_pass_brigade(f->next, b);
}
- r->allowed |= (1 << M_GET);
+ r->allowed |= (AP_METHOD_BIT << M_GET);
if (r->method_number != M_GET) {
return ap_pass_brigade(f->next, b);
}
}
ctx->ssi_tag_brigade = apr_brigade_create(f->c->pool);
- apr_cpystrn(ctx->error_str, DEFAULT_ERROR_MSG, sizeof(ctx->error_str));
- apr_cpystrn(ctx->time_str, DEFAULT_TIME_FORMAT, sizeof(ctx->time_str));
+ apr_cpystrn(ctx->error_str, conf->default_error_msg, sizeof(ctx->error_str));
+ apr_cpystrn(ctx->time_str, conf->default_time_fmt, sizeof(ctx->time_str));
ctx->error_length = strlen(ctx->error_str);
}
else {
- ap_pass_brigade(f->next, b);
- return APR_ENOMEM;
+ return ap_pass_brigade(f->next, b);
}
}
+ else {
+ ctx->bytes_parsed = 0;
+ }
/* Assure the platform supports Group protections */
- if ((*state == xbithack_full)
+ if ((*conf->xbithack == xbithack_full)
&& (r->finfo.valid & APR_FINFO_GPROT)
&& (r->finfo.protection & APR_GEXECUTE)) {
ap_update_mtime(r, r->finfo.mtime);
ap_set_last_modified(r);
}
- if ((parent = ap_get_module_config(r->request_config, &includes_module))) {
+ if ((parent = ap_get_module_config(r->request_config, &include_module))) {
/* Kludge --- for nested includes, we want to keep the subprocess
* environment of the base document (for compatibility); that means
* torquing our own last_modified date as well so that the
* environment */
ap_add_common_vars(r);
ap_add_cgi_vars(r);
- add_include_vars(r, DEFAULT_TIME_FORMAT);
+ add_include_vars(r, conf->default_time_fmt);
}
/* XXX: this is bogus, at some point we're going to do a subrequest,
* and when we do it we're going to be subjecting code that doesn't
*/
- send_parsed_content(&b, r, f);
+ /* Always unset the content-length. There is no way to know if
+ * the content will be modified at some point by send_parsed_content.
+ * It is very possible for us to not find any content in the first
+ * 9k of the file, but still have to modify the content of the file.
+ * If we are going to pass the file through send_parsed_content, then
+ * the content-length should just be unset.
+ */
+ apr_table_unset(f->r->headers_out, "Content-Length");
+
+ rv = send_parsed_content(&b, r, f);
if (parent) {
/* signify that the sub request should not be killed */
- ap_set_module_config(r->request_config, &includes_module,
+ ap_set_module_config(r->request_config, &include_module,
NESTED_INCLUDE_MAGIC);
}
- return OK;
+ return rv;
}
-static void ap_register_include_handler(char *tag, include_handler func)
+static void ap_register_include_handler(char *tag, include_handler_fn_t *func)
{
apr_hash_set(include_hash, tag, strlen(tag) + 1, (const void *)func);
}
static void include_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
- include_hash = apr_make_hash(p);
+ include_hash = apr_hash_make(p);
ssi_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
}
}
+static const char *set_default_error_msg(cmd_parms *cmd, void *mconfig, const char *msg)
+{
+ include_dir_config *conf = (include_dir_config *)mconfig;
+ conf->default_error_msg = apr_pstrdup(cmd->pool, msg);
+ return NULL;
+}
+
+static const char *set_default_time_fmt(cmd_parms *cmd, void *mconfig, const char *fmt)
+{
+ include_dir_config *conf = (include_dir_config *)mconfig;
+ conf->default_time_fmt = apr_pstrdup(cmd->pool, fmt);
+ return NULL;
+}
+
/*
* Module definition and configuration data structs...
*/
{
AP_INIT_TAKE1("XBitHack", set_xbithack, NULL, OR_OPTIONS,
"Off, On, or Full"),
+ AP_INIT_TAKE1("SSIErrorMsg", set_default_error_msg, NULL, OR_ALL,
+ "a string"),
+ AP_INIT_TAKE1("SSITimeFormat", set_default_time_fmt, NULL, OR_ALL,
+ "a strftime(3) formatted string"),
{NULL}
};
+static int xbithack_handler(request_rec *r)
+{
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+ /* OS/2 dosen't currently support the xbithack. This is being worked on. */
+ return DECLINED;
+#else
+ enum xbithack *state;
+
+ if (ap_strcmp_match(r->handler, "text/html")) {
+ return DECLINED;
+ }
+ if (!(r->finfo.protection & APR_UEXECUTE)) {
+ return DECLINED;
+ }
+
+ state = (enum xbithack *) ap_get_module_config(r->per_dir_config,
+ &include_module);
+
+ if (*state == xbithack_off) {
+ return DECLINED;
+ }
+ /* We always return declined, because the default handler will actually
+ * serve the file. All we have to do is add the filter.
+ */
+ ap_add_output_filter("INCLUDES", NULL, r, r->connection);
+ return DECLINED;
+#endif
+}
+
static void register_hooks(apr_pool_t *p)
{
APR_REGISTER_OPTIONAL_FN(ap_ssi_get_tag_and_value);
APR_REGISTER_OPTIONAL_FN(ap_ssi_parse_string);
APR_REGISTER_OPTIONAL_FN(ap_register_include_handler);
ap_hook_post_config(include_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
+ ap_hook_handler(xbithack_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_CONTENT);
}
-module AP_MODULE_DECLARE_DATA includes_module =
+module AP_MODULE_DECLARE_DATA include_module =
{
STANDARD20_MODULE_STUFF,
create_includes_dir_config, /* dir config creater */