source: main/trunk/greenstone2/runtime-src/src/recpt/mod_gsdl.cpp@ 21808

Last change on this file since 21808 was 21324, checked in by ak19, 14 years ago

Changes to makefiles, configure files, and source code to work with the new configure flags that allow indexers to be individually compiled up by setting each indexer to be enabled or disabled (enable-mg, enable-mgpp, enable-lucene)

File size: 18.0 KB
Line 
1/**********************************************************************
2 *
3 * mod_gsdl.cpp -- front end for apache 1.3 or 2.x module
4 * Copyright (C) 2003 DL Consulting Ltd
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "httpd.h"
27#include "http_core.h"
28#include "http_config.h"
29#include "http_protocol.h"
30#include "http_main.h"
31#include "util_script.h"
32#include "ap_config.h"
33#include "http_log.h"
34
35
36#if _APACHE_MOD >= 2
37
38#include "ap_compat.h"
39
40// In addition to the backward compatible features defined in
41// ap_compat.h, define
42
43typedef apr_pool_t ap_pool; // map old type to new apr_* version
44
45// In Apache 2.x, ap_log_error takes extra parameter -- status code
46// from the previous command; define macro to automatically add in
47// surrogate value of 0 for this
48#define ap_log_error(file,line,level,server,fmt) \
49 ap_log_error(file,line,level,0,server,fmt)
50
51#endif
52
53#if defined(USE_MYSQL)
54#include "mysqlclass.h"
55#endif
56#if defined(USE_ACCESS)
57#include "accessclass.h"
58#endif
59
60#include "maincfg.h"
61#include "string_pool.h"
62
63#include "receptionist.h"
64#include "cgiwrapper.h"
65#include "cgiutils.h"
66#include "fileutil.h"
67#include "nullproto.h"
68#include "collectserver.h"
69#include "filter.h"
70#include "browsefilter.h"
71
72//#ifdef ENABLE_MG
73//#include "mgqueryfilter.h"
74//#include "mgsearch.h"
75//#endif
76
77#include "infodbclass.h"
78#include "collectset.h"
79
80#include "gdbmclass.h"
81
82#include "action.h"
83#include "pageaction.h"
84#include "queryaction.h"
85#include "documentaction.h"
86#include "extlinkaction.h"
87#ifdef ENABLE_MGPP
88#include "phindaction.h"
89#endif
90#if defined(USE_MYSQL) || defined(USE_ACCESS)
91#include "orderaction.h"
92#endif
93#include "configaction.h"
94
95#include "browserclass.h"
96#include "vlistbrowserclass.h"
97#include "hlistbrowserclass.h"
98#include "datelistbrowserclass.h"
99#include "invbrowserclass.h"
100#include "pagedbrowserclass.h"
101#include "phindbrowserclass.h"
102
103#include <strstream>
104
105receptionist recpt;
106nullproto nproto;
107
108extern "C" module MODULE_VAR_EXPORT gsdl_module;
109
110typedef struct {
111 char *config_gsdlhome;
112 char *config_collecthome;
113 char *config_httpprefix;
114 char *config_httpweb;
115} gsdl_config;
116
117static void *gsdl_create_config(ap_pool *p, server_rec *s) {
118
119#if _APACHE_MOD >= 2
120 gsdl_config *cfg = (gsdl_config *)apr_pcalloc(p, sizeof(gsdl_config));
121#else
122 gsdl_config *cfg = (gsdl_config *)ap_pcalloc(p, sizeof(gsdl_config));
123#endif
124
125 return (void *)cfg;
126}
127
128static void *gsdl_create_dir_config(ap_pool *p, char *path) {
129
130 return (gsdl_config *) gsdl_create_config(p, NULL);
131}
132
133static const char *gsdl_cmd(cmd_parms *cmd, void *mconfig,
134 char *val) {
135
136 server_rec *s = cmd->server;
137 gsdl_config *cfg = (gsdl_config *) ap_get_module_config(s->module_config, &gsdl_module);
138
139 if (strcmp(cmd->cmd->name, "gsdlhome") == 0) {
140 cfg->config_gsdlhome = val;
141 } else if (strcmp(cmd->cmd->name, "collecthome") == 0) {
142 cfg->config_collecthome = val;
143 } else if (strcmp(cmd->cmd->name, "httpprefix") == 0) {
144 cfg->config_httpprefix = val;
145 } else if (strcmp(cmd->cmd->name, "httpweb") == 0) {
146 cfg->config_httpweb = val;
147 }
148
149 return NULL;
150}
151
152#if _APACHE_MOD < 2
153static void gsdl_exit(void* d) {
154#else
155static apr_status_t gsdl_exit(void* d) {
156#endif
157
158#if defined(USE_ACCESS)
159 // shut down com
160 CoUninitialize();
161#endif
162
163#if _APACHE_MOD >= 2
164 return APR_SUCCESS;
165#endif
166}
167
168#if _APACHE_MOD < 2
169static void gsdl_init(server_rec *s, ap_pool *p) {
170#else
171static void gsdl_init(ap_pool *p, server_rec *s) {
172#endif
173
174 // Register gsdl_exit has cleanup operation for when pchild (process id
175 // of child) exits
176#if _APACHE_MOD >= 2
177 apr_pool_cleanup_register(p,s, apr_pool_cleanup_null, gsdl_exit);
178#else
179 ap_register_cleanup(p,s, ap_null_cleanup, gsdl_exit);
180#endif
181
182 recpt.loaded = false;
183
184 gsdl_config *cfg = (gsdl_config *) ap_get_module_config(s->module_config, &gsdl_module);
185
186 if (!cfg->config_gsdlhome) {
187 ap_log_error("", 0, APLOG_ERR, s, "gsdlhome not set\n");
188 return;
189 }
190 text_t gsdlhome = cfg->config_gsdlhome;
191
192 if (!directory_exists(gsdlhome)) {
193 ap_log_error("", 0, APLOG_ERR, s, "gsdlhome directory does not exist\n");
194 return;
195 }
196
197 if (!cfg->config_collecthome) {
198 ap_log_error("", 0, APLOG_ERR, s, "collecthome not set\n");
199 return;
200 }
201 text_t collecthome = cfg->config_collecthome;
202
203 if (!directory_exists(collecthome)) {
204 ap_log_error("", 0, APLOG_ERR, s, "collecthome directory does not exist\n");
205 return;
206 }
207
208
209 if (!cfg->config_httpprefix) {
210 ap_log_error("", 0, APLOG_ERR, s, "httpprefix not set\n");
211 return;
212 }
213
214 if (!cfg->config_httpweb) {
215 ap_log_error("", 0, APLOG_ERR, s, "httpweb not set\n");
216 return;
217 }
218
219 text_t httpprefix = cfg->config_httpprefix;
220 text_t httpweb = cfg->config_httpweb;
221
222 text_t collection = "";
223
224 collectset *cservers = new collectset();
225
226 cservers->add_all_collections(gsdlhome,collecthome);
227
228 // set up the null protocol
229 nproto.set_collectset(cservers);
230
231 // add the protocol to the receptionist
232 recpt.add_protocol(&nproto);
233
234 // add database object to receptionist
235#if defined(USE_MYSQL)
236 mysqlclass *db = new mysqlclass();
237#elif defined(USE_ACCESS)
238 // start up com
239 if(FAILED(CoInitialize(NULL))) {
240 cout << "CoInitialize failed\n";
241 exit(-1);
242 }
243 accessclass *db = new accessclass();
244#else
245
246 // not using either mysql or access database - we'll use the gdbmclass
247 // class as a filler (but most likely won't work) - only useful
248 // if creating a binary that doesn't require access to the database
249 dbclass *db = new gdbmclass();
250
251#endif
252
253#if defined(USE_MYSQL) || defined(USE_ACCESS)
254 recpt.add_dbclass(db);
255#endif
256
257 // the list of actions.
258 pageaction *apageaction = new pageaction();
259 apageaction->set_receptionist(&recpt);
260 recpt.add_action(apageaction);
261
262 queryaction *aqueryaction = new queryaction();
263 aqueryaction->set_receptionist(&recpt);
264 recpt.add_action(aqueryaction);
265
266 documentaction *adocumentaction = new documentaction();
267 adocumentaction->set_receptionist(&recpt);
268 recpt.add_action(adocumentaction);
269
270 extlinkaction *anextlinkaction = new extlinkaction();
271 recpt.add_action(anextlinkaction);
272
273 // phindaction is for MGPP and uses MGQuery
274#ifdef ENABLE_MGPP
275 phindaction *aphindaction = new phindaction();
276 recpt.add_action(aphindaction);
277#endif
278
279#if defined(USE_MYSQL) || defined(USE_ACCESS)
280 orderaction *aorderaction = new orderaction();
281 aorderaction->set_receptionist(&recpt);
282 recpt.add_action(aorderaction);
283#endif
284
285 configaction *aconfigaction = new configaction();
286 aconfigaction->set_receptionist(&recpt);
287 recpt.add_action(aconfigaction);
288
289 // list of browsers
290 vlistbrowserclass *avlistbrowserclass = new vlistbrowserclass();
291 recpt.add_browser(avlistbrowserclass);
292 recpt.setdefaultbrowser("VList");
293
294 hlistbrowserclass *ahlistbrowserclass = new hlistbrowserclass();
295 recpt.add_browser(ahlistbrowserclass);
296
297 datelistbrowserclass *adatelistbrowserclass = new datelistbrowserclass();
298 recpt.add_browser(adatelistbrowserclass);
299
300 invbrowserclass *ainvbrowserclass = new invbrowserclass();
301 recpt.add_browser(ainvbrowserclass);
302
303 pagedbrowserclass *apagedbrowserclass = new pagedbrowserclass();
304 recpt.add_browser(apagedbrowserclass);
305
306 phindbrowserclass *aphindbrowserclass = new phindbrowserclass();;
307 recpt.add_browser(aphindbrowserclass);
308
309 // configure everything
310 recpt.configure("gsdlhome", gsdlhome);
311 recpt.configure("collecthome", collecthome);
312 recpt.configure("collection", collection);
313 recpt.configure("httpweb", httpweb);
314 recpt.configure("httpprefix", httpprefix);
315 // set httpprefixfull - if httpprefix is a relative path we need to get
316 // the server name and port from the web server environment (note that
317 // gwcgi and gwcgifull will be configured for each page request (in gsdl_handler)
318 // as we need to know that directory info etc.)
319 text_t httpprefixfull = httpprefix;
320 if ((httpprefixfull.size() < 7) ||
321 (substr(httpprefixfull.begin(), httpprefixfull.begin()+7) != "http://")) {
322 if (s->server_hostname && s->port) {
323 httpprefixfull = "http://" + text_t(s->server_hostname) + ":" + text_t(s->port) + httpprefixfull;
324 }
325 }
326 recpt.configure("httpprefixfull", httpprefixfull);
327
328 // read in main.cfg file
329 if (!main_cfg_read(recpt, gsdlhome, collecthome, collection)) {
330 ap_log_error("", 0, APLOG_ERR, s, "failed to read main.cfg file\n");
331 return;
332 }
333
334 text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
335 char *eout = error_file.getcstr();
336 ofstream errout (eout, ios::app);
337 delete eout;
338
339 // initialise the library software
340 if (!recpt.init(errout)) {
341 ap_log_error("", 0, APLOG_ERR, s, "Greenstone failed to initialize\n");
342 errout.close();
343 return;
344 }
345
346 errout.close();
347
348 // set flag so gsdl_handler can check that everything initialized
349 // successfully
350 recpt.loaded = true;
351}
352
353
354#if _APACHE_MOD < 2
355
356typedef const char *(*CMD_HAND_TYPE) ();
357static command_rec gsdl_cmds[] = {
358 {"gsdlhome", (CMD_HAND_TYPE)gsdl_cmd,
359 (void *)XtOffsetOf(gsdl_config, config_gsdlhome),
360 OR_ALL, TAKE1, "GSDLHOME directory."},
361 {"collecthome", (CMD_HAND_TYPE)gsdl_cmd,
362 (void *)XtOffsetOf(gsdl_config, config_collecthome),
363 OR_ALL, TAKE1, "COLLECTHOME directory."},
364 {"httpprefix", (CMD_HAND_TYPE)gsdl_cmd,
365 (void *)XtOffsetOf(gsdl_config, config_httpprefix),
366 OR_ALL, TAKE1, "GSDLHOME http path."},
367 {"httpweb", (CMD_HAND_TYPE)gsdl_cmd,
368 (void *)XtOffsetOf(gsdl_config, config_httpweb),
369 OR_ALL, TAKE1, "GSDLHOME http web path."},
370 {NULL, NULL, NULL, 0, cmd_how(0), NULL}
371};
372#else
373
374/*
375static const char
376*set_max_cache_size(cmd_parms *parms, void *in_struct_ptr, const char *arg)
377{
378 apr_size_t val;
379
380 return NULL;
381}
382
383 AP_INIT_TAKE1("MCacheSize", set_max_cache_size, NULL, RSRC_CONF,
384 "The maximum amount of memory used by the cache in KBytes"),
385
386*/
387
388// const char *(*cmd_func)();
389
390static const command_rec gsdl_cmds[] = {
391 AP_INIT_TAKE1("gsdlhome", (cmd_func)gsdl_cmd, NULL, OR_ALL,"GSDLHOME directory."),
392 AP_INIT_TAKE1("collecthome", (cmd_func)gsdl_cmd, NULL, OR_ALL,"COLLECTHOME directory."),
393 AP_INIT_TAKE1("httpprefix", (cmd_func)gsdl_cmd, NULL, OR_ALL,"GSDLHOME http path."),
394 AP_INIT_TAKE1("httpweb", (cmd_func)gsdl_cmd, NULL, OR_ALL,"GSDLHOME http web path."),
395 {NULL}
396};
397
398
399#endif
400
401static int gsdl_handler(request_rec *r) {
402
403 if (strcmp(r->handler, "gsdl")) {
404 return DECLINED;
405 }
406
407 // check that everything has been initialized
408 if (!recpt.loaded) {
409 ap_log_error("", 0, APLOG_ERR, r->server, "gsdl_handler: attempt to use uninitialized receptionist - aborting\n");
410 return 500;
411 }
412
413 gsdl_config *cfg = (gsdl_config *) ap_get_module_config(r->server->module_config, &gsdl_module);
414
415 if (!cfg->config_gsdlhome) {
416 ap_log_error("", 0, APLOG_ERR, r->server, "gsdl_handler: gsdlhome not set\n");
417 return 500;
418 }
419
420 if (!cfg->config_collecthome) {
421 ap_log_error("", 0, APLOG_ERR, r->server, "gsdl_handler: collecthome not set\n");
422 return 500;
423 }
424
425 // configure gwcgi and gwcgifull
426 recpt.configure("gwcgi", r->uri);
427 recpt.configure("gwcgifull", "http://" + text_t(r->server->server_hostname) +
428 ":" + text_t(r->server->port) + r->uri);
429
430 string_pool str_pool;
431
432 text_t gsdlhome = cfg->config_gsdlhome;
433
434 text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
435 char *eout = str_pool.get_cstr_from_pool(error_file);
436 ofstream errout (eout, ios::app);
437
438 text_t argstr;
439 fileupload_tmap fileuploads;
440
441 char *request_method_str = getenv("REQUEST_METHOD");
442 char *content_length_str = getenv("CONTENT_LENGTH");
443 if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
444 content_length_str != NULL) {
445 // POST form data
446 long content_length = (content_length_str ? atoi(content_length_str) : 0);
447 if (content_length > 0) {
448#ifdef __WIN32__
449 // On Windows it is important that standard input be read in binary
450 // mode, otherwise end of line "<CR><LF>" is turned into <LF> only
451 // which breaks the MIME standard (and our parsing code!)
452
453 int result = _setmode( _fileno( stdin ), _O_BINARY );
454 if( result == -1 ) {
455 cerr << "Warning: Failed to set standard input to binary mode." << endl;
456 cerr << " Parsing of multi-part MIME will most likely fail" << endl;
457 }
458#endif
459
460 long length = content_length;
461 unsigned char * buffer = new unsigned char[content_length];
462
463 int chars_read = fread(buffer,1,content_length,stdin);
464
465 if (chars_read != content_length) {
466 cerr << "Warning: mismatch between CONTENT_LENGTH and data read from standard in" << endl;
467 }
468
469 argstr.setcarr((char *)buffer, content_length);
470
471 text_t content_type;
472 char *content_type_str = getenv("CONTENT_TYPE");
473 if (content_type_str) content_type = content_type_str;
474 argstr = parse_post_data(content_type, argstr, fileuploads, gsdlhome);
475 }
476 } else {
477
478 if (r->args) argstr = r->args;
479 }
480
481 // parse the cgi arguments and produce the resulting page if there
482 // have been no errors so far
483 cgiargsclass args;
484 text_tmap fastcgienv; // Not being used in this case
485 if (!recpt.parse_cgi_args (argstr, fileuploads, args, errout, fastcgienv)) {
486 errout.close();
487 ap_log_error("", 0, APLOG_ERR, r->server, "parse_cgi_args failed\n");
488 return 500;
489 }
490
491 ostrstream pageout;
492
493 // get http headers
494 text_tmap headers;
495 recpt.get_cgihead_info(args, headers, errout, fastcgienv);
496
497 if (headers.find("Location") != headers.end()) {
498 // redirect
499 char *val = str_pool.get_cstr_from_pool(headers.find("Location")->second);
500#if _APACHE_MOD >= 2
501 apr_table_set(r->headers_out, "location", val);
502#else
503 ap_table_set(r->headers_out, "location", val);
504#endif
505 return HTTP_MOVED_TEMPORARILY;
506 }
507
508 text_tmap::iterator here = headers.begin();
509 text_tmap::iterator end = headers.end();
510 while (here != end) {
511 text_t namet = (*here).first;
512 lc(namet);
513 char *name = str_pool.get_cstr_from_pool(namet);
514 char *val = str_pool.get_cstr_from_pool((*here).second);
515
516 if ((*here).first == "content-type") {
517#if _APACHE_MOD < 2
518 r->content_type = val;
519#else
520
521 char* val_copy = strdup(val); // if note freed by r->content_type => Memory leak!
522 ap_set_content_type(r, val_copy);
523#endif
524 } else if ((*here).first == "content-encoding") {
525 r->content_encoding = val;
526 } else {
527#if _APACHE_MOD >= 2
528 apr_table_set(r->headers_out, name, val);
529#else
530 ap_table_set(r->headers_out, name, val);
531#endif
532 }
533
534 here++;
535 }
536 ap_send_http_header(r);
537
538 if (!r->header_only) {
539 if (!recpt.produce_content(args, pageout, errout)) {
540 ap_log_error("", 0, APLOG_ERR, r->server, "produce_content failed\n");
541 return 500;
542 }
543 char *out = pageout.str();
544 ap_rwrite(out, pageout.pcount(), r);
545 pageout.rdbuf()->freeze(0);
546 }
547
548 errout.close();
549
550 return OK;
551}
552
553#if _APACHE_MOD < 2
554
555static const handler_rec gsdl_handlers[] = {
556 { "gsdl", gsdl_handler },
557 { NULL, NULL }
558};
559
560
561extern "C" {
562 module MODULE_VAR_EXPORT gsdl_module = {
563 STANDARD_MODULE_STUFF,
564 NULL, /* module \initializer */
565 gsdl_create_dir_config, /* create per-dir config structures */
566 NULL, /* merge per-dir config structures */
567 gsdl_create_config, /* create per-server config structures */
568 NULL, /* merge per-server config structures */
569 gsdl_cmds, /* table of config file commands */
570 gsdl_handlers, /* [#8] MIME-typed-dispatched handlers */
571 NULL, /* [#1] URI to filename translation */
572 NULL, /* [#4] validate user id from request */
573 NULL, /* [#5] check if the user is ok _here_ */
574 NULL, /* [#3] check access by host address */
575 NULL, /* [#6] determine MIME type */
576 NULL, /* [#7] pre-run fixups */
577 NULL, /* [#9] log a transaction */
578 NULL, /* [#2] header parser */
579 gsdl_init, /* child_init */
580 NULL, /* child_exit */
581 NULL /* [#0] post read-request */
582#ifdef EAPI
583 ,NULL, /* EAPI: add_module */
584 NULL, /* EAPI: remove_module */
585 NULL, /* EAPI: rewrite_command */
586 NULL, /* EAPI: new_connection */
587 NULL /* EAPI: close_connection */
588#endif
589 };
590};
591
592#else
593
594static void gsdl_register_hooks(ap_pool *p)
595{
596 ap_hook_child_init(gsdl_init,NULL,NULL,APR_HOOK_MIDDLE);
597 ap_hook_handler(gsdl_handler, NULL, NULL, APR_HOOK_MIDDLE);
598
599}
600
601extern "C" {
602 module AP_MODULE_DECLARE_DATA gsdl_module = {
603 STANDARD20_MODULE_STUFF,
604 gsdl_create_dir_config, /* create per-dir config structures */
605 NULL, /* merge per-dir config structures */
606 gsdl_create_config, /* create per-server config structures */
607 NULL, /* merge per-server config structures */
608 gsdl_cmds, /* command handlers */
609 gsdl_register_hooks, /* set up other request processing hooks */
610 };
611};
612#endif
Note: See TracBrowser for help on using the repository browser.