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 + -
显示快捷键?