source: trunk/gsdl/src/recpt/cgiwrapper.cpp@ 963

Last change on this file since 963 was 963, checked in by sjboddie, 24 years ago

gsdlhome now comes from gsdlsite.cfg

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
RevLine 
[144]1/**********************************************************************
2 *
3 * cgiwrapper.cpp -- output pages using the cgi protocol
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
[533]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.
[144]9 *
[533]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 *
[144]24 * $Id: cgiwrapper.cpp 963 2000-02-21 22:01:02Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
[963]30 Revision 1.22 2000/02/21 21:56:46 sjboddie
31 gsdlhome now comes from gsdlsite.cfg
32
[872]33 Revision 1.21 2000/01/25 22:45:59 sjboddie
34 few changes to get fastcgi to work properly
35
[533]36 Revision 1.20 1999/09/07 04:56:53 sjboddie
37 added GPL notice
38
[508]39 Revision 1.19 1999/09/02 00:24:36 rjmcnab
40 fixed bug in getting POST arguments
41
[465]42 Revision 1.18 1999/08/20 01:02:07 sjboddie
43 added some usage logging
44
[389]45 Revision 1.17 1999/07/15 06:03:15 rjmcnab
46 Moved the adding of the actions to librarymain so that they can be
47 overriden easily.
48
[387]49 Revision 1.16 1999/07/14 08:31:05 rjmcnab
50 Fixed a small bug in the POST implementation.
51
[377]52 Revision 1.15 1999/07/13 23:32:17 rjmcnab
53 Added authenaction and usersaction
54
[365]55 Revision 1.14 1999/07/11 01:03:37 rjmcnab
56 Added ability to receive POST cgi form data.
57
[284]58 Revision 1.13 1999/06/24 05:12:18 sjboddie
59 lots of small changes
60
[248]61 Revision 1.12 1999/04/30 01:59:40 sjboddie
62 lots of stuff - getting documentaction working (documentaction replaces
63 old browseaction)
64
[210]65 Revision 1.11 1999/03/25 03:12:01 sjboddie
66
67 subjectbrowseaction was replaced with browseaction
68
[189]69 Revision 1.10 1999/03/05 03:53:54 sjboddie
70
71 fixed some bugs
72
[188]73 Revision 1.9 1999/03/04 22:38:21 sjboddie
74
75 Added subjectbrowseaction. - Doesn't do anything yet.
76
[173]77 Revision 1.8 1999/02/28 20:00:13 rjmcnab
78
79
80 Fixed a few things.
81
[165]82 Revision 1.7 1999/02/21 22:33:53 rjmcnab
83
84 Lots of stuff :-)
85
[160]86 Revision 1.6 1999/02/12 02:40:17 sjboddie
87
88 Added page action
89
[158]90 Revision 1.5 1999/02/11 01:24:04 rjmcnab
91
92 Fixed a few compiler warnings.
93
[155]94 Revision 1.4 1999/02/08 01:28:01 rjmcnab
95
96 Got the receptionist producing something using the statusaction.
97
[150]98 Revision 1.3 1999/02/05 10:42:44 rjmcnab
99
100 Continued working on receptionist
101
[146]102 Revision 1.2 1999/02/04 10:00:56 rjmcnab
103
104 Developed the idea of an "action" and having them define the cgi arguments
105 which they need and how those cgi arguments function.
106
[144]107 Revision 1.1 1999/02/04 01:16:17 rjmcnab
108
109 Initial revision.
110
111 Revision 1.5 1999/01/19 01:38:18 rjmcnab
112
113 Made the source more portable.
114
115 Revision 1.4 1999/01/12 01:51:04 rjmcnab
116
117 Standard header.
118
119 */
120
121
122#include "gsdlconf.h"
123#include "cgiwrapper.h"
[150]124#include "recptconfig.h"
[963]125#include "fileutil.h"
[144]126#include <stdlib.h>
[872]127#include <assert.h>
[144]128
129#if defined(GSDL_USE_OBJECTSPACE)
130# include <ospace/std/iostream>
131# include <ospace/std/fstream>
132#elif defined(GSDL_USE_IOS_H)
133# include <iostream.h>
134# include <fstream.h>
135#else
136# include <iostream>
137# include <fstream>
138#endif
139
140#ifdef USE_FASTCGI
141#include "fcgiapp.h"
142#endif
143
[387]144
[144]145#ifdef USE_FASTCGI
146// used to output the text from receptionist
147class fcgistreambuf : public streambuf {
148public:
149 fcgistreambuf ();
150 int sync ();
151 int overflow (int ch);
152 int underflow () {return EOF;}
153
154 void fcgisbreset() {fcgx_stream = NULL; other_ostream = NULL;};
155 void set_fcgx_stream(FCGX_Stream *newone) {fcgx_stream=newone;};
156 void set_other_ostream(ostream *newone) {other_ostream=newone;};
157
158private:
159 FCGX_Stream *fcgx_stream;
160 ostream *other_ostream;
161};
162
163fcgistreambuf::fcgistreambuf() {
164 fcgisbreset();
165 if (base() == ebuf()) allocate();
166 setp (base(), ebuf());
167};
168
169int fcgistreambuf::sync () {
170 if ((fcgx_stream != NULL) &&
171 (FCGX_PutStr (pbase(), out_waiting(), fcgx_stream) < 0)) {
172 fcgx_stream = NULL;
173 }
174
175 if (other_ostream != NULL) {
176 char *thepbase=pbase();
177 for (int i=0;i<out_waiting();i++) (*other_ostream).put(thepbase[i]);
178 }
179
180 setp (pbase(), epptr());
181
182 return 0;
183}
184
185int fcgistreambuf::overflow (int ch) {
186 if (sync () == EOF) return EOF;
187 if (ch != EOF) sputc (ch);
188 return 0;
189}
190
191#endif
192
193
[963]194static void page_errorsitecfg (text_t &errorpage, int mode) {
[155]195 errorpage += "Content-type: text/html\n\n";
[144]196
[155]197 errorpage += "<html>\n";
198 errorpage += "<head>\n";
199 errorpage += "<title>Error</title>\n";
200 errorpage += "</head>\n";
201 errorpage += "<body>\n";
202 errorpage += "<h2>Oops!</h2>\n";
[963]203 if (mode == 0) {
204 errorpage += "The gsdlsite.cfg configuration file could not be found. This file\n";
205 errorpage += "should contain configuration information relating to this\n";
206 errorpage += "site's setup.\n";
207 errorpage += "gsdlsite.cfg should reside in the same directory as this executable\n";
208 } else if (mode == 1) {
209 errorpage += "The gsdlsite.cfg configuration file does not contain a valid gsdlhome\n";
210 errorpage += "entry.\n";
211 errorpage += "gsdlsite.cfg resides in the same directory as this executable\n";
[155]212 }
213 errorpage += "</body>\n";
214 errorpage += "</html>\n";
215}
[144]216
[155]217
218static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection,
219 text_t &errorpage) {
220 errorpage += "Content-type: text/html\n\n";
221
222 errorpage += "<html>\n";
223 errorpage += "<head>\n";
224 errorpage += "<title>Error</title>\n";
225 errorpage += "</head>\n";
226 errorpage += "<body>\n";
227 errorpage += "<h2>Oops!</h2>\n";
[144]228 if (collection.empty()) {
[963]229 text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
[155]230 errorpage += "The main.cfg configuration file could not be found. This file\n";
231 errorpage += "should contain configuration information relating to the\n";
232 errorpage += "setup of the interface. As this cgi script is not being run\n";
233 errorpage += "in collection specific mode the file should reside at\n";
[963]234 errorpage += main_cfg_file + ".\n";
[144]235 } else {
[963]236 text_t collect_cfg_file = filename_cat (gsdlhome, "collect", collection, "etc", "collect.cfg");
237 text_t main_collect_cfg_file = filename_cat (gsdlhome, "etc", "collect.cfg");
238 text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
239 errorpage += "Either the collect.cfg or main.cfg configuration file could\n";
[155]240 errorpage += "not be found. This file should contain configuration information\n";
241 errorpage += "relating to the setup of the interface. As this cgi script is\n";
242 errorpage += "being run in collection specific mode the file should reside\n";
243 errorpage += "at either ";
[963]244 errorpage += collect_cfg_file + ",\n";
245 errorpage += main_collect_cfg_file + " or " + main_cfg_file + ".\n";
[144]246 }
[155]247 errorpage += "</body>\n";
248 errorpage += "</html>\n";
[144]249}
250
251
[963]252static void page_errorinit (const text_t &gsdlhome, text_t &errorpage) {
[155]253 errorpage += "Content-type: text/html\n\n";
[150]254
[155]255 errorpage += "<html>\n";
256 errorpage += "<head>\n";
257 errorpage += "<title>Error</title>\n";
258 errorpage += "</head>\n";
259 errorpage += "<body>\n";
260 errorpage += "<h2>Oops!</h2>\n";
261 errorpage += "An error occurred during the initialisation of the Greenstone Digital\n";
262 errorpage += "Library software. It is likely that the software has not been setup\n";
263 errorpage += "correctly.\n";
[144]264
[963]265 text_t init_file = filename_cat (gsdlhome, "etc", "initout.txt");
266 char *ifile = init_file.getcstr();
267 ifstream initin (ifile);
268 delete ifile;
[155]269 if (initin) {
[963]270 errorpage += "The initialisation error log, " + init_file + ", contains the\n";
[155]271 errorpage += "following information:\n\n";
272 errorpage += "<pre>\n";
273
274 char c;
275 initin.get(c);
276 while (!initin.eof ()) {
277 errorpage.push_back(c);
278 initin.get(c);
279 }
280
281 errorpage += "</pre>\n";
282
283 initin.close();
284
[150]285 } else {
[963]286 errorpage += "Please consult " + init_file + " for more information.\n";
[150]287 }
[155]288
289 errorpage += "</body>\n";
290 errorpage += "</html>\n";
[150]291}
292
[963]293static void page_errorparseargs (const text_t &gsdlhome, text_t &errorpage) {
[155]294 errorpage += "Content-type: text/html\n\n";
[150]295
[155]296 errorpage += "<html>\n";
297 errorpage += "<head>\n";
298 errorpage += "<title>Error</title>\n";
299 errorpage += "</head>\n";
300 errorpage += "<body>\n";
301 errorpage += "<h2>Oops!</h2>\n";
302 errorpage += "An error occurred during the parsing of the cgi arguments.\n";
[150]303
[963]304 text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
305 char *efile = error_file.getcstr();
306 ifstream errin (efile);
307 delete efile;
[155]308 if (errin) {
[963]309 errorpage += "The error log, " + error_file + ", contains the\n";
[155]310 errorpage += "following information:\n\n";
311 errorpage += "<pre>\n";
[150]312
[155]313 char c;
314 errin.get(c);
315 while (!errin.eof ()) {
316 errorpage.push_back(c);
317 errin.get(c);
318 }
319 errorpage += "</pre>\n";
320 errin.close();
321
322 } else {
[963]323 errorpage += "Please consult " + error_file + " for more information.\n";
[155]324 }
325
326 errorpage += "</body>\n";
327 errorpage += "</html>\n";
[144]328}
329
[963]330static void page_errorcgipage (const text_t &gsdlhome, text_t &errorpage) {
[155]331 errorpage += "Content-type: text/html\n\n";
[144]332
[155]333 errorpage += "<html>\n";
334 errorpage += "<head>\n";
335 errorpage += "<title>Error</title>\n";
336 errorpage += "</head>\n";
337 errorpage += "<body>\n";
338 errorpage += "<h2>Oops!</h2>\n";
339 errorpage += "An error occurred during the construction of the cgi page.\n";
340
[963]341
342 text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
343 char *efile = error_file.getcstr();
344 ifstream errin (efile);
345 delete efile;
[155]346 if (errin) {
[963]347 errorpage += "The error log, " + error_file + ", contains the\n";
[155]348 errorpage += "following information:\n\n";
349 errorpage += "<pre>\n";
350
351 char c;
352 errin.get(c);
353 while (!errin.eof ()) {
354 errorpage.push_back(c);
355 errin.get(c);
356 }
357 errorpage += "</pre>\n";
358 errin.close();
359
360 } else {
[963]361 errorpage += "Please consult " + error_file + " for more information.\n";
[155]362 }
363
364 errorpage += "</body>\n";
365 errorpage += "</html>\n";
366}
367
368
[144]369// cgiwrapper does everything necessary to output a page
370// using the cgi protocol. If this is being run for a particular
371// collection then "collection" should be set, otherwise it
372// should equal "".
[189]373void cgiwrapper (receptionist &recpt, text_t collection) {
[144]374#ifdef USE_FASTCGI
375 fcgistreambuf outbuf;
376#endif
377
[155]378 // init stuff - we can't output error pages directly with
379 // fastcgi so the pages are stored until we can output them
380 text_t errorpage;
381 outconvertclass text_t2ascii;
[144]382
383 // set defaults
384 int maxrequests = 10000;
[165]385 recpt.configure ("collection", collection);
386 recpt.configure ("httpimg", "/gsdl/images");
[144]387 char *script_name = getenv("SCRIPT_NAME");
[165]388 if (script_name != NULL) recpt.configure("gwcgi", script_name);
389 else recpt.configure("gwcgi", "/cgi-bin/gw");
[144]390
[150]391 // read in the configuration files.
[963]392 text_t gsdlhome;
393 if (!site_cfg_read (recpt, gsdlhome, maxrequests)) {
[150]394 // couldn't find the site configuration file
[963]395 page_errorsitecfg (errorpage, 0);
396 } else if (gsdlhome.empty()) {
397 // no gsdlhome in gsdlsite.cfg
398 page_errorsitecfg (errorpage, 1);
399 } else if (!main_cfg_read (recpt, gsdlhome, collection)) {
[150]400 // couldn't find the main configuration file
[963]401 page_errormaincfg (gsdlhome, collection, errorpage);
[144]402 }
403
404 // initialise the library software
[155]405 if (errorpage.empty()) {
[963]406 text_t init_file = filename_cat (gsdlhome, "etc", "initout.txt");
407 char *iout = init_file.getcstr();
408 ofstream initout (iout);
409 delete iout;
[155]410 if (!recpt.init(initout)) {
411 // an error occurred during the initialisation
412 initout.close();
[963]413 page_errorinit(gsdlhome, errorpage);
[155]414 }
[144]415 initout.close();
416 }
417
418 // find out whether this is being run as a cgi-script
419 // or a fastcgi script
420 int numrequests = 0;
421#ifdef USE_FASTCGI
422 int isfastcgi = !FCGX_IsCGI();
423 FCGX_Stream *fcgiin, *fcgiout, *fcgierr;
424 FCGX_ParamArray fcgienvp;
425#else
426 int isfastcgi = 0;
427#endif
428
429 // get the query string if it is not being run as a fastcgi
430 // script
431 text_t argstr = "";
[155]432 cgiargsclass args;
[144]433 char *aURIStr;
434 if (!isfastcgi) {
[365]435 char *request_method_str = getenv("REQUEST_METHOD");
436 char *content_length_str = getenv("CONTENT_LENGTH");
437 if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
[508]438 content_length_str != NULL) {
[365]439 // POST form data
[387]440 int content_length = text_t(content_length_str).getint();
[508]441 if (content_length > 0) {
442 char c;
443 do {
444 cin.get(c);
445 if (cin.eof()) break;
446 argstr.push_back (c);
447 content_length--;
448 } while (content_length > 0);
[365]449 }
450
451 } else {
452 aURIStr = getenv("QUERY_STRING");
[508]453 if ((request_method_str != NULL && strcmp(request_method_str, "GET") == 0)
454 || aURIStr != NULL) {
[365]455 // GET form data
[508]456 if (aURIStr != NULL) argstr = aURIStr;
[365]457 } else {
458 // debugging from command line
459 char cinURIStr[1024];
460 cin.get(cinURIStr, 1024);
461 argstr = cinURIStr;
462 }
[144]463 }
[365]464
465 // cgi scripts only deal with one request
[144]466 maxrequests = 1;
467 }
468
469 // Page-request loop. If this is not being run as a fastcgi
470 // process then only one request will be processed and then
471 // the process will exit.
472 while (numrequests < maxrequests) {
473#ifdef USE_FASTCGI
474 if (isfastcgi) {
475 if (FCGX_Accept(&fcgiin, &fcgiout, &fcgierr, &fcgienvp) < 0) break;
476 aURIStr = FCGX_GetParam("QUERY_STRING", fcgienvp);
477 if (aURIStr != NULL) argstr = aURIStr;
478 else argstr = "";
479 }
480#endif
481
482 // get output streams ready
483#ifdef USE_FASTCGI
484 outbuf.fcgisbreset ();
485 if (isfastcgi) outbuf.set_fcgx_stream (fcgiout);
486 else outbuf.set_other_ostream (&cout);
487 ostream pageout (&outbuf);
488#else
489#define pageout cout
490#endif
[155]491
[872]492 // if using fastcgi we'll load environment into a map,
493 // otherwise simply pass empty map (can't get environment
494 // variables using getenv() while using FCGX versions
495 // of fastcgi - at least I can't ;-) - Stefan)
496 text_tmap fastcgienv;
497#ifdef USE_FASTCGI
498 if (isfastcgi) {
499 for(; *fcgienvp != NULL; fcgienvp++) {
500 text_t fvalue = *fcgienvp;
501 text_t::const_iterator begin = fvalue.begin();
502 text_t::const_iterator end = fvalue.end();
503 text_t::const_iterator equals_sign = findchar (begin, end, '=');
504 if (equals_sign != end)
505 fastcgienv[substr(begin, equals_sign)] = substr(equals_sign+1, end);
506 }
507 }
508#endif
509
510 // temporarily need to configure gwcgi here when using fastcgi as I can't
511 // get it to pass the SCRIPT_NAME environment variable to the initial
512 // environment (if anyone can work out how to do this using the apache
513 // server, let me know). Note that this overrides the gwcgi field in
514 // site.cfg (which it shouldn't do) but I can't at present set gwcgi
515 // from site.cfg as I have old receptionists laying around that wouldn't
516 // appreciate it. The following 5 lines of code should be deleted once
517 // I either a: get the server to pass SCRIPT_NAME at initialization
518 // time or b: convert all the collections using old receptionists over
519 // to this version and uncomment gwcgi in the site.cfg file -- Stefan.
520#ifdef USE_FASTCGI
521 if (isfastcgi) {
522 recpt.configure("gwcgi", fastcgienv["SCRIPT_NAME"]);
523 }
524#endif
525
526
[155]527 if (errorpage.empty()) {
[963]528 text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
529 char *eout = error_file.getcstr();
530 ofstream errout (eout);
531 delete eout;
[155]532 cerr = errout;
[144]533
[155]534 // parse the cgi arguments and produce the resulting page if there
535 // has been no errors so far
[872]536 if (!recpt.parse_cgi_args (argstr, args, errout, fastcgienv)) {
[155]537 errout.close ();
[963]538 page_errorparseargs(gsdlhome, errorpage);
[155]539 } else {
[872]540 if (!recpt.produce_cgi_page (args, pageout, errout, fastcgienv)) {
[155]541 errout.close ();
[963]542 page_errorcgipage(gsdlhome, errorpage);
[155]543 } else {
544 errout.close ();
545 }
[872]546 recpt.log_cgi_args (args, errout, fastcgienv);
[155]547 }
548 }
549 // there was an error, output the error page
550 if (!errorpage.empty()) {
551 pageout << text_t2ascii << errorpage;
552 errorpage.clear();
553 numrequests = maxrequests; // make this the last page
554 }
555 pageout << flush;
[144]556
557 // finish with the output streams
558#ifdef USE_FASTCGI
559 if (isfastcgi) FCGX_Finish();
560#endif
561
562 numrequests++;
563 }
564
565 return;
566}
567
Note: See TracBrowser for help on using the repository browser.