apache_module.cpp
来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 435 行
CPP
435 行
///////////////////////////////////////////////////////////////////////////////
// $Header: /shorthand/src/apache_module.cpp 6 1/09/03 7:14p Arm $
//-----------------------------------------------------------------------------
// Project: ShortHand interpreter
// Author: Andrei Remenchuk <andrei@remenchuk.com>
//-----------------------------------------------------------------------------
// apache_module.cpp: implementations of Apache Module mod_shorthand
///////////////////////////////////////////////////////////////////////////////
#ifdef WIN32
#include <winsock2.h>
#include <stddef.h>
#endif
#include <stdlib.h>
#if HAVE_UNISTD_H && !defined(WIN32)
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <ctype.h>
/** apache includes */
#include "httpd.h"
#include "http_config.h"
#if MODULE_MAGIC_NUMBER > 19980712
# include "ap_compat.h"
#else
# if MODULE_MAGIC_NUMBER > 19980324
# include "compat.h"
# endif
#endif
#include "http_core.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "http_log.h"
#include "util_script.h"
/* shorthand includes */
#include "array.h"
#include "nodes.h"
#include "http.h"
#include "utils.h"
#include "module.h"
#include "version.h"
#include "regexx.h"
#undef putenv
/**
* Apache module HTTP stream.
*/
class ApacheHttpStream : public HttpStream
{
protected:
request_rec* m_req;
int m_chunk_number;
// inbound cookies
map<string*> m_in_cookies;
CHttpCookieJar m_out_cookies;
bool m_headers_sent;
bool m_did_client_block;
bool m_have_input;
bool m_cookies_grabbed;
int m_response_code;
string m_response_message;
public:
ApacheHttpStream(request_rec* req)
{
m_req = req;
m_headers_sent = false;
m_did_client_block = false;
m_have_input = false;
m_response_code = 0;
m_cookies_grabbed = false;
}
bool http_headers_sent()
{
return m_headers_sent;
}
/**
* Reads a piece of data sent by client in PUT or POST request.
*/
int http_read(void* buffer, int buffer_size)
{
int result;
if (!m_did_client_block)
{
m_did_client_block = true;
result = ap_setup_client_block(m_req, REQUEST_CHUNKED_DECHUNK);
if (result != OK)
{
m_have_input = false;
return 0;
}
result = ap_should_client_block(m_req);
if (result == 0)
{
m_have_input = false;
return 0;
}
m_have_input = true;
}
else if (!m_have_input)
{
return 0;
}
result = ap_get_client_block(m_req, (char*) buffer, buffer_size);
return result;
}
int code() const { return m_response_code; }
int http_add_header(const char* name, const char* value);
int http_send_headers();
int http_write_chunk(const void* chunk_data, unsigned int chunk_length);
void grab_cookies();
const char* http_get_cookie(const char* name);
int http_set_cookie(const CHttpCookie* cookie);
// overrides HTTP response code (with optional status line message)
// most servers will allow to change code, but few allow to change message
void http_set_response_code(int code, const char* msg)
{
m_response_code = code;
m_response_message = msg;
m_req->status = code;
}
int http_finalize()
{
if (!m_headers_sent)
{
http_send_headers();
}
return 0;
}
};
/*
* Declarations of routines to manipulate the module's configuration
* info. Note that these are returned, and passed in, as void *'s;
* the server core keeps track of them, but it doesn't, and can't,
* know their internal structure.
*/
static int send_parsed_shorthand(request_rec * r);
static int send_parsed_shorthand_source(request_rec * r);
int shorthand_xbithack_handler(request_rec * r);
void shorthand_init_handler(server_rec *s, pool *p);
int apache_shorthand_module_main(request_rec *r, FILE* f, int display_source_mode);
/* {{{ php_create_dir
*/
static void *shorthand_create_dir(pool *p, char *dummy)
{
/*
HashTable *per_dir_info;
per_dir_info = (HashTable *) malloc(sizeof(HashTable));
zend_hash_init(per_dir_info, 5, NULL, (void (*)(void *)) destroy_per_dir_entry, 1);
register_cleanup(p, (void *) per_dir_info, (void (*)(void *)) php_destroy_per_dir_info, (void (*)(void *)) zend_hash_destroy);
return per_dir_info;
*/
return NULL; // TODO
}
/* }}} */
/* {{{ php_merge_dir
*/
static void *shorthand_merge_dir(pool *p, void *basev, void *addv)
{
/* This function *must* return addv, and not modify basev */
//zend_hash_merge_ex((HashTable *) addv, (HashTable *) basev, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (zend_bool (*)(void *, void *)) should_overwrite_per_dir_entry);
//return addv;
return NULL;
}
/* }}} */
/* {{{ command_rec php_commands[]
*/
command_rec shorthand_commands[] =
{
//{"php_value", php_apache_value_handler, NULL, OR_OPTIONS, TAKE2, "PHP Value Modifier"},
//{"php_flag", php_apache_flag_handler, NULL, OR_OPTIONS, TAKE2, "PHP Flag Modifier"},
//{"php_admin_value", php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Value Modifier (Admin)"},
//{"php_admin_flag", php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Flag Modifier (Admin)"},
{NULL}
};
/* }}} */
/* {{{ handler_rec php_handlers[]
*/
handler_rec shorthand_handlers[] =
{
{"application/x-httpd-shorthand", send_parsed_shorthand},
{"application/x-httpd-shorthand-source", send_parsed_shorthand_source},
{"text/html", shorthand_xbithack_handler},
{NULL}
};
/* }}} */
module MODULE_VAR_EXPORT shorthand_module = {
STANDARD_MODULE_STUFF,
shorthand_init_handler, /* initializer */
shorthand_create_dir, /* dir config creator */
shorthand_merge_dir, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
shorthand_commands, /* command table */
shorthand_handlers, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL, /* logger */
NULL /* header parser */
};
static int send_parsed_shorthand(request_rec * r)
{
FILE *f;
//if (true) return FORBIDDEN;
if (r->method_number != M_GET && r->method_number != M_POST) return DECLINED;
if (r->finfo.st_mode == 0) return NOT_FOUND;
r->content_type = "text/html";
//r->content_encoding = "chunked";
r->chunked = 1;
r->mtime = r->finfo.st_mtime;
ap_set_last_modified (r);
f = ap_pfopen (r->pool, r->filename, "r");
if (f == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "file permissions deny server access: %s", r->filename);
return FORBIDDEN;
}
ap_soft_timeout ("send", r);
//ap_send_http_header (r);
int rc = apache_shorthand_module_main(r, f, 0);
TRACE((1, "apache_shorthand_module_main() returned %d\n", rc));
/*
if (!r->header_only)
{
ap_rputs(content, r);
//ap_send_fd (f, r);
}
ap_pfclose (r->pool, f);
*/
ap_kill_timeout (r);
return (rc == 302) ? REDIRECT : OK;
}
static int send_parsed_shorthand_source(request_rec * r)
{
return NOT_FOUND;
}
int shorthand_xbithack_handler(request_rec * r)
{
return send_parsed_shorthand(r);
}
void shorthand_init_handler(server_rec *s, pool *p)
{
}
/**
* main module interpretation function
*/
int apache_shorthand_module_main(request_rec *r, FILE* f, int display_source_mode)
{
#ifdef _DEBUG
extern int trace_level;
trace_level = 20;
#endif
int rc = OK;
ApacheHttpStream stream(r);
ShhModule module(r->filename);
try
{
ap_add_cgi_vars(r);
ap_parse_uri_components(r->pool, r->unparsed_uri, &r->parsed_uri);
ap_add_common_vars(r);
char** env = ap_create_environment(r->pool, r->subprocess_env);
char* e = *env;
while(e != NULL && *e != '\0')
{
TRACE((2, "putenv: %s...\n", e));
safe_putenv(strdup(e));
e = *++env;
}
putenf("SHORTHAND_VERSION", "%s", shorthand_version);
mstream input; input.load_from_file(r->filename);
// execute the script
module.execute_script(input.data(), &stream);
}
catch(ShhException* ex)
{
string msg;
msg.printf("\n\n<br><br><b>Error %s:</b> %s\r\n", ex->href(), ex->message());
TRACE((2, "execution exception %04d: %s\n", ex->code(), ex->message()));
fprintf(stderr, "mod_shorthand: error %04d: %s\n", ex->code(), ex->message());
stream.http_write_chunk(msg.cstr(), msg.length());
}
stream.http_finalize();
return stream.code();
}
int ApacheHttpStream::http_write_chunk(const void* chunk_data, unsigned int chunk_length)
{
if (!m_headers_sent) http_send_headers();
int count = 0;
if (chunk_length > 0)
{
count += ap_rwrite(chunk_data, chunk_length, m_req);
}
return count;
}
void ApacheHttpStream::grab_cookies()
{
string tmp;
const char* cookies = safe_getenv("HTTP_COOKIE", tmp);
//cookies = "cookie1=value1; c3=; cookie2=This is the value (%3b) of cookie called \"Cookie2\"";
if (cookies == NULL) cookies = "";
int length = strlen(cookies);
TRACE((8, "cookies: %s\n", cookies));
RX cookies_rx(" *([^=]+) *= *([^;]*);?");
int off = 0;
while((off = cookies_rx.search(cookies, length, off, false)) != -1)
{
string name, value;
cookies_rx.submatch(cookies, 1, name);
cookies_rx.submatch(cookies, 2, value);
TRACE((8, "in-cookie: name=%s value=%s\n", name.cstr(), value.cstr()));
string clean_value;
value.urldecode(clean_value);
m_in_cookies.put(name, clean_value.clone());
}
//http_add_header("X-Cookies", cookies ? cookies : "");
m_cookies_grabbed = true;
}
const char* ApacheHttpStream::http_get_cookie(const char* name)
{
if (!m_cookies_grabbed) grab_cookies();
string** value = m_in_cookies.get(name);
if (value == NULL || *value == NULL)
return NULL;
else
return (*value)->cstr();
}
int ApacheHttpStream::http_set_cookie(const CHttpCookie* cookie)
{
m_out_cookies.add(cookie->clone());
return 0;
}
int ApacheHttpStream::http_add_header(const char* name, const char* value)
{
ap_table_set(m_req->headers_out, name, value);
if (stricmp(name, "Location") == 0) m_response_code = 302;
return 0;
}
int ApacheHttpStream::http_send_headers()
{
if (m_headers_sent) return 0;
for(int i=0,n=m_out_cookies.size(); i<n; i++)
{
CHttpCookie* cookie = m_out_cookies.get(i);
if (cookie == NULL || cookie->is_deleted()) continue;
string line; cookie->create_response(line, true);
ap_table_add(m_req->headers_out, "Set-Cookie", line);
}
ap_send_http_header(m_req);
m_headers_sent = true;
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?