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

Last change on this file since 388 was 387, checked in by rjmcnab, 25 years ago

Fixed a small bug in the POST implementation.

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