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

Last change on this file since 373 was 365, checked in by rjmcnab, 25 years ago

Added ability to receive POST cgi form data.

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