/* ====================================================================
* 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
* incorporated into the Apache module framework by rst.
*
*/
-/*
- * sub key may be anything a Perl*Handler can be:
- * subroutine name, package name (defaults to package::handler),
- * Class->method call or anoymous sub {}
- *
- * Child <!--#perl sub="sub {print $$}" --> accessed
- * <!--#perl sub="sub {print ++$Access::Cnt }" --> times. <br>
- *
- * <!--#perl arg="one" sub="mymod::includer" -->
- *
- * -Doug MacEachern
- */
+
+#include "apr.h"
+#include "apr_strings.h"
+#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
-#ifdef USE_PERL_SSI
-#include "config.h"
-#include "modules/perl/mod_perl.h"
-#else
-#include "apr_strings.h"
#include "ap_config.h"
#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 "util_script.h"
#include "http_core.h"
#include "mod_include.h"
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-#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 -------------------------- */
/* XXX: could use ap_table_overlap here */
static void add_include_vars(request_rec *r, char *timefmt)
{
-#ifndef WIN32
- struct passwd *pw;
-#endif /* ndef WIN32 */
+ char *pwname;
apr_table_t *e = r->subprocess_env;
char *t;
apr_time_t date = r->request_time;
ap_ht_time(r->pool, r->finfo.mtime, timefmt, 0));
apr_table_setn(e, "DOCUMENT_URI", r->uri);
apr_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
-#ifndef WIN32
- pw = getpwuid(r->finfo.user);
- if (pw) {
- apr_table_setn(e, "USER_NAME", apr_pstrdup(r->pool, pw->pw_name));
+ if (apr_get_username(&pwname, r->finfo.user, r->pool) == APR_SUCCESS) {
+ apr_table_setn(e, "USER_NAME", pwname);
}
else {
- apr_table_setn(e, "USER_NAME", apr_psprintf(r->pool, "user#%lu",
- (unsigned long) r->finfo.user));
+ apr_table_setn(e, "USER_NAME", "<unknown>");
}
-#endif /* ndef WIN32 */
-
if ((t = strrchr(r->filename, '/'))) {
apr_table_setn(e, "DOCUMENT_NAME", ++t);
}
* first byte of the BEGINNING_SEQUENCE (after finding a complete match) or it
* returns NULL if no match found.
*/
-static ap_bucket *find_start_sequence(ap_bucket *dptr, include_ctx_t *ctx,
- ap_bucket_brigade *bb, int *do_cleanup)
+static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx,
+ apr_bucket_brigade *bb, int *do_cleanup)
{
- apr_ssize_t len;
+ apr_size_t len;
const char *c;
const char *buf;
const char *str = STARTING_SEQUENCE;
+ apr_bucket *tmp_bkt;
+ apr_size_t start_index;
*do_cleanup = 0;
do {
- if (AP_BUCKET_IS_EOS(dptr)) {
+ if (APR_BUCKET_IS_EOS(dptr)) {
break;
}
- ap_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') {
- ap_bucket *tmp_bkt;
- apr_ssize_t start_index;
-
/* We want to split the bucket at the '<'. */
- ctx->state = PARSE_TAG;
+ ctx->bytes_parsed++;
+ ctx->state = PARSE_DIRECTIVE;
ctx->tag_length = 0;
ctx->parse_pos = 0;
ctx->tag_start_bucket = dptr;
ctx->tag_start_index = c - buf;
if (ctx->head_start_index > 0) {
start_index = (c - buf) - ctx->head_start_index;
- ap_bucket_split(ctx->head_start_bucket, ctx->head_start_index);
- tmp_bkt = AP_BUCKET_NEXT(ctx->head_start_bucket);
+ apr_bucket_split(ctx->head_start_bucket, ctx->head_start_index);
+ tmp_bkt = APR_BUCKET_NEXT(ctx->head_start_bucket);
if (dptr == ctx->head_start_bucket) {
ctx->tag_start_bucket = tmp_bkt;
ctx->tag_start_index = start_index;
}
}
c++;
+ ctx->bytes_parsed++;
}
- dptr = AP_BUCKET_NEXT(dptr);
- } while (dptr != AP_BRIGADE_SENTINEL(bb));
+ dptr = APR_BUCKET_NEXT(dptr);
+ } while (dptr != APR_BRIGADE_SENTINEL(bb));
return NULL;
}
-static ap_bucket *find_end_sequence(ap_bucket *dptr, include_ctx_t *ctx, ap_bucket_brigade *bb)
+static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_bucket_brigade *bb)
{
- apr_ssize_t len;
+ apr_size_t len;
const char *c;
const char *buf;
const char *str = ENDING_SEQUENCE;
do {
- if (AP_BUCKET_IS_EOS(dptr)) {
+ if (APR_BUCKET_IS_EOS(dptr)) {
break;
}
- ap_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_TAG) {
+ if (ctx->state != PARSE_TAIL) {
ctx->state = PARSE_TAIL;
ctx->tail_start_bucket = dptr;
ctx->tail_start_index = c - buf;
ctx->parse_pos++;
}
else {
- if (ctx->state == PARSE_TAG) {
+ if (ctx->state == PARSE_DIRECTIVE) {
if (ctx->tag_length == 0) {
if (!apr_isspace(*c)) {
ctx->tag_start_bucket = dptr;
ctx->tag_start_index = c - buf;
ctx->tag_length = 1;
+ ctx->directive_length = 1;
}
}
else {
+ if (!apr_isspace(*c)) {
+ ctx->directive_length++;
+ }
+ else {
+ ctx->state = PARSE_TAG;
+ }
ctx->tag_length++;
}
}
+ else if (ctx->state == PARSE_TAG) {
+ ctx->tag_length++;
+ }
else {
if (str[ctx->parse_pos] == '\0') {
- ap_bucket *tmp_buck = dptr;
+ apr_bucket *tmp_buck = dptr;
/* We want to split the bucket at the '>'. The
* 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) {
- ap_bucket_split(dptr, c - buf);
- tmp_buck = AP_BUCKET_NEXT(dptr);
+ apr_bucket_split(dptr, c - buf);
+ tmp_buck = APR_BUCKET_NEXT(dptr);
}
return (tmp_buck);
}
ctx->tag_length += ctx->parse_pos;
if (*c == str[0]) {
- ctx->parse_pos = 1;
ctx->state = PARSE_TAIL;
ctx->tail_start_bucket = dptr;
ctx->tail_start_index = c - buf;
+ ctx->tag_length += ctx->parse_pos;
+ ctx->parse_pos = 1;
}
else {
- ctx->parse_pos = 0;
- ctx->state = PARSE_TAG;
+ if (ctx->tag_length > ctx->directive_length) {
+ ctx->state = PARSE_TAG;
+ }
+ else {
+ ctx->state = PARSE_DIRECTIVE;
+ ctx->directive_length += ctx->parse_pos;
+ }
ctx->tail_start_bucket = NULL;
ctx->tail_start_index = 0;
+ ctx->tag_length += ctx->parse_pos;
+ ctx->parse_pos = 0;
}
}
}
}
c++;
+ ctx->bytes_parsed++;
}
- dptr = AP_BUCKET_NEXT(dptr);
- } while (dptr != AP_BRIGADE_SENTINEL(bb));
+ dptr = APR_BUCKET_NEXT(dptr);
+ } while (dptr != APR_BRIGADE_SENTINEL(bb));
return NULL;
}
*/
static apr_status_t get_combined_directive (include_ctx_t *ctx,
request_rec *r,
- ap_bucket_brigade *bb,
- char *tmp_buf, int tmp_buf_size)
+ apr_bucket_brigade *bb,
+ char *tmp_buf,
+ apr_size_t tmp_buf_size)
{
- int done = 0;
- ap_bucket *dptr;
+ int done = 0;
+ apr_bucket *dptr;
const char *tmp_from;
- apr_ssize_t tmp_from_len;
+ apr_size_t tmp_from_len;
/* If the tag length is longer than the tmp buffer, allocate space. */
if (ctx->tag_length > tmp_buf_size-1) {
/* Prime the pump. Start at the beginning of the tag... */
dptr = ctx->tag_start_bucket;
- ap_bucket_read (dptr, &tmp_from, &tmp_from_len, 0); /* Read the bucket... */
+ apr_bucket_read (dptr, &tmp_from, &tmp_from_len, 0); /* Read the bucket... */
/* Adjust the pointer to start at the tag within the bucket... */
if (dptr == ctx->tail_start_bucket) {
done = 1;
}
else {
- dptr = AP_BUCKET_NEXT (dptr);
- ap_bucket_read (dptr, &tmp_from, &tmp_from_len, 0);
+ dptr = APR_BUCKET_NEXT (dptr);
+ apr_bucket_read (dptr, &tmp_from, &tmp_from_len, 0);
/* Adjust the count to stop at the beginning of the tail. */
if (dptr == ctx->tail_start_bucket) {
tmp_from_len -= (tmp_from_len - ctx->tail_start_index);
}
}
} 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;
#define SKIP_TAG_WHITESPACE(ptr) while ((*ptr != '\0') && (apr_isspace (*ptr))) ptr++
-static void get_tag_and_value(include_ctx_t *ctx, char **tag,
+static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
char **tag_val, int dodecode)
{
char *c = ctx->curr_tag_pos;
}
}
- *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);
}
return;
}
-static char *get_directive(include_ctx_t *ctx, dir_token_id *fnd_token)
-{
- char *c = ctx->curr_tag_pos;
- char *dest;
- int len = 0;
-
- SKIP_TAG_WHITESPACE(c);
-
- dest = c;
- /* now get directive */
- while ((*c != '\0') && (!apr_isspace(*c))) {
- *c = apr_tolower(*c);
- c++;
- len++;
- }
-
- *c++ = '\0';
- ctx->curr_tag_pos = c;
-
- *fnd_token = TOK_UNKNOWN;
- switch (len) {
- case 2: if (!strcmp(dest, "if")) *fnd_token = TOK_IF;
- break;
- case 3: if (!strcmp(dest, "set")) *fnd_token = TOK_SET;
- break;
- case 4: if (!strcmp(dest, "else")) *fnd_token = TOK_ELSE;
- else if (!strcmp(dest, "elif")) *fnd_token = TOK_ELIF;
- else if (!strcmp(dest, "exec")) *fnd_token = TOK_EXEC;
- else if (!strcmp(dest, "echo")) *fnd_token = TOK_ECHO;
-#ifdef USE_PERL_SSI
- else if (!strcmp(dest, "perl")) *fnd_token = TOK_PERL;
-#endif
- break;
- case 5: if (!strcmp(dest, "endif")) *fnd_token = TOK_ENDIF;
- else if (!strcmp(dest, "fsize")) *fnd_token = TOK_FSIZE;
- break;
- case 6: if (!strcmp(dest, "config")) *fnd_token = TOK_CONFIG;
- break;
- case 7: if (!strcmp(dest, "include")) *fnd_token = TOK_INCLUDE;
- break;
- case 8: if (!strcmp(dest, "flastmod")) *fnd_token = TOK_FLASTMOD;
- else if (!strcmp(dest, "printenv")) *fnd_token = TOK_PRINTENV;
- break;
- }
-
- return (dest);
-}
/*
* Do variable substitution on strings
*/
-static void parse_string(request_rec *r, const char *in, char *out,
- size_t length, int leave_name)
+static void ap_ssi_parse_string(request_rec *r, const char *in, char *out,
+ size_t length, int leave_name)
{
char ch;
char *next = out;
break;
case '$':
{
-/* pjr hack char var[MAX_STRING_LEN]; */
const char *start_of_var_name;
char *end_of_var_name; /* end of var name + 1 */
- const char *expansion;
- const char *val;
+ const char *expansion, *temp_end, *val;
char tmp_store;
size_t l;
*next = '\0';
return;
}
- (const char *)end_of_var_name = in;
+ temp_end = in;
+ end_of_var_name = (char *)temp_end;
++in;
}
else {
while (apr_isalnum(*in) || *in == '_') {
++in;
}
- (const char *)end_of_var_name = in;
+ temp_end = in;
+ end_of_var_name = (char *)temp_end;
}
/* what a pain, too bad there's no table_getn where you can
* pass a non-nul terminated string */
l = end_of_var_name - start_of_var_name;
if (l != 0) {
-/* pjr - this is a test hack to avoid a memcpy. Make sure that this works...
-* l = (l > sizeof(var) - 1) ? (sizeof(var) - 1) : l;
-* memcpy(var, start_of_var_name, l);
-* var[l] = '\0';
-*
-* val = apr_table_get(r->subprocess_env, var);
-*/
-/* pjr hack */ tmp_store = *end_of_var_name;
-/* pjr hack */ *end_of_var_name = '\0';
-/* pjr hack */ val = apr_table_get(r->subprocess_env, start_of_var_name);
-/* pjr hack */ *end_of_var_name = tmp_store;
+ tmp_store = *end_of_var_name;
+ *end_of_var_name = '\0';
+ val = apr_table_get(r->subprocess_env, start_of_var_name);
+ *end_of_var_name = tmp_store;
if (val) {
expansion = val;
/* --------------------------- Action handlers ---------------------------- */
-static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
- ap_bucket *head_ptr, ap_bucket **inserted_head)
-{
- request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
- int rr_status;
- ap_bucket *tmp_buck, *tmp2_buck;
-
- if (rr->status != HTTP_OK) {
- return -1;
- }
-
- /* No hardwired path info or query allowed */
-
- if ((rr->path_info && rr->path_info[0]) || rr->args) {
- return -1;
- }
- if (rr->finfo.protection == 0) {
- return -1;
- }
-
- /* Script gets parameters of the *document*, for back compatibility */
-
- rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */
- rr->args = r->args;
-
- /* Force sub_req to be treated as a CGI request, even if ordinary
- * typing rules would have called it something else.
- */
-
- rr->content_type = CGI_MAGIC_TYPE;
-
- /* Run it. */
-
- rr_status = ap_run_sub_req(rr);
- if (ap_is_HTTP_REDIRECT(rr_status)) {
- apr_ssize_t len_loc, h_wrt;
- const char *location = apr_table_get(rr->headers_out, "Location");
-
- location = ap_escape_html(rr->pool, location);
- len_loc = strlen(location);
-
- tmp_buck = ap_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
- tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
- tmp2_buck = ap_bucket_create_immortal("\">", sizeof("\">"));
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
- tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
- tmp2_buck = ap_bucket_create_immortal("</A>", sizeof("</A>"));
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-
- if (*inserted_head == NULL) {
- *inserted_head = tmp_buck;
- }
- }
-
- ap_destroy_sub_req(rr);
- ap_chdir_file(r->filename);
-
- return 0;
-}
-
/* ensure that path is relative, and does not contain ".." elements
* ensentially ensure that it does not match the regex:
* (^/|(^|/)\.\.(/|$))
return 1;
}
-static int handle_include(include_ctx_t *ctx, ap_bucket_brigade **bb, request_rec *r,
- ap_filter_t *f, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_include(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
char parsed_string[MAX_STRING_LEN];
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if (tag_val == NULL) {
if (tag == NULL) {
return (0);
request_rec *rr = NULL;
char *error_fmt = NULL;
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+ ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
if (tag[0] == 'f') {
/* be safe; only files in this directory or below allowed */
if (!is_only_below(parsed_string)) {
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);
-/*
- rr->output_filters = f->next;
-*/ if (ap_run_sub_req(rr)) {
+ SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+
+ if (ap_run_sub_req(rr)) {
error_fmt = "unable to include \"%s\" in parsed file %s";
}
}
- ap_chdir_file(r->filename);
if (error_fmt) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
0, r, error_fmt, tag_val, r->filename);
/* 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);
}
return 0;
}
-typedef struct {
-#ifdef TPF
- TPF_FORK_CHILD t;
-#endif
- request_rec *r;
- char *s;
-} include_cmd_arg;
-
-
-
-static apr_status_t build_argv_list(char ***argv, request_rec *r, apr_pool_t *p)
-{
- int numwords, x, idx;
- char *w;
- const char *args = r->args;
-
- if (!args || !args[0] || ap_strchr_c(args, '=')) {
- numwords = 1;
- }
- else {
- /* count the number of keywords */
- for (x = 0, numwords = 1; args[x]; x++) {
- if (args[x] == '+') {
- ++numwords;
- }
- }
- }
- /* Everything is - 1 to account for the first parameter which is the
- * program name. We didn't used to have to do this, but APR wants it.
- */
- if (numwords > APACHE_ARG_MAX - 1) {
- numwords = APACHE_ARG_MAX - 1; /* Truncate args to prevent overrun */
- }
- *argv = (char **) apr_palloc(p, (numwords + 2) * sizeof(char *));
-
- for (x = 1, idx = 1; x < numwords; x++) {
- w = ap_getword_nulls(p, &args, '+');
- ap_unescape_url(w);
- (*argv)[idx++] = ap_escape_shell_cmd(p, w);
- }
- (*argv)[idx] = NULL;
-
- return APR_SUCCESS;
-}
-
-
-
-static int include_cmd(include_ctx_t *ctx, ap_bucket_brigade **bb, char *s,
- request_rec *r, ap_filter_t *f)
-{
- include_cmd_arg arg;
- apr_procattr_t *procattr;
- apr_proc_t *procnew;
- apr_status_t rc;
- apr_table_t *env = r->subprocess_env;
- char **argv;
- apr_file_t *file = NULL;
-#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \
- defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
- core_dir_config *conf;
- conf = (core_dir_config *) ap_get_module_config(r->per_dir_config,
- &core_module);
-#endif
-
- arg.r = r;
- arg.s = s;
-#ifdef TPF
- arg.t.filename = r->filename;
- arg.t.subprocess_env = r->subprocess_env;
- arg.t.prog_type = FORK_FILE;
-#endif
-
- if (r->path_info && r->path_info[0] != '\0') {
- request_rec *pa_req;
-
- apr_table_setn(env, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
-
- pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, f->next);
- if (pa_req->filename) {
- apr_table_setn(env, "PATH_TRANSLATED",
- apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info,
- NULL));
- }
- }
-
- if (r->args) {
- char *arg_copy = apr_pstrdup(r->pool, r->args);
-
- apr_table_setn(env, "QUERY_STRING", r->args);
- ap_unescape_url(arg_copy);
- apr_table_setn(env, "QUERY_STRING_UNESCAPED",
- ap_escape_shell_cmd(r->pool, arg_copy));
- }
-
- if ((apr_createprocattr_init(&procattr, r->pool) != APR_SUCCESS) ||
- (apr_setprocattr_io(procattr, APR_NO_PIPE,
- APR_FULL_BLOCK, APR_NO_PIPE) != APR_SUCCESS) ||
- (apr_setprocattr_dir(procattr, ap_make_dirstr_parent(r->pool, r->filename)) != APR_SUCCESS) ||
-#ifdef RLIMIT_CPU
- ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) ||
-#endif
-#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
- ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) ||
-#endif
-#ifdef RLIMIT_NPROC
- ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) ||
-#endif
- (apr_setprocattr_cmdtype(procattr, APR_SHELLCMD) != APR_SUCCESS)) {
- /* Something bad happened, tell the world. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
- "couldn't initialize proc attributes: %s %s", r->filename, s);
- rc = !APR_SUCCESS;
- }
- else {
- SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
- build_argv_list(&argv, r, r->pool);
- argv[0] = apr_pstrdup(r->pool, s);
- procnew = apr_pcalloc(r->pool, sizeof(*procnew));
- rc = apr_create_process(procnew, s, argv, ap_create_environment(r->pool, env), procattr, r->pool);
-
- if (rc != APR_SUCCESS) {
- /* Bad things happened. Everyone should have cleaned up. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
- "couldn't create child process: %d: %s", rc, s);
- }
- else {
- ap_bucket_brigade *bcgi;
- ap_bucket *b;
-
- apr_note_subprocess(r->pool, procnew, kill_after_timeout);
- /* Fill in BUFF structure for parents pipe to child's stdout */
- file = procnew->out;
- if (!file)
- return APR_EBADF;
- bcgi = ap_brigade_create(r->pool);
- b = ap_bucket_create_pipe(file);
- AP_BRIGADE_INSERT_TAIL(bcgi, b);
- ap_pass_brigade(f->next, bcgi);
-
- /* We can't close the pipe here, because we may return before the
- * full CGI has been sent to the network. That's okay though,
- * because we can rely on the pool to close the pipe for us.
- */
- }
- }
-
- return 0;
-}
-
-static int handle_exec(include_ctx_t *ctx, ap_bucket_brigade **bb, request_rec *r,
- ap_filter_t *f, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
-{
- char *tag = NULL;
- char *tag_val = NULL;
- char *file = r->filename;
- ap_bucket *tmp_buck;
- char parsed_string[MAX_STRING_LEN];
- *inserted_head = NULL;
- if (ctx->flags & FLAG_PRINTING) {
- if (ctx->flags & FLAG_NO_EXEC) {
- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
- "exec used but not allowed in %s", r->filename);
- CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
- }
- else {
- while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
- if (tag_val == NULL) {
- if (tag == NULL) {
- return (0);
- }
- else {
- return 1;
- }
- }
- if (!strcmp(tag, "cmd")) {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 1);
- if (include_cmd(ctx, bb, parsed_string, r, f) == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
- "execution failure for parameter \"%s\" "
- "to tag exec in file %s", tag, r->filename);
- CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
- }
- /* just in case some stooge changed directories */
- ap_chdir_file(r->filename);
- }
- else if (!strcmp(tag, "cgi")) {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
- SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
- if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) {
- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
- "invalid CGI ref \"%s\" in %s", tag_val, file);
- CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
- }
- ap_chdir_file(r->filename);
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
- "unknown parameter \"%s\" to tag exec in %s", tag, file);
- CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
- }
- }
- }
- }
- return 0;
-}
-
-static int handle_echo(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_echo(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
const char *echo_text = NULL;
- ap_bucket *tmp_buck;
- apr_ssize_t e_len, e_wrt;
+ apr_bucket *tmp_buck;
+ apr_size_t e_len, e_wrt;
enum {E_NONE, E_URL, E_ENTITY} encode;
encode = E_ENTITY;
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if (tag_val == NULL) {
if (tag != NULL) {
return 1;
}
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 = ap_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 = ap_bucket_create_immortal("(none)", sizeof("none"));
+ tmp_buck = apr_bucket_immortal_create("(none)", sizeof("(none)")-1);
}
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
if (*inserted_head == NULL) {
*inserted_head = tmp_buck;
}
return 0;
}
-#ifdef USE_PERL_SSI
-static int handle_perl(include_ctx_t *ctx, request_rec *r)
-{
- char *tag = NULL;
- char *tag_val = NULL;
- char parsed_string[MAX_STRING_LEN];
- SV *sub = Nullsv;
- AV *av = newAV();
-
- if (ctx->flags & FLAG_PRINTING) {
- if (ctx->flags & FLAG_NO_EXEC) {
- ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
- "#perl SSI disallowed by IncludesNoExec in %s",
- r->filename);
- return (DECLINED);
- }
-
- while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
- if (tag_val == NULL) {
- break;
- }
- if (strnEQ(tag, "sub", 3)) {
- sub = newSVpv(tag_val, 0);
- }
- else if (strnEQ(tag, "arg", 3)) {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
- av_push(av, newSVpv(parsed_string, 0));
- }
- }
-
- perl_stdout2client(r);
- perl_setup_env(r);
- perl_call_handler(sub, r, av);
- }
-
- return (OK);
-}
-#endif
-
/* error and tf must point to a string with room for at
* least MAX_STRING_LEN characters
*/
-static int handle_config(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_config(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 0);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
if (tag_val == NULL) {
if (tag == NULL) {
return 0; /* Reached the end of the string. */
}
}
if (!strcmp(tag, "errmsg")) {
- parse_string(r, tag_val, ctx->error_str, MAX_STRING_LEN, 0);
+ ap_ssi_parse_string(r, tag_val, ctx->error_str, MAX_STRING_LEN, 0);
ctx->error_length = strlen(ctx->error_str);
}
else if (!strcmp(tag, "timefmt")) {
apr_time_t date = r->request_time;
- parse_string(r, tag_val, ctx->time_str, MAX_STRING_LEN, 0);
+ ap_ssi_parse_string(r, tag_val, ctx->time_str, MAX_STRING_LEN, 0);
apr_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, ctx->time_str, 0));
apr_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, ctx->time_str, 1));
apr_table_setn(env, "LAST_MODIFIED",
ap_ht_time(r->pool, r->finfo.mtime, ctx->time_str, 0));
}
else if (!strcmp(tag, "sizefmt")) {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+ ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
decodehtml(parsed_string);
if (!strcmp(parsed_string, "bytes")) {
ctx->flags |= FLAG_SIZE_IN_BYTES;
}
}
else {
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
"unknown parameter \"%s\" to tag config in %s",
request_rec *rr = NULL;
int ret=0;
char *error_fmt = NULL;
+ apr_status_t rv = APR_SUCCESS;
if (!strcmp(tag, "file")) {
/* be safe; only files in this directory or below allowed */
}
else {
ap_getparents(tag_val); /* get rid of any nasties */
+
+ /* note: it is okay to pass NULL for the "next filter" since
+ we never attempt to "run" this sub request. */
rr = ap_sub_req_lookup_file(tag_val, r, NULL);
- if (rr->status == HTTP_OK && rr->finfo.protection != 0) {
+ if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
to_send = rr->filename;
- if (apr_stat(finfo, to_send, rr->pool) != APR_SUCCESS) {
+ if ((rv = apr_stat(finfo, to_send, APR_FINFO_GPROT
+ | APR_FINFO_MIN, rr->pool)) != APR_SUCCESS
+ && rv != APR_INCOMPLETE) {
error_fmt = "unable to get information about \"%s\" "
"in parsed file %s";
}
if (error_fmt) {
ret = -1;
- /* TODO: pass APLOG_NOERRNO if no apr_stat() failure; pass rv from apr_stat()
- * otherwise
- */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error_fmt, to_send, r->filename);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR | (rv ? 0 : APLOG_NOERRNO),
+ rv, r, error_fmt, to_send, r->filename);
}
if (rr) ap_destroy_sub_req(rr);
return ret;
}
else if (!strcmp(tag, "virtual")) {
+ /* note: it is okay to pass NULL for the "next filter" since
+ we never attempt to "run" this sub request. */
rr = ap_sub_req_lookup_uri(tag_val, r, NULL);
- if (rr->status == HTTP_OK && rr->finfo.protection != 0) {
+ if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
memcpy((char *) finfo, (const char *) &rr->finfo,
sizeof(rr->finfo));
ap_destroy_sub_req(rr);
}
}
-#define NEG_SIGN " -"
-#define ZERO_K " 0k"
-#define ONE_K " 1k"
-
-static void generate_size(apr_ssize_t size, char *buff, apr_ssize_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, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+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 *tag = NULL;
char *tag_val = NULL;
apr_finfo_t finfo;
- apr_ssize_t s_len, s_wrt;
- ap_bucket *tmp_buck;
+ apr_size_t s_len, s_wrt;
+ apr_bucket *tmp_buck;
char parsed_string[MAX_STRING_LEN];
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if (tag_val == NULL) {
if (tag == NULL) {
return 0;
}
}
else {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+ ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
if (!find_file(r, "fsize", tag, parsed_string, &finfo)) {
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 = ap_bucket_create_heap(buff, s_len, 1, &s_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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;
}
return 0;
}
-static int handle_flastmod(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_flastmod(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
apr_finfo_t finfo;
- apr_ssize_t t_len, t_wrt;
- ap_bucket *tmp_buck;
+ apr_size_t t_len, t_wrt;
+ apr_bucket *tmp_buck;
char parsed_string[MAX_STRING_LEN];
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if (tag_val == NULL) {
if (tag == NULL) {
return 0;
}
}
else {
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+ ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
if (!find_file(r, "flastmod", tag, parsed_string, &finfo)) {
char *t_val;
t_val = ap_ht_time(r->pool, finfo.mtime, ctx->time_str, 0);
t_len = strlen(t_val);
- tmp_buck = ap_bucket_create_heap(t_val, t_len, 1, &t_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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;
}
char buffer[MAX_STRING_LEN];
apr_pool_t *expr_pool;
int retval = 0;
- apr_ssize_t debug_pos = 0;
+ apr_size_t debug_pos = 0;
debug[debug_pos] = '\0';
*was_error = 0;
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 */
sizeof (" Evaluate string\n"));
debug_pos += sizeof (" Evaluate string\n");
#endif
- parse_string(r, current->token.value, buffer, sizeof(buffer), 0);
+ ap_ssi_parse_string(r, current->token.value, buffer, sizeof(buffer), 0);
apr_cpystrn(current->token.value, buffer, sizeof(current->token.value));
current->value = (current->token.value[0] != '\0');
current->done = 1;
if (!current->left->done) {
switch (current->left->token.type) {
case token_string:
- parse_string(r, current->left->token.value,
+ ap_ssi_parse_string(r, current->left->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->left->token.value, buffer,
sizeof(current->left->token.value));
if (!current->right->done) {
switch (current->right->token.type) {
case token_string:
- parse_string(r, current->right->token.value,
+ ap_ssi_parse_string(r, current->right->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->right->token.value, buffer,
sizeof(current->right->token.value));
}
#ifdef DEBUG_INCLUDE
debug_pos += sprintf (&debug[debug_pos], " Left: %c\n",
- current->left->value ? "1" : "0");
+ current->left->value ? '1' : '0');
debug_pos += sprintf (&debug[debug_pos], " Right: %c\n",
current->right->value ? '1' : '0');
#endif
*was_error = 1;
goto RETURN;
}
- parse_string(r, current->left->token.value,
+ ap_ssi_parse_string(r, current->left->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->left->token.value, buffer,
sizeof(current->left->token.value));
- parse_string(r, current->right->token.value,
+ ap_ssi_parse_string(r, current->right->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->right->token.value, buffer,
sizeof(current->right->token.value));
*was_error = 1;
goto RETURN;
}
- parse_string(r, current->left->token.value,
+ ap_ssi_parse_string(r, current->left->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->left->token.value, buffer,
sizeof(current->left->token.value));
- parse_string(r, current->right->token.value,
+ ap_ssi_parse_string(r, current->right->token.value,
buffer, sizeof(buffer), 0);
apr_cpystrn(current->right->token.value, buffer,
sizeof(current->right->token.value));
retval = (root == (struct parse_node *) NULL) ? 0 : root->value;
RETURN:
- apr_destroy_pool(expr_pool);
+ apr_pool_destroy(expr_pool);
return (retval);
}
/*-------------------------------------------------------------------------*/
#ifdef DEBUG_INCLUDE
+/* XXX overlaying the static string pointed to by cond_txt isn't cool */
+
#define MAX_DEBUG_SIZE MAX_STRING_LEN
#define LOG_COND_STATUS(cntx, t_buck, h_ptr, ins_head, tag_text) \
{ \
char *cond_txt = "**** X conditional_status=\"0\"\n"; \
- apr_ssize_t c_wrt; \
+ apr_size_t c_wrt; \
\
if (cntx->flags & FLAG_COND_TRUE) { \
- cont_txt[31] = '1'; \
+ cond_txt[31] = '1'; \
} \
memcpy(&cond_txt[5], tag_text, sizeof(tag_text)); \
- t_buck = ap_bucket_create_heap(cond_txt, sizeof(cond_txt), 1, &c_wrt); \
- AP_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \
+ 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) { \
ins_head = t_buck; \
}
#define DUMP_PARSE_EXPR_DEBUG(t_buck, h_ptr, d_buf, ins_head) \
{ \
- apr_ssize_t b_wrt; \
+ apr_size_t b_wrt; \
if (d_buf[0] != '\0') { \
- t_buck = ap_bucket_create_heap(d_buf, strlen(d_buf), 1, &b_wrt); \
- AP_BUCKET_INSERT_BEFORE(h_ptr, t_buck); \
+ 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) { \
ins_head = t_buck; \
/*-------------------------------------------------------------------------*/
/* pjr - These seem to allow expr="fred" expr="joe" where joe overwrites fred. */
-static int handle_if(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_if(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
char *expr = NULL;
int expr_ret, was_error, was_unmatched;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
char debug_buf[MAX_DEBUG_SIZE];
*inserted_head = NULL;
}
else {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 0);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
if (tag == NULL) {
if (expr == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
expr = tag_val;
#ifdef DEBUG_INCLUDE
if (1) {
- apr_ssize_t d_len = 0, d_wrt = 0;
+ apr_size_t d_len = 0, d_wrt = 0;
d_len = sprintf(debug_buf, "**** if expr=\"%s\"\n", expr);
- tmp_buck = ap_bucket_create_heap(debug_buf, d_len, 1, &d_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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) {
*inserted_head = tmp_buck;
return 0;
}
-static int handle_elif(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_elif(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
char *expr = NULL;
int expr_ret, was_error, was_unmatched;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
char debug_buf[MAX_DEBUG_SIZE];
*inserted_head = NULL;
if (!ctx->if_nesting_level) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 0);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
if (tag == '\0') {
LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " elif");
expr = tag_val;
#ifdef DEBUG_INCLUDE
if (1) {
- apr_ssize_t d_len = 0, d_wrt = 0;
+ apr_size_t d_len = 0, d_wrt = 0;
d_len = sprintf(debug_buf, "**** elif expr=\"%s\"\n", expr);
- tmp_buck = ap_bucket_create_heap(debug_buf, d_len, 1, &d_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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) {
*inserted_head = tmp_buck;
return 0;
}
-static int handle_else(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_else(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
*inserted_head = NULL;
if (!ctx->if_nesting_level) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if ((tag != NULL) || (tag_val != NULL)) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
"else directive does not take tags in %s", r->filename);
return 0;
}
-static int handle_endif(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_endif(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
*inserted_head = NULL;
if (!ctx->if_nesting_level) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if ((tag != NULL) || (tag_val != NULL)) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
"endif directive does not take tags in %s", r->filename);
}
}
-static int handle_set(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_set(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
char *var = NULL;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
char parsed_string[MAX_STRING_LEN];
*inserted_head = NULL;
if (ctx->flags & FLAG_PRINTING) {
while (1) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if ((tag == NULL) && (tag_val == NULL)) {
return 0;
}
CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
return (-1);
}
- parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+ ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
apr_table_setn(r->subprocess_env, apr_pstrdup(r->pool, var),
apr_pstrdup(r->pool, parsed_string));
}
return 0;
}
-static int handle_printenv(include_ctx_t *ctx, request_rec *r, ap_bucket *head_ptr,
- ap_bucket **inserted_head)
+static int handle_printenv(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+ ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
{
char *tag = NULL;
char *tag_val = NULL;
- ap_bucket *tmp_buck;
+ apr_bucket *tmp_buck;
if (ctx->flags & FLAG_PRINTING) {
- get_tag_and_value(ctx, &tag, &tag_val, 1);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
if ((tag == NULL) && (tag_val == NULL)) {
apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
int i;
char *key_text, *val_text;
- apr_ssize_t k_len, v_len, t_wrt;
+ apr_size_t k_len, v_len, t_wrt;
*inserted_head = NULL;
for (i = 0; i < arr->nelts; ++i) {
v_len = strlen(val_text);
/* Key_text */
- tmp_buck = ap_bucket_create_heap(key_text, k_len, 1, &t_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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 = ap_bucket_create_immortal("=", 1);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ tmp_buck = apr_bucket_immortal_create("=", 1);
+ APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
/* Value_text */
- tmp_buck = ap_bucket_create_heap(val_text, v_len, 1, &t_wrt);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ tmp_buck = apr_bucket_heap_create(val_text, v_len, 1, &t_wrt);
+ APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
/* newline... */
- tmp_buck = ap_bucket_create_immortal("\n", 1);
- AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+ 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(ap_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;
- ap_bucket *dptr = AP_BRIGADE_FIRST(*bb);
- ap_bucket *tmp_dptr;
- ap_bucket_brigade *tag_and_after;
+ apr_bucket *dptr = APR_BRIGADE_FIRST(*bb);
+ apr_bucket *tmp_dptr;
+ apr_bucket_brigade *tag_and_after;
int ret;
+ apr_status_t rv;
- ap_chdir_file(r->filename);
if (r->args) { /* add QUERY stuff to env cause it ain't yet */
char *arg_copy = apr_pstrdup(r->pool, r->args);
ap_escape_shell_cmd(r->pool, arg_copy));
}
- while (dptr != AP_BRIGADE_SENTINEL(*bb)) {
+ while (dptr != APR_BRIGADE_SENTINEL(*bb)) {
/* State to check for the STARTING_SEQUENCE. */
if ((ctx->state == PRE_HEAD) || (ctx->state == PARSE_HEAD)) {
int do_cleanup = 0;
- apr_ssize_t cleanup_bytes = ctx->parse_pos;
+ apr_size_t cleanup_bytes = ctx->parse_pos;
tmp_dptr = find_start_sequence(dptr, ctx, *bb, &do_cleanup);
* be a tag after all. This can only happen if the starting
* tag actually spans brigades. This should be very rare.
*/
- if ((do_cleanup) && (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade))) {
- ap_bucket *tmp_bkt;
+ if ((do_cleanup) && (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade))) {
+ apr_bucket *tmp_bkt;
- tmp_bkt = ap_bucket_create_immortal(STARTING_SEQUENCE, cleanup_bytes);
- AP_BRIGADE_INSERT_HEAD(*bb, tmp_bkt);
-
- while (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = AP_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
- }
+ tmp_bkt = apr_bucket_immortal_create(STARTING_SEQUENCE,
+ cleanup_bytes);
+ APR_BRIGADE_INSERT_HEAD(*bb, tmp_bkt);
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
/* If I am inside a conditional (if, elif, else) that is false
* then I need to throw away anything contained in it.
*/
if ((!(ctx->flags & FLAG_PRINTING)) && (tmp_dptr != NULL) &&
- (dptr != AP_BRIGADE_SENTINEL(*bb))) {
- while ((dptr != AP_BRIGADE_SENTINEL(*bb)) &&
+ (dptr != APR_BRIGADE_SENTINEL(*bb))) {
+ while ((dptr != APR_BRIGADE_SENTINEL(*bb)) &&
(dptr != tmp_dptr)) {
- ap_bucket *free_bucket = dptr;
+ apr_bucket *free_bucket = dptr;
- dptr = AP_BUCKET_NEXT (dptr);
- AP_BUCKET_REMOVE(free_bucket);
- ap_bucket_destroy(free_bucket);
+ dptr = APR_BUCKET_NEXT (dptr);
+ apr_bucket_delete(free_bucket);
}
}
/* Adjust the current bucket position based on what was found... */
- if ((tmp_dptr != NULL) && (ctx->state == PARSE_TAG)) {
+ if ((tmp_dptr != NULL) && (ctx->state == PARSE_DIRECTIVE)) {
if (ctx->tag_start_bucket != NULL) {
dptr = ctx->tag_start_bucket;
}
else {
- dptr = AP_BRIGADE_SENTINEL(*bb);
+ 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 = AP_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
+ dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
}
}
/* State to check for the ENDING_SEQUENCE. */
- if (((ctx->state == PARSE_TAG) || (ctx->state == PARSE_TAIL)) &&
- (dptr != AP_BRIGADE_SENTINEL(*bb))) {
+ if (((ctx->state == PARSE_DIRECTIVE) ||
+ (ctx->state == PARSE_TAG) ||
+ (ctx->state == PARSE_TAIL)) &&
+ (dptr != APR_BRIGADE_SENTINEL(*bb))) {
tmp_dptr = find_end_sequence(dptr, ctx, *bb);
if (tmp_dptr != NULL) {
* In any event after this the entire set of tag buckets will be
* in one place or another.
*/
- if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tag_and_after = ap_brigade_split(*bb, dptr);
- AP_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
+ if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+ tag_and_after = apr_brigade_split(*bb, dptr);
+ 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 = AP_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
+ dptr = APR_BRIGADE_SENTINEL(*bb); /* remainder of this brigade... */
}
}
/* State to processed the directive... */
if (ctx->state == PARSED) {
- ap_bucket *content_head = NULL, *tmp_bkt;
+ apr_bucket *content_head = NULL, *tmp_bkt;
+ apr_size_t tmp_i;
char tmp_buf[TMP_BUF_SIZE];
- char *directive_str = NULL;
- dir_token_id directive_token;
+ int (*handle_func)(include_ctx_t *, apr_bucket_brigade **, request_rec *,
+ ap_filter_t *, apr_bucket *, apr_bucket **);
/* By now the full tag (all buckets) should either be set aside into
* ssi_tag_brigade or contained within the current bb. All tag
/* DO CLEANUP HERE!!!!! */
tmp_dptr = ctx->head_start_bucket;
- if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = AP_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
- }
+ if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
else {
do {
tmp_bkt = tmp_dptr;
- tmp_dptr = AP_BUCKET_NEXT (tmp_dptr);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
+ tmp_dptr = APR_BUCKET_NEXT (tmp_dptr);
+ apr_bucket_delete(tmp_bkt);
} while ((tmp_dptr != dptr) &&
- (tmp_dptr != AP_BRIGADE_SENTINEL(*bb)));
+ (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!
*/
- directive_str = get_directive(ctx, &directive_token);
- switch (directive_token) {
- case TOK_IF:
- ret = handle_if(ctx, r, dptr, &content_head);
- break;
- case TOK_ELSE:
- ret = handle_else(ctx, r, dptr, &content_head);
- break;
- case TOK_ELIF:
- ret = handle_elif(ctx, r, dptr, &content_head);
- break;
- case TOK_ENDIF:
- ret = handle_endif(ctx, r, dptr, &content_head);
- break;
- case TOK_EXEC:
- ret = handle_exec(ctx, bb, r, f, dptr, &content_head);
- break;
- case TOK_INCLUDE:
- ret = handle_include(ctx, bb, r, f, dptr, &content_head);
- break;
-#ifdef USE_PERL_SSI /* Leaving this as is for now... */
- case TOK_PERL:
- SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
- ret = handle_perl(ctx, r);
- break;
-#endif
- case TOK_SET:
- ret = handle_set(ctx, r, dptr, &content_head);
- break;
- case TOK_ECHO:
- ret = handle_echo(ctx, r, dptr, &content_head);
- break;
- case TOK_FSIZE:
- ret = handle_fsize(ctx, r, dptr, &content_head);
- break;
- case TOK_CONFIG:
- ret = handle_config(ctx, r, dptr, &content_head);
- break;
- case TOK_FLASTMOD:
- ret = handle_flastmod(ctx, r, dptr, &content_head);
- break;
- case TOK_PRINTENV:
- ret = handle_printenv(ctx, r, dptr, &content_head);
- break;
+ /* Retrieve the handler function to be called for this directive from the
+ * functions registered in the hash table.
+ * Need to lower case the directive for proper matching. Also need to have
+ * it NULL terminated (and include the NULL in the length) for proper
+ * hash matching.
+ */
+ for (tmp_i = 0; tmp_i < ctx->directive_length; tmp_i++) {
+ ctx->combined_tag[tmp_i] = apr_tolower(ctx->combined_tag[tmp_i]);
+ }
+ ctx->combined_tag[ctx->directive_length] = '\0';
+ ctx->curr_tag_pos = &ctx->combined_tag[ctx->directive_length+1];
- case TOK_UNKNOWN:
- default:
+ handle_func =
+ (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);
+ }
+ else {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
"unknown directive \"%s\" in parsed doc %s",
- directive_str, r->filename);
+ ctx->combined_tag, r->filename);
CREATE_ERROR_BUCKET(ctx, tmp_bkt, dptr, content_head);
}
content_head = dptr;
}
tmp_dptr = ctx->head_start_bucket;
- if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = AP_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
- }
+ if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
else {
do {
tmp_bkt = tmp_dptr;
- tmp_dptr = AP_BUCKET_NEXT (tmp_dptr);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
+ tmp_dptr = APR_BUCKET_NEXT (tmp_dptr);
+ apr_bucket_delete(tmp_bkt);
} while ((tmp_dptr != content_head) &&
- (tmp_dptr != AP_BRIGADE_SENTINEL(*bb)));
+ (tmp_dptr != APR_BRIGADE_SENTINEL(*bb)));
}
if (ctx->combined_tag == tmp_buf) {
memset (ctx->combined_tag, '\0', ctx->tag_length);
ctx->tail_start_index = 0;
ctx->curr_tag_pos = NULL;
ctx->tag_length = 0;
+ ctx->directive_length = 0;
- if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- while (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- tmp_bkt = AP_BRIGADE_FIRST(ctx->ssi_tag_brigade);
- AP_BUCKET_REMOVE(tmp_bkt);
- ap_bucket_destroy(tmp_bkt);
- }
+ if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+ apr_brigade_cleanup(ctx->ssi_tag_brigade);
}
ctx->state = PRE_HEAD;
*/
if (ctx->state == PRE_HEAD) {
/* Inside a false conditional (if, elif, else), so toss it all... */
- if ((dptr != AP_BRIGADE_SENTINEL(*bb)) &&
+ if ((dptr != APR_BRIGADE_SENTINEL(*bb)) &&
(!(ctx->flags & FLAG_PRINTING))) {
- ap_bucket *free_bucket;
+ apr_bucket *free_bucket;
do {
free_bucket = dptr;
- dptr = AP_BUCKET_NEXT (dptr);
- AP_BUCKET_REMOVE(free_bucket);
- ap_bucket_destroy(free_bucket);
- } while (dptr != AP_BRIGADE_SENTINEL(*bb));
+ dptr = APR_BUCKET_NEXT (dptr);
+ 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... */
- ap_bucket *content_head, *tmp_bkt;
+ apr_bucket *content_head = NULL, *tmp_bkt;
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
"Invalid mod_include state during file %s", r->filename);
- CREATE_ERROR_BUCKET(ctx, tmp_bkt, AP_BRIGADE_FIRST(*bb), content_head);
+ CREATE_ERROR_BUCKET(ctx, tmp_bkt, APR_BRIGADE_FIRST(*bb), content_head);
}
else { /* Entire brigade is middle chunk of SSI tag... */
- if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
- AP_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
+ if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+ APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
}
else { /* End of brigade contains part of SSI tag... */
if (ctx->head_start_index > 0) {
- ap_bucket_split(ctx->head_start_bucket, ctx->head_start_index);
- ctx->head_start_bucket = AP_BUCKET_NEXT(ctx->head_start_bucket);
+ apr_bucket_split(ctx->head_start_bucket, ctx->head_start_index);
+ ctx->head_start_bucket = APR_BUCKET_NEXT(ctx->head_start_bucket);
ctx->head_start_index = 0;
}
/* Set aside tag, pass pre-tag... */
- tag_and_after = ap_brigade_split(*bb, ctx->head_start_bucket);
- ap_save_brigade(f, &ctx->ssi_tag_brigade, &tag_and_after);
- ap_pass_brigade(f->next, *bb);
+ tag_and_after = apr_brigade_split(*bb, ctx->head_start_bucket);
+ 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, ap_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);
}
if (ap_allow_options(r) & OPT_INCNOEXEC) {
ctx->flags |= FLAG_NO_EXEC;
}
- ctx->ssi_tag_brigade = ap_brigade_create(f->c->pool);
+ 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;
+ }
- if ((*state == xbithack_full)
-#if !defined(OS2) && !defined(WIN32)
- /* OS/2 dosen't support Groups. */
- && (r->finfo.protection & APR_GEXECUTE)
-#endif
- ) {
+ /* Assure the platform supports Group protections */
+ 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_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_hash_make(p);
+
+ ssi_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
+
+ if(ssi_pfn_register) {
+ ssi_pfn_register("if", handle_if);
+ ssi_pfn_register("set", handle_set);
+ ssi_pfn_register("else", handle_else);
+ ssi_pfn_register("elif", handle_elif);
+ ssi_pfn_register("echo", handle_echo);
+ ssi_pfn_register("endif", handle_endif);
+ ssi_pfn_register("fsize", handle_fsize);
+ ssi_pfn_register("config", handle_config);
+ ssi_pfn_register("include", handle_include);
+ ssi_pfn_register("flastmod", handle_flastmod);
+ ssi_pfn_register("printenv", handle_printenv);
+ }
+}
+
+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...
+ */
static const command_rec includes_cmds[] =
{
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 void register_hooks(void)
+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 */
NULL, /* server config */
NULL, /* merge server config */
includes_cmds, /* command apr_table_t */
- NULL, /* handlers */
register_hooks /* register hooks */
};