📄 mod_include.c
字号:
/* 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.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#define APR_WANT_MEMFUNC#include "apr_want.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 "http_log.h"#include "http_main.h"#include "util_script.h"#include "http_core.h"#include "mod_include.h"/* helper for Latin1 <-> entity encoding */#if APR_CHARSET_EBCDIC#include "util_ebcdic.h"#define RAW_ASCII_CHAR(ch) apr_xlate_conv_byte(ap_hdrs_from_ascii, \ (unsigned char)ch)#else /* APR_CHARSET_EBCDIC */#define RAW_ASCII_CHAR(ch) (ch)#endif /* !APR_CHARSET_EBCDIC *//* * +-------------------------------------------------------+ * | | * | Types and Structures * | | * +-------------------------------------------------------+ *//* sll used for string expansion */typedef struct result_item { struct result_item *next; apr_size_t len; const char *string;} result_item_t;/* conditional expression parser stuff */typedef enum { TOKEN_STRING, TOKEN_RE, TOKEN_AND, TOKEN_OR, TOKEN_NOT, TOKEN_EQ, TOKEN_NE, TOKEN_RBRACE, TOKEN_LBRACE, TOKEN_GROUP, TOKEN_GE, TOKEN_LE, TOKEN_GT, TOKEN_LT, TOKEN_ACCESS} token_type_t;typedef struct { token_type_t type; const char *value;#ifdef DEBUG_INCLUDE const char *s;#endif} token_t;typedef struct parse_node { struct parse_node *parent; struct parse_node *left; struct parse_node *right; token_t token; int value; int done;#ifdef DEBUG_INCLUDE int dump_done;#endif} parse_node_t;typedef enum { XBITHACK_OFF, XBITHACK_ON, XBITHACK_FULL} xbithack_t;typedef struct { const char *default_error_msg; const char *default_time_fmt; const char *undefined_echo; xbithack_t xbithack; const int accessenable;} include_dir_config;typedef struct { const char *default_start_tag; const char *default_end_tag;} include_server_config;/* main parser states */typedef enum { PARSE_PRE_HEAD, PARSE_HEAD, PARSE_DIRECTIVE, PARSE_DIRECTIVE_POSTNAME, PARSE_DIRECTIVE_TAIL, PARSE_DIRECTIVE_POSTTAIL, PARSE_PRE_ARG, PARSE_ARG, PARSE_ARG_NAME, PARSE_ARG_POSTNAME, PARSE_ARG_EQ, PARSE_ARG_PREVAL, PARSE_ARG_VAL, PARSE_ARG_VAL_ESC, PARSE_ARG_POSTVAL, PARSE_TAIL, PARSE_TAIL_SEQ, PARSE_EXECUTE} parse_state_t;typedef struct arg_item { struct arg_item *next; char *name; apr_size_t name_len; char *value; apr_size_t value_len;} arg_item_t;typedef struct { const char *source; const char *rexp; apr_size_t nsub; ap_regmatch_t match[AP_MAX_REG_MATCH];} backref_t;typedef struct { unsigned int T[256]; unsigned int x; apr_size_t pattern_len;} bndm_t;struct ssi_internal_ctx { parse_state_t state; int seen_eos; int error; char quote; /* quote character value (or \0) */ apr_size_t parse_pos; /* parse position of partial matches */ apr_size_t bytes_read; apr_bucket_brigade *tmp_bb; request_rec *r; const char *start_seq; bndm_t *start_seq_pat; const char *end_seq; apr_size_t end_seq_len; char *directive; /* name of the current directive */ apr_size_t directive_len; /* length of the current directive name */ arg_item_t *current_arg; /* currently parsed argument */ arg_item_t *argv; /* all arguments */ backref_t *re; /* NULL if there wasn't a regex yet */ const char *undefined_echo; apr_size_t undefined_echo_len; int accessenable; /* is using the access tests allowed? */#ifdef DEBUG_INCLUDE struct { ap_filter_t *f; apr_bucket_brigade *bb; } debug;#endif};/* * +-------------------------------------------------------+ * | | * | Debugging Utilities * | | * +-------------------------------------------------------+ */#ifdef DEBUG_INCLUDE#define TYPE_TOKEN(token, ttype) do { \ (token)->type = ttype; \ (token)->s = #ttype; \} while(0)#define CREATE_NODE(ctx, name) do { \ (name) = apr_palloc((ctx)->dpool, sizeof(*(name))); \ (name)->parent = (name)->left = (name)->right = NULL; \ (name)->done = 0; \ (name)->dump_done = 0; \} while(0)static void debug_printf(include_ctx_t *ctx, const char *fmt, ...){ va_list ap; char *debug__str; va_start(ap, fmt); debug__str = apr_pvsprintf(ctx->pool, fmt, ap); va_end(ap); APR_BRIGADE_INSERT_TAIL(ctx->intern->debug.bb, apr_bucket_pool_create( debug__str, strlen(debug__str), ctx->pool, ctx->intern->debug.f->c->bucket_alloc));}#define DUMP__CHILD(ctx, is, node, child) if (1) { \ parse_node_t *d__c = node->child; \ if (d__c) { \ if (!d__c->dump_done) { \ if (d__c->parent != node) { \ debug_printf(ctx, "!!! Parse tree is not consistent !!!\n"); \ if (!d__c->parent) { \ debug_printf(ctx, "Parent of " #child " child node is " \ "NULL.\n"); \ } \ else { \ debug_printf(ctx, "Parent of " #child " child node " \ "points to another node (of type %s)!\n", \ d__c->parent->token.s); \ } \ return; \ } \ node = d__c; \ continue; \ } \ } \ else { \ debug_printf(ctx, "%s(missing)\n", is); \ } \}static void debug_dump_tree(include_ctx_t *ctx, parse_node_t *root){ parse_node_t *current; char *is; if (!root) { debug_printf(ctx, " -- Parse Tree empty --\n\n"); return; } debug_printf(ctx, " ----- Parse Tree -----\n"); current = root; is = " "; while (current) { switch (current->token.type) { case TOKEN_STRING: case TOKEN_RE: debug_printf(ctx, "%s%s (%s)\n", is, current->token.s, current->token.value); current->dump_done = 1; current = current->parent; continue; case TOKEN_NOT: case TOKEN_GROUP: case TOKEN_RBRACE: case TOKEN_LBRACE: if (!current->dump_done) { debug_printf(ctx, "%s%s\n", is, current->token.s); is = apr_pstrcat(ctx->dpool, is, " ", NULL); current->dump_done = 1; } DUMP__CHILD(ctx, is, current, right) if (!current->right || current->right->dump_done) { is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4); if (current->right) current->right->dump_done = 0; current = current->parent; } continue; default: if (!current->dump_done) { debug_printf(ctx, "%s%s\n", is, current->token.s); is = apr_pstrcat(ctx->dpool, is, " ", NULL); current->dump_done = 1; } DUMP__CHILD(ctx, is, current, left) DUMP__CHILD(ctx, is, current, right) if ((!current->left || current->left->dump_done) && (!current->right || current->right->dump_done)) { is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4); if (current->left) current->left->dump_done = 0; if (current->right) current->right->dump_done = 0; current = current->parent; } continue; } } /* it is possible to call this function within the parser loop, to see * how the tree is built. That way, we must cleanup after us to dump * always the whole tree */ root->dump_done = 0; if (root->left) root->left->dump_done = 0; if (root->right) root->right->dump_done = 0; debug_printf(ctx, " --- End Parse Tree ---\n\n"); return;}#define DEBUG_INIT(ctx, filter, brigade) do { \ (ctx)->intern->debug.f = filter; \ (ctx)->intern->debug.bb = brigade; \} while(0)#define DEBUG_PRINTF(arg) debug_printf arg#define DEBUG_DUMP_TOKEN(ctx, token) do { \ token_t *d__t = (token); \ \ if (d__t->type == TOKEN_STRING || d__t->type == TOKEN_RE) { \ DEBUG_PRINTF(((ctx), " Found: %s (%s)\n", d__t->s, d__t->value)); \ } \ else { \ DEBUG_PRINTF((ctx, " Found: %s\n", d__t->s)); \ } \} while(0)#define DEBUG_DUMP_EVAL(ctx, node) do { \ char c = '"'; \ switch ((node)->token.type) { \ case TOKEN_STRING: \ debug_printf((ctx), " Evaluate: %s (%s) -> %c\n", (node)->token.s,\ (node)->token.value, ((node)->value) ? '1':'0'); \ break; \ case TOKEN_AND: \ case TOKEN_OR: \ debug_printf((ctx), " Evaluate: %s (Left: %s; Right: %s) -> %c\n",\ (node)->token.s, \ (((node)->left->done) ? ((node)->left->value ?"1":"0") \ : "short circuited"), \ (((node)->right->done) ? ((node)->right->value?"1":"0") \ : "short circuited"), \ (node)->value ? '1' : '0'); \ break; \ case TOKEN_EQ: \ case TOKEN_NE: \ case TOKEN_GT: \ case TOKEN_GE: \ case TOKEN_LT: \ case TOKEN_LE: \ if ((node)->right->token.type == TOKEN_RE) c = '/'; \ debug_printf((ctx), " Compare: %s (\"%s\" with %c%s%c) -> %c\n", \ (node)->token.s, \ (node)->left->token.value, \ c, (node)->right->token.value, c, \ (node)->value ? '1' : '0'); \ break; \ default: \ debug_printf((ctx), " Evaluate: %s -> %c\n", (node)->token.s, \ (node)->value ? '1' : '0'); \ break; \ } \} while(0)#define DEBUG_DUMP_UNMATCHED(ctx, unmatched) do { \ if (unmatched) { \ DEBUG_PRINTF(((ctx), " Unmatched %c\n", (char)(unmatched))); \ } \} while(0)#define DEBUG_DUMP_COND(ctx, text) \ DEBUG_PRINTF(((ctx), "**** %s cond status=\"%c\"\n", (text), \ ((ctx)->flags & SSI_FLAG_COND_TRUE) ? '1' : '0'))#define DEBUG_DUMP_TREE(ctx, root) debug_dump_tree(ctx, root)#else /* DEBUG_INCLUDE */#define TYPE_TOKEN(token, ttype) (token)->type = ttype
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -