Annotation of parser3/src/targets/apache13/modules/extra/mod_parser3.C, revision 1.26
1.2 paf 1: /** @file
1.7 paf 2: Parser: apache 1.3 module.
1.2 paf 3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5:
6: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
7:
1.26 ! paf 8: $Id: mod_parser3.C,v 1.25 2001/04/09 14:02:03 paf Exp $
1.2 paf 9: */
10:
11: #include "httpd.h"
12: #include "http_config.h"
13: #include "http_core.h"
14: #include "http_log.h"
15: #include "http_main.h"
16: #include "http_protocol.h"
17: #include "util_script.h"
18:
1.15 paf 19: #include "pa_sapi.h"
1.2 paf 20: #include "pa_common.h"
21: #include "pa_globals.h"
22: #include "pa_request.h"
1.8 paf 23: #include "pa_version.h"
1.22 paf 24: #include "pa_socks.h"
25:
26: /// @todo init_socks
1.2 paf 27:
1.8 paf 28: struct Parser_module_config {
29: const char* parser_root_auto_path; /// filespec of admin's auto.p file
30: const char* parser_site_auto_path; /// filespec of site's auto.p file
31: };
1.2 paf 32:
33: /*
34: * Declare ourselves so the configuration routines can find and know us.
35: * We'll fill it in at the end of the module.
36: */
37: extern "C" module MODULE_VAR_EXPORT parser3_module;
38:
39: /*
40: * Locate our directory configuration record for the current request.
41: */
1.14 paf 42: static Parser_module_config *our_dconfig(request_rec *r) {
43: return (Parser_module_config *)
44: ap_get_module_config(r->per_dir_config, &parser3_module);
1.2 paf 45: }
46:
1.14 paf 47: static const char *cmd_parser_auto_path(cmd_parms *cmd, void *mconfig, char *file_spec) {
1.8 paf 48: Parser_module_config *cfg = (Parser_module_config *) mconfig;
1.2 paf 49:
1.8 paf 50: // remember assigned filespec into cfg
51: (cmd->info?cfg->parser_root_auto_path:cfg->parser_site_auto_path)=file_spec;
1.2 paf 52:
53: return NULL;
54: }
55:
1.8 paf 56:
1.2 paf 57: /*--------------------------------------------------------------------------*/
58: /* */
59: /* Now we declare our content handlers, which are invoked when the server */
60: /* encounters a document which our module is supposed to have a chance to */
61: /* see. (See mod_mime's SetHandler and AddHandler directives, and the */
62: /* mod_info and mod_status examples, for more details.) */
63: /* */
64: /* Since content handlers are dumping data directly into the connexion */
65: /* (using the r*() routines, such as rputs() and rprintf()) without */
66: /* intervention by other parts of the server, they need to make */
67: /* sure any accumulated HTTP headers are sent first. This is done by */
68: /* calling send_http_header(). Otherwise, no header will be sent at all, */
69: /* and the output sent to the client will actually be HTTP-uncompliant. */
70: /*--------------------------------------------------------------------------*/
71: /*
72: * Sample content handler. All this does is display the call list that has
73: * been built up so far.
74: *
75: * The return value instructs the caller concerning what happened and what to
76: * do next:
77: * OK ("we did our thing")
78: * DECLINED ("this isn't something with which we want to get involved")
79: * HTTP_mumble ("an error status should be reported")
80: */
81:
82:
1.8 paf 83: //@{
1.15 paf 84: /// SAPI func decl
1.26 ! paf 85: void SAPI::log(Pool& pool, const char *fmt, ...) {
! 86: request_rec *r=static_cast<request_rec *>(pool.context());
! 87:
! 88: va_list args;
! 89: va_start(args,fmt);
! 90: char buf[MAX_STRING];
! 91: vsnprintf(buf, MAX_STRING, fmt, args);
! 92: ap_log_rerror(0, 0, APLOG_ERR | APLOG_NOERRNO, r, "%s", buf);
! 93: va_end(args);
! 94: }
! 95:
1.15 paf 96: const char *SAPI::get_env(Pool& pool, const char *name) {
1.10 paf 97: request_rec *r=static_cast<request_rec *>(pool.context());
1.4 paf 98: return (const char *)ap_table_get(r->subprocess_env, name);
99: }
100:
1.24 paf 101: size_t SAPI::read_post(Pool& pool, char *buf, size_t max_bytes) {
1.10 paf 102: request_rec *r=static_cast<request_rec *>(pool.context());
1.5 paf 103:
104: /* ap_log_error(APLOG_MARK, APLOG_DEBUG, r->server,
1.15 paf 105: "mod_parser3: SAPI::read_post(max=%u)", max_bytes);
1.5 paf 106: */
107: int retval;
108: if((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
109: return 0;
110: if(!ap_should_client_block(r))
111: return 0;
112:
113: uint total_read_bytes=0;
114: void (*handler)(int)=signal(SIGPIPE, SIG_IGN);
115: while (total_read_bytes<max_bytes) {
116: ap_hard_timeout("Read POST information", r); /* start timeout timer */
117: uint read_bytes=
118: ap_get_client_block(r, buf+total_read_bytes, max_bytes-total_read_bytes);
119: ap_reset_timeout(r);
120: if (read_bytes<=0)
1.2 paf 121: break;
1.5 paf 122: total_read_bytes+=read_bytes;
123: }
124: signal(SIGPIPE, handler);
125: return total_read_bytes;
1.2 paf 126: }
127:
1.15 paf 128: void SAPI::add_header_attribute(Pool& pool, const char *key, const char *value) {
1.10 paf 129: request_rec *r=static_cast<request_rec *>(pool.context());
1.2 paf 130:
1.3 paf 131: if(strcasecmp(key, "content-type")==0) {
1.2 paf 132: /* r->content_type, *not* r->headers_out("Content-type"). If you don't
133: * set it, it will be filled in with the server's default type (typically
134: * "text/plain"). You *must* also ensure that r->content_type is lower
135: * case.
136: */
137: r->content_type = value;
138: } else
139: ap_table_merge(r->headers_out, key, value);
140: }
141:
1.15 paf 142: void SAPI::send_header(Pool& pool) {
1.10 paf 143: request_rec *r=static_cast<request_rec *>(pool.context());
1.5 paf 144:
1.8 paf 145: ap_hard_timeout("Send header", r);
1.2 paf 146: ap_send_http_header(r);
1.5 paf 147: ap_kill_timeout(r);
1.2 paf 148: }
149:
1.21 paf 150: void SAPI::send_body(Pool& pool, const void *buf, size_t size) {
1.10 paf 151: request_rec *r=static_cast<request_rec *>(pool.context());
1.5 paf 152:
1.8 paf 153: ap_hard_timeout("Send body", r);
1.2 paf 154: ap_rwrite(buf, size, r);
1.5 paf 155: ap_kill_timeout(r);
1.2 paf 156: }
1.18 paf 157:
1.26 ! paf 158: int SAPI::execute(Pool& pool,
! 159: const String& file_spec,
! 160: const Hash *env,
! 161: const Array *argv,
! 162: const String& in, String& out, String& err) {
! 163: request_rec *r=static_cast<request_rec *>(pool.context());
! 164:
! 165: /*
! 166: * we spawn out of r->main if it's there so that we can avoid
! 167: * waiting for free_proc_chain to cleanup in the middle of an
! 168: * SSI request -djg
! 169: */
! 170: if(!ap_bspawn_child(r->main ? r->main->pool : r->pool, cgi_child,
! 171: (void *) &cld, kill_after_timeout,
! 172: &script_out, &script_in, &script_err))
! 173: PTHROW(0, 0,
! 174: &file_spec,
! 175: "could not spawn child process");
! 176:
! 177:
! 178: return pa_exec(file_spec, env, argv, in, out, err);
! 179: }
1.18 paf 180:
1.8 paf 181: //@}
182:
1.11 paf 183: /**
184: main workhorse
185:
1.21 paf 186: @todo intelligent cache-control
1.11 paf 187: */
1.8 paf 188: static int parser_handler(request_rec *r)
1.2 paf 189: {
1.16 paf 190: Pool pool(r->pool);
1.10 paf 191: pool.set_context(r);
1.2 paf 192:
1.8 paf 193: Parser_module_config *dcfg=our_dconfig(r);
1.2 paf 194:
195:
196: /* A flag which modules can set, to indicate that the data being
197: * returned is volatile, and clients should be told not to cache it.
198: */
199: r->no_cache=1;
200:
201: PTRY { // global try
1.4 paf 202: ap_add_common_vars(r);
203: ap_add_cgi_vars(r);
204:
1.2 paf 205: // Request info
206: Request::Info request_info;
1.20 paf 207: request_info.document_root=SAPI::get_env(pool, "DOCUMENT_ROOT");
1.14 paf 208: request_info.path_translated=r->filename;
1.2 paf 209: request_info.method=r->method;
210: request_info.query_string=r->args;
1.20 paf 211: request_info.uri=SAPI::get_env(pool, "REQUEST_URI");
212: request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE");
213: const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH");
1.2 paf 214: request_info.content_length=(content_length?atoi(content_length):0);
1.20 paf 215: request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");
216: request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT");
1.2 paf 217:
218: // prepare to process request
219: Request request(pool,
220: request_info,
221: String::UL_HTML_TYPO
222: );
223:
224: // process the request
225: request.core(
1.8 paf 226: dcfg->parser_root_auto_path, true, // /path/to/admin/auto.p
227: dcfg->parser_site_auto_path, true, // /path/to/site/auto.p
1.2 paf 228: r->header_only!=0);
229: // no actions with request' data past this point
230: // request.exception not not handled here, but all
231: // request' data are associated with it's pool=exception
232:
233: // successful finish
234: } PCATCH(e) { // global problem
1.18 paf 235: // don't allocate anything on pool here:
236: // possible pool' exception not catch-ed now
237: // and there could be out-of-memory exception
1.2 paf 238: const char *body=e.comment();
1.18 paf 239: // log it
240: SAPI::log(pool, "exception in request exception handler: %s", body);
241:
242: //
1.2 paf 243: int content_length=strlen(body);
244:
245: // prepare header
1.15 paf 246: SAPI::add_header_attribute(pool, "content-type", "text/plain");
1.2 paf 247: char content_length_cstr[MAX_NUMBER];
1.25 paf 248: snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
1.15 paf 249: SAPI::add_header_attribute(pool, "content-length", content_length_cstr);
1.2 paf 250:
251: // send header
1.15 paf 252: SAPI::send_header(pool);
1.2 paf 253:
254: // send body
255: if(!r->header_only)
1.15 paf 256: SAPI::send_body(pool, body, content_length);
1.2 paf 257:
258: // unsuccessful finish
259: }
260: PEND_CATCH
261:
262: /*
263: * We did what we wanted to do, so tell the rest of the server we
264: * succeeded.
265: */
266: return OK;
267: }
268:
269: /*--------------------------------------------------------------------------*/
270: /* */
271: /* Now let's declare routines for each of the callback phase in order. */
272: /* (That's the order in which they're listed in the callback list, *not */
273: /* the order in which the server calls them! See the command_rec */
274: /* declaration near the bottom of this file.) Note that these may be */
275: /* called for situations that don't relate primarily to our function - in */
276: /* other words, the fixup handler shouldn't assume that the request has */
277: /* to do with "example" stuff. */
278: /* */
279: /* With the exception of the content handler, all of our routines will be */
280: /* called for each request, unless an earlier handler from another module */
281: /* aborted the sequence. */
282: /* */
283: /* Handlers that are declared as "int" can return the following: */
284: /* */
285: /* OK Handler accepted the request and did its thing with it. */
286: /* DECLINED Handler took no action. */
287: /* HTTP_mumble Handler looked at request and found it wanting. */
288: /* */
289: /* What the server does after calling a module handler depends upon the */
290: /* handler's return value. In all cases, if the handler returns */
291: /* DECLINED, the server will continue to the next module with an handler */
292: /* for the current phase. However, if the handler return a non-OK, */
293: /* non-DECLINED status, the server aborts the request right there. If */
294: /* the handler returns OK, the server's next action is phase-specific; */
295: /* see the individual handler comments below for details. */
296: /* */
297: /*--------------------------------------------------------------------------*/
298: /*
299: * This function is called during server initialisation. Any information
300: * that needs to be recorded must be in static cells, since there's no
301: * configuration record.
302: *
303: * There is no return value.
304: */
1.14 paf 305:
306: static void setup_module_cells() {
1.2 paf 307: static bool globals_inited=false;
308: if(globals_inited)
309: return;
310: globals_inited=true;
311:
1.14 paf 312: /*
313: * allocate our module-private pool.
314: */
1.16 paf 315: static Pool pool(ap_make_sub_pool(NULL)); // global pool
1.2 paf 316: PTRY {
317: // init global variables
1.15 paf 318: pa_globals_init(pool);
1.2 paf 319: } PCATCH(e) { // global problem
1.18 paf 320: ap_log_error(APLOG_MARK, APLOG_EMERG, 0,
321: "setup_module_cells failed: ", e.comment());
322: exit(1);
1.2 paf 323: }
324: PEND_CATCH
325: }
326:
1.14 paf 327: static void parser_server_init(server_rec *s, pool *p) {
328: #if MODULE_MAGIC_NUMBER >= 19980527
1.17 paf 329: ap_add_version_component("Parser/"PARSER_VERSION);
1.14 paf 330: #endif
1.2 paf 331:
332: /*
1.14 paf 333: * Set up any module cells that ought to be initialised.
1.2 paf 334: */
1.14 paf 335: setup_module_cells();
1.2 paf 336: }
337:
338: /*
339: * This function gets called to create a per-directory configuration
340: * record. This will be called for the "default" server environment, and for
341: * each directory for which the parser finds any of our directives applicable.
342: * If a directory doesn't have any of our directives involved (i.e., they
343: * aren't in the .htaccess file, or a <Location>, <Directory>, or related
344: * block), this routine will *not* be called - the configuration for the
345: * closest ancestor is used.
346: *
347: * The return value is a pointer to the created module-specific
348: * structure.
349: */
1.14 paf 350: static void *parser_create_dir_config(pool *p, char *dirspec) {
351: /*
1.2 paf 352: * Allocate the space for our record from the pool supplied.
353: */
1.14 paf 354: Parser_module_config *cfg=
355: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
1.2 paf 356: /*
357: * Now fill in the defaults. If there are any `parent' configuration
358: * records, they'll get merged as part of a separate callback.
359: */
1.8 paf 360: cfg->parser_root_auto_path = 0;
361: cfg->parser_site_auto_path = 0;
1.2 paf 362: return (void *) cfg;
363: }
364:
365: /*
366: * This function gets called to merge two per-directory configuration
367: * records. This is typically done to cope with things like .htaccess files
368: * or <Location> directives for directories that are beneath one for which a
369: * configuration record was already created. The routine has the
370: * responsibility of creating a new record and merging the contents of the
371: * other two into it appropriately. If the module doesn't declare a merge
372: * routine, the record for the closest ancestor location (that has one) is
373: * used exclusively.
374: *
375: * The routine MUST NOT modify any of its arguments!
376: *
377: * The return value is a pointer to the created module-specific structure
378: * containing the merged values.
379: */
1.8 paf 380: static void *parser_merge_dir_config(pool *p, void *parent_conf,
1.14 paf 381: void *newloc_conf) {
382: Parser_module_config *merged_config =
383: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
1.8 paf 384: Parser_module_config *pconf = (Parser_module_config *) parent_conf;
385: Parser_module_config *nconf = (Parser_module_config *) newloc_conf;
386:
387: // always from parent
388: merged_config->parser_root_auto_path = ap_pstrdup(p, pconf->parser_root_auto_path);
1.2 paf 389: /*
390: * Some things get copied directly from the more-specific record, rather
391: * than getting merged.
392: */
1.8 paf 393: merged_config->parser_site_auto_path = ap_pstrdup(p, nconf->parser_site_auto_path?
394: nconf->parser_site_auto_path:pconf->parser_site_auto_path);
395:
1.2 paf 396: return (void *) merged_config;
397: }
398:
399: /*
400: * This function gets called to create a per-server configuration
401: * record. It will always be called for the "default" server.
402: *
403: * The return value is a pointer to the created module-specific
404: * structure.
405: */
1.14 paf 406: static void *parser_create_server_config(pool *p, server_rec *s) {
1.2 paf 407: /*
1.8 paf 408: * As with the parser_create_dir_config() reoutine, we allocate and fill
1.2 paf 409: * in an empty record.
410: */
1.14 paf 411: Parser_module_config *cfg=
412: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
413:
1.8 paf 414: cfg->parser_root_auto_path = 0;
415: cfg->parser_site_auto_path = 0;
1.14 paf 416:
1.2 paf 417: return (void *) cfg;
418: }
419:
420: /*
421: * This function gets called to merge two per-server configuration
422: * records. This is typically done to cope with things like virtual hosts and
423: * the default server configuration The routine has the responsibility of
424: * creating a new record and merging the contents of the other two into it
425: * appropriately. If the module doesn't declare a merge routine, the more
426: * specific existing record is used exclusively.
427: *
428: * The routine MUST NOT modify any of its arguments!
429: *
430: * The return value is a pointer to the created module-specific structure
431: * containing the merged values.
432: */
1.8 paf 433: static void *parser_merge_server_config(pool *p, void *server1_conf,
1.2 paf 434: void *server2_conf)
435: {
436:
1.14 paf 437: Parser_module_config *merged_config =
438: (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config));
1.8 paf 439: Parser_module_config *s1conf = (Parser_module_config *) server1_conf;
440: Parser_module_config *s2conf = (Parser_module_config *) server2_conf;
1.2 paf 441:
442: /*
443: * Our inheritance rules are our own, and part of our module's semantics.
444: * Basically, just note whence we came.
445: */
1.8 paf 446: merged_config->parser_root_auto_path = ap_pstrdup(p, s2conf->parser_root_auto_path?
447: s2conf->parser_root_auto_path:s1conf->parser_root_auto_path);
448: merged_config->parser_site_auto_path = ap_pstrdup(p, s2conf->parser_site_auto_path?
449: s2conf->parser_site_auto_path:s1conf->parser_site_auto_path);
450:
451: return (void *) merged_config;
1.2 paf 452: }
453:
454: /*
455: * This routine gives our module an opportunity to translate the URI into an
456: * actual filename. If we don't do anything special, the server's default
457: * rules (Alias directives and the like) will continue to be followed.
458: *
459: * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
460: * further modules are called for this phase.
461: */
1.14 paf 462: static int parser_translate_handler(request_rec *r) {
463: Parser_module_config *cfg=our_dconfig(r);
1.2 paf 464: return DECLINED;
465: }
466:
467: /*
468: * This routine is called to check the authentication information sent with
469: * the request (such as looking up the user in a database and verifying that
470: * the [encrypted] password sent matches the one in the database).
471: *
472: * The return value is OK, DECLINED, or some HTTP_mumble error (typically
473: * HTTP_UNAUTHORIZED). If we return OK, no other modules are given a chance
474: * at the request during this phase.
475: */
1.14 paf 476: static int parser_check_user_id(request_rec *r) {
477: Parser_module_config *cfg=our_dconfig(r);
1.2 paf 478: return DECLINED;
479: }
480:
481: /*
482: * This routine is called to check to see if the resource being requested
483: * requires authorisation.
484: *
485: * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
486: * other modules are called during this phase.
487: *
488: * If *all* modules return DECLINED, the request is aborted with a server
489: * error.
490: */
1.14 paf 491: static int parser_auth_checker(request_rec *r) {
492: Parser_module_config *cfg=our_dconfig(r);
1.2 paf 493: return DECLINED;
494: }
495:
496: /*
497: * This routine is called to check for any module-specific restrictions placed
498: * upon the requested resource. (See the mod_access module for an example.)
499: *
500: * The return value is OK, DECLINED, or HTTP_mumble. All modules with an
501: * handler for this phase are called regardless of whether their predecessors
502: * return OK or DECLINED. The first one to return any other status, however,
503: * will abort the sequence (and the request) as usual.
504: */
1.14 paf 505: static int parser_access_checker(request_rec *r) {
1.2 paf 506:
1.14 paf 507: Parser_module_config *cfg=our_dconfig(r);
1.2 paf 508: return DECLINED;
509: }
510:
511: /*--------------------------------------------------------------------------*/
512: /* */
513: /* All of the routines have been declared now. Here's the list of */
514: /* directives specific to our module, and information about where they */
515: /* may appear and how the command parser should pass them to us for */
516: /* processing. Note that care must be taken to ensure that there are NO */
517: /* collisions of directive names between modules. */
518: /* */
519: /*--------------------------------------------------------------------------*/
520: /*
521: * List of directives specific to our module.
522: */
1.8 paf 523: static const command_rec parser_cmds[] =
1.2 paf 524: {
525: {
1.8 paf 526: "parser_root_auto_path", /* directive name */
527: (const char *(*)(void))((void *)cmd_parser_auto_path), // config action routine
528: (void*)true, /* argument to include in call */
529: (int)(ACCESS_CONF|RSRC_CONF), /* where available */
530: TAKE1, /* arguments */
531: "Parser root auto.p filespec (Admin)" // directive description
532: },
533: {
534: "parser_site_auto_path", /* directive name */
535: (const char *(*)(void))((void *)cmd_parser_auto_path), // config action routine
536: (void*)false, /* argument to include in call */
537: (int)(OR_OPTIONS), /* where available */
538: TAKE1, /* arguments */
539: "Parser site auto.p filespec" // directive description
1.2 paf 540: },
541: {NULL}
542: };
543:
544: /*--------------------------------------------------------------------------*/
545: /* */
546: /* Now the list of content handlers available from this module. */
547: /* */
548: /*--------------------------------------------------------------------------*/
549: /*
550: * List of content handlers our module supplies. Each handler is defined by
551: * two parts: a name by which it can be referenced (such as by
552: * {Add,Set}Handler), and the actual routine name. The list is terminated by
553: * a NULL block, since it can be of variable length.
554: *
555: * Note that content-handlers are invoked on a most-specific to least-specific
556: * basis; that is, a handler that is declared for "text/plain" will be
557: * invoked before one that was declared for "text / *". Note also that
558: * if a content-handler returns anything except DECLINED, no other
559: * content-handlers will be called.
560: */
1.8 paf 561: static const handler_rec parser_handlers[] =
1.2 paf 562: {
1.8 paf 563: {"parser3-handler", parser_handler},
1.2 paf 564: {NULL}
565: };
566:
567: /*--------------------------------------------------------------------------*/
568: /* */
569: /* Finally, the list of callback routines and data structures that */
570: /* provide the hooks into our module from the other parts of the server. */
571: /* */
572: /*--------------------------------------------------------------------------*/
573: /*
574: * Module definition for configuration. If a particular callback is not
575: * needed, replace its routine name below with the word NULL.
576: *
577: * The number in brackets indicates the order in which the routine is called
578: * during request processing. Note that not all routines are necessarily
579: * called (such as if a resource doesn't have access restrictions).
580: */
581: module MODULE_VAR_EXPORT parser3_module =
582: {
583: STANDARD_MODULE_STUFF,
1.14 paf 584: parser_server_init, /* module initializer */
585: parser_create_dir_config, /* per-directory config creator */
586: parser_merge_dir_config, /* dir config merger */
587: parser_create_server_config, /* server config creator */
588: parser_merge_server_config, /* server config merger */
589: parser_cmds, /* command table */
590: parser_handlers, /* [9] list of handlers */
591: parser_translate_handler, /* [2] filename-to-URI translation */
592: parser_check_user_id, /* [5] check/validate user_id */
593: parser_auth_checker, /* [6] check user_id is valid *here* */
594: parser_access_checker, /* [4] check access by host address */
595: 0, /* [7] MIME type checker/setter */
596: 0, /* [8] fixups */
597: 0 /* [10] logger */
1.2 paf 598: };
E-mail: