source: gsdl/trunk/src/w32server/cgiwrapper.cpp@ 16320

Last change on this file since 16320 was 16320, checked in by davidb, 16 years ago

Introduction of 'collecthome' to support collections outside of the gsdlhome area

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/**********************************************************************
2 *
3 * cgiwrapper.cpp -- windows local library cgiwrapper
4 * Copyright (C) 1999 The New Zealand Digital Library Project
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 "text_t.h"
27
28#include <windows.h>
29#include <string.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <direct.h>
34#include "cgiwrapper.h"
35#include "netio.h"
36#include "wincgiutils.h"
37#include "settings.h"
38#include "fileutil.h"
39#include "parse.h"
40
41#include "gsdlconf.h"
42#include "maincfg.h"
43
44#if defined (GSDL_USE_OBJECTSPACE)
45#include <ospace\std\iostream>
46#include <ospace\std\fstream>
47#elif defined (GSDL_USE_IOS_H)
48#include <iostream.h>
49#include <fstream.h>
50#else
51#include <iostream>
52#include <fstream>
53#endif
54
55#include "receptionist.h"
56#include "nullproto.h"
57
58// actions
59#include "statusaction.h"
60#include "pageaction.h"
61#include "pingaction.h"
62#include "queryaction.h"
63#include "documentaction.h"
64#include "dynamicclassifieraction.h"
65#include "tipaction.h"
66#include "authenaction.h"
67#include "usersaction.h"
68#include "userdb.h"
69#include "extlinkaction.h"
70#include "collectoraction.h"
71#include "phindaction.h"
72#include "configaction.h"
73
74// browsers
75#include "vlistbrowserclass.h"
76#include "hlistbrowserclass.h"
77#include "datelistbrowserclass.h"
78#include "invbrowserclass.h"
79#include "pagedbrowserclass.h"
80#include "htmlbrowserclass.h"
81#include "phindbrowserclass.h"
82
83// the number of times the library has been accessed
84int libaccessnum = 0;
85
86// used to output the text from receptionist
87class textstreambuf : public streambuf
88{
89public:
90 textstreambuf ();
91 int sync ();
92 int overflow (int ch);
93 int underflow () {return EOF;}
94
95 void tsbreset() {RInfo=NULL;casostr=NULL;}
96 void setrequestinfo (RequestInfoT *theRInfo) {RInfo=theRInfo;}
97 void cascadeoutput (ostream *thecasostr) {casostr=thecasostr;}
98
99private:
100 RequestInfoT *RInfo;
101 ostream *casostr;
102#if !defined (GSDL_USE_IOS_H)
103 char buffer[256];
104#endif
105};
106
107textstreambuf::textstreambuf() {
108 tsbreset();
109#if !defined (GSDL_USE_IOS_H)
110 setp (&buffer[0], &buffer[255]);
111#else
112 if (base() == ebuf()) allocate();
113 setp (base(), ebuf());
114#endif
115};
116
117int textstreambuf::sync () {
118 if ((RInfo != NULL) &&
119 (Send_String_N(pbase(), pptr()-pbase(), RInfo) < 0)) {
120 RInfo = NULL;
121 }
122
123 if (casostr != NULL) {
124 char *thepbase=pbase();
125 for (int i=0;i<(pptr()-pbase());++i) (*casostr).put(thepbase[i]);
126 }
127
128 setp (pbase(), epptr());
129
130 return 0;
131}
132
133int textstreambuf::overflow (int ch) {
134 if (sync () == EOF) return EOF;
135 if (ch != EOF) sputc (ch);
136 return 0;
137}
138
139
140// used to output all the log and error messages
141// from receptionist
142class logstreambuf : public streambuf
143{
144public:
145 logstreambuf ();
146 int sync ();
147 int overflow (int ch);
148 int underflow () {return EOF;}
149
150#if !defined (GSDL_USE_IOS_H)
151private:
152 char buffer[256];
153#endif
154};
155
156logstreambuf::logstreambuf () {
157#if !defined (GSDL_USE_IOS_H)
158 setp (&buffer[0], &buffer[255]);
159#else
160 if (base() == ebuf()) allocate();
161 setp (base(), ebuf());
162#endif
163}
164
165int logstreambuf::sync () {
166 if (gsdl_keep_log || gsdl_show_console) {
167 log_message ("LOCAL LIB MESSAGE: ");
168 log_message_N (pbase(), pptr()-pbase());
169 }
170
171 setp (pbase(), epptr());
172 return 0;
173}
174
175int logstreambuf::overflow (int ch) {
176 if (sync () == EOF) return EOF;
177 if (ch != EOF) sputc (ch);
178 return 0;
179}
180
181static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection) {
182
183 if (collection.empty()) {
184 text_t message = "Error\n\n"
185 "The main.cfg configuration file could not be found. This file\n"
186 "should contain configuration information relating to the\n"
187 "setup of the interface. As this program is not being run\n"
188 "in collection specific mode the file should reside at\n" +
189 gsdlhome + "\\etc\\main.cfg.\n";
190
191 MessageBox(NULL, message.getcstr(),
192 "Greenstone Digital Library Software"
193 ,MB_OK|MB_SYSTEMMODAL);
194 } else {
195 text_t message = "Neither the collect.cfg or main.cfg configuration files could\n"
196 "be found. This file should contain configuration information\n"
197 "relating to the setup of the interface. As this cgi script is\n"
198 "being run in collection specific mode the file should reside\n"
199 "at either " + gsdlhome + "\\collect\\" + collection + "\\etc\\collect.cfg,\n" +
200 gsdlhome + "\\etc\\collect.cfg or " + gsdlhome + "\\etc\\main.cfg.\n";
201
202 MessageBox(NULL, message.getcstr(),
203 "Greenstone Digital Library Software"
204 ,MB_OK|MB_SYSTEMMODAL);
205 }
206}
207
208static void page_errorinit (const text_t &/*gsdlhome*/) {
209
210 text_t message = "Error\n\n"
211 "An error occurred during the initialisation of the Greenstone Digital\n"
212 "Library software. It is likely that the software has not been setup\n"
213 "correctly.\n";
214
215 MessageBox(NULL, message.getcstr(),
216 "Greenstone Digital Library Software"
217 ,MB_OK|MB_SYSTEMMODAL);
218}
219
220static void page_errorparseargs (const text_t &/*gsdlhome*/) {
221
222 text_t message = "Error\n\n"
223 "An error occurred during the parsing of the cgi arguments.\n";
224
225 MessageBox(NULL, message.getcstr(),
226 "Greenstone Digital Library Software"
227 ,MB_OK|MB_SYSTEMMODAL);
228}
229
230static void page_errorcgipage (const text_t &/*gsdlhome*/) {
231
232 text_t message = "Error\n\n"
233 "An error occurred during the construction of the cgi page.\n";
234
235 MessageBox(NULL, message.getcstr(),
236 "Greenstone Digital Library Software"
237 ,MB_OK|MB_SYSTEMMODAL);
238}
239
240// returns 0 if the directories can't be found
241// and the user wants to quit (it returns 1
242// if everything is ok)
243int checkdir (const text_t &thedir) {
244 UINT curerrormode;
245 int drive = _getdrive();
246 char cwd[1024];
247 char rootpath[4];
248 UINT drivetype;
249 char *cstrthedir = thedir.getcstr();
250 int returnvalue = 1;
251
252 // make sure no rude error messages are presented to the user
253 curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
254
255 // get the drive name
256 if (thedir.size() >= 2 && thedir[1] == ':') {
257 if (thedir[0] >= 'a' && thedir[0] <= 'z') {
258 drive = thedir[0] - 'a' + 1;
259
260 } else if (thedir[0] >= 'A' && thedir[0] <= 'Z') {
261 drive = thedir[0] - 'A' + 1;
262 }
263 }
264
265 // find the drive type
266 rootpath[0] = drive + 'A' - 1;
267 rootpath[1] = ':';
268 rootpath[2] = '\\';
269 rootpath[3] = '\0';
270 drivetype = GetDriveType (rootpath);
271
272 // try and set this directory to be the current working
273 // directory
274 _getcwd(cwd, 1024);
275 while (_chdir(cstrthedir) != 0) {
276 // failed
277 if (drivetype == DRIVE_CDROM) {
278 // message to insert the cdrom
279 if (MessageBox (NULL,
280 "Please insert the Greenstone Digital Library\n"
281 "CD-ROM into the CD-ROM drive and press 'OK'.\n\n"
282 "If you don't have the CD-ROM press 'Cancel' to exit\n"
283 "this program.", "Greenstone Digital Library Software",
284 MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL) {
285
286 returnvalue = 0;
287 break;
288 }
289
290 } else {
291 // message saying that the system was unable
292 // to find a certain directory
293 text_t message = "Failed to find the directory:\n\n" + thedir;
294 message += "\n\n"
295 "This directory is needed for the successful operation\n"
296 "of this software. Make sure it hasn't been deleted or\n"
297 "moved, and restart the software. You may need to\n"
298 "reinstall this software to correct the problem.";
299 char *cstrmessage = message.getcstr();
300
301 MessageBox (NULL, cstrmessage, "Greenstone Digital Library Software",
302 MB_OK | MB_TASKMODAL);
303
304 delete []cstrmessage;
305
306 returnvalue = 0;
307 break;
308 }
309 }
310
311 // revert to the previous error and cwd states
312 _chdir(cwd);
313 SetErrorMode(curerrormode);
314
315 // free the allocated C string
316 delete []cstrthedir;
317
318 return returnvalue;
319}
320
321
322// c-string version of checkdir for the outside
323// world
324int cstrcheckdir (char *cstrthedir) {
325 return checkdir (cstrthedir);
326}
327
328
329receptionist recpt;
330nullproto nproto;
331collectset *cservers = NULL;
332
333textstreambuf textstream;
334logstreambuf logstream;
335DWORD lastlibaccesstime;
336DWORD baseavailvirtual;
337text_t current_gsdlhome;
338colinfo_tmap translated_collectinfo;
339
340statusaction *astatusaction = NULL;
341pageaction *apageaction = NULL;
342pingaction *apingaction = NULL;
343tipaction *atipaction = NULL;
344queryaction *aqueryaction = NULL;
345documentaction *adocumentaction = NULL;
346dynamicclassifieraction *adynamicclassifieraction = NULL;
347usersaction *ausersaction = NULL;
348extlinkaction *anextlinkaction = NULL;
349collectoraction *acollectoraction = NULL;
350authenaction *aauthenaction = NULL;
351phindaction *aphindaction = NULL;
352configaction *aconfigaction = NULL;
353vlistbrowserclass *avlistbrowserclass = NULL;
354hlistbrowserclass *ahlistbrowserclass = NULL;
355datelistbrowserclass *adatelistbrowserclass = NULL;
356invbrowserclass *ainvbrowserclass = NULL;
357pagedbrowserclass *apagedbrowserclass = NULL;
358htmlbrowserclass *ahtmlbrowserclass = NULL;
359phindbrowserclass *aphindbrowserclass = NULL;
360text_t userdbfile = NULL;
361userdbclass *udb = NULL;
362text_t keydbfile = NULL;
363keydbclass *kdb = NULL;
364
365// returns 1 if successful, 0 if unsuccessful (note that as well as being
366// called when the server first starts up this function is called when the
367// "restart library" button is pressed)
368int gsdl_init (bool atStartup) {
369
370 if (atStartup) {
371#if defined (GSDL_USE_IOS_H)
372 cerr = &logstream;
373 cout = &textstream;
374#else
375 cerr.rdbuf(&logstream);
376 cout.rdbuf(&textstream);
377#endif
378 }
379
380 // collection should be set to "" unless in collection specific mode -
381 // changing this to the name of the collection should be all that's
382 // required to create a collection specific receptionist
383 text_t collection = "";
384 text_tset dbhomes;
385 text_tset collections;
386
387 if (atStartup) {
388 // note the current time
389 lastlibaccesstime = GetTickCount();
390
391 // before we do the init we should make sure
392 // that we can find the relevant directories
393 if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
394 if (!checkdir (gsdl_collecthome + "\\")) return 0;
395 if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
396 }
397
398 // deleting cservers clears all the collection servers
399 if (cservers != NULL) delete cservers;
400
401 cservers = new collectset();
402
403 // get all collections from each gsdlhome (this relies
404 // on there not being more than one collection with the same
405 // name)
406 if (!collection.empty()) {
407 // collection specific receptionist - one collection, one gsdlhome
408 collections.insert (collection);
409 dbhomes.insert (gsdl_dbhome);
410 collectioninfo_t tmp;
411 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
412 tmp.gsdl_collecthome = gsdl_collecthome;
413 tmp.gsdl_dbhome = gsdl_dbhome;
414 translated_collectinfo[collection] = tmp;
415
416 } else {
417
418 text_tset::const_iterator colhere;
419 text_tset::const_iterator colend;
420 text_tset these_collections;
421
422 // first volume gsdlhome's
423 colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
424 colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
425 while (this_info != end_info) {
426 if (dbhomes.find ((*this_info).second.gsdl_dbhome) == dbhomes.end()) {
427 these_collections.erase (these_collections.begin(), these_collections.end());
428 read_dir ((*this_info).second.gsdl_collecthome, these_collections);
429 colhere = these_collections.begin();
430 colend = these_collections.end();
431 while (colhere != colend) {
432 if ((collections.find (*colhere)) == collections.end()) {
433 // make sure the build.cfg file is at gsdlhome (as it's possible that
434 // the collection appears at this gsdlhome only because it's gdbm
435 // file is installed here -- it's real gdbm will therefore be
436 // somewhere else).
437 text_t build_cfg = filename_cat ((*this_info).second.gsdl_collecthome,
438 *colhere, "index", "build.cfg");
439 if (file_exists (build_cfg)) {
440 collections.insert (*colhere);
441
442 // since gsdl_collectinfo keys will be stuff like collection#1
443 // for a multiple volume collection we want to translate it
444 // so that the keys are the actual collection names
445 translated_collectinfo[*colhere] = (*this_info).second;
446 }
447 }
448 ++colhere;
449 }
450 dbhomes.insert ((*this_info).second.gsdl_dbhome);
451 }
452 ++this_info;
453 }
454
455 // then if necessary the main dbhome (this should only happen if the
456 // gsdl.ini is a little screwed up and no volume dbhomes occurred)
457 if (dbhomes.find (gsdl_dbhome) == dbhomes.end()) {
458 these_collections.erase (these_collections.begin(), these_collections.end());
459 read_dir (filename_cat (gsdl_dbhome, "collect"), these_collections);
460 colhere = these_collections.begin();
461 colend = these_collections.end();
462 while (colhere != colend) {
463 collections.insert (*colhere);
464 collectioninfo_t tmp;
465 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
466 tmp.gsdl_collecthome = gsdl_collecthome;
467 tmp.gsdl_dbhome = gsdl_dbhome;
468 translated_collectinfo[*colhere] = tmp;
469 ++colhere;
470 }
471 dbhomes.insert (gsdl_dbhome);
472 }
473 }
474
475 text_tset::const_iterator thiscol = collections.begin();
476 text_tset::const_iterator endcol = collections.end();
477
478 while (thiscol != endcol) {
479
480 // ignore the modelcol
481 if (*thiscol == "modelcol") {
482 ++thiscol;
483 continue;
484 }
485
486 // create collection server and add to null protocol
487 text_t this_gsdlhome = gsdl_gsdlhome;
488 text_t this_collecthome = gsdl_collecthome;
489 text_t this_dbhome = gsdl_dbhome;
490 colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
491 assert (it != translated_collectinfo.end());
492 this_gsdlhome = (*it).second.gsdl_gsdlhome;
493 this_collecthome = (*it).second.gsdl_collecthome;
494 this_dbhome = (*it).second.gsdl_dbhome;
495
496 cservers->add_collection (*thiscol, this_gsdlhome, this_collecthome);
497
498 ++thiscol;
499 }
500
501 // set up the null protocol
502 nproto.set_collectset(cservers);
503
504 if ((ausersaction == NULL) && (aauthenaction == NULL)){
505 userdbfile = filename_cat(gsdl_gsdlhome, "etc", "users.db");
506 udb = new userdbclass(userdbfile);
507 keydbfile = filename_cat(gsdl_gsdlhome, "etc", "key.db");
508 kdb = new keydbclass(keydbfile);
509 }
510 // add the protocol to the receptionist
511 if (atStartup) recpt.add_protocol (&nproto);
512
513 // the list of actions.
514 if (astatusaction == NULL) {
515 astatusaction = new statusaction();
516 astatusaction->set_receptionist (&recpt);
517 recpt.add_action (astatusaction);
518 }
519
520 if (apageaction == NULL) {
521 apageaction = new pageaction();
522 apageaction->set_receptionist (&recpt);
523 recpt.add_action (apageaction);
524 }
525
526 if (apingaction == NULL) {
527 apingaction = new pingaction();
528 recpt.add_action (apingaction);
529 }
530
531 if (atipaction == NULL) {
532 atipaction = new tipaction();
533 recpt.add_action (atipaction);
534 }
535
536 if (aqueryaction == NULL) {
537 aqueryaction = new queryaction();
538 aqueryaction->set_receptionist (&recpt);
539 recpt.add_action (aqueryaction);
540 }
541
542 if (adocumentaction == NULL) {
543 adocumentaction = new documentaction();
544 adocumentaction->set_receptionist (&recpt);
545 recpt.add_action (adocumentaction);
546 }
547
548 if (ausersaction == NULL) {
549 ausersaction = new usersaction();
550 ausersaction->set_userdb(udb);
551 recpt.add_action (ausersaction);
552 }
553
554 if (anextlinkaction == NULL) {
555 anextlinkaction = new extlinkaction();
556 recpt.add_action (anextlinkaction);
557 }
558
559 if (acollectoraction == NULL) {
560 acollectoraction = new collectoraction();
561 acollectoraction->set_receptionist (&recpt);
562 recpt.add_action (acollectoraction);
563 }
564
565 if (aauthenaction == NULL) {
566 aauthenaction = new authenaction();
567 aauthenaction->set_userdb(udb);
568 aauthenaction->set_keydb(kdb);
569 aauthenaction->set_receptionist(&recpt);
570 recpt.add_action (aauthenaction);
571 }
572
573 if (aphindaction == NULL) {
574 aphindaction = new phindaction();
575 recpt.add_action (aphindaction);
576 }
577
578 if (aconfigaction == NULL) {
579 aconfigaction = new configaction();
580 aconfigaction->set_receptionist(&recpt);
581 recpt.add_action (aconfigaction);
582 }
583
584 if (adynamicclassifieraction == NULL) {
585 adynamicclassifieraction = new dynamicclassifieraction();
586 adynamicclassifieraction->set_receptionist(&recpt);
587 recpt.add_action (adynamicclassifieraction);
588 }
589
590
591 // list of browsers
592 if (avlistbrowserclass == NULL) {
593 avlistbrowserclass = new vlistbrowserclass();
594 recpt.add_browser (avlistbrowserclass);
595 recpt.setdefaultbrowser ("VList");
596 }
597
598 if (ahlistbrowserclass == NULL) {
599 ahlistbrowserclass = new hlistbrowserclass();
600 recpt.add_browser (ahlistbrowserclass);
601 }
602
603 if (adatelistbrowserclass == NULL) {
604 adatelistbrowserclass = new datelistbrowserclass();
605 recpt.add_browser (adatelistbrowserclass);
606 }
607
608 if (ainvbrowserclass == NULL) {
609 ainvbrowserclass = new invbrowserclass();
610 recpt.add_browser (ainvbrowserclass);
611 }
612
613 if (apagedbrowserclass == NULL) {
614 apagedbrowserclass = new pagedbrowserclass();
615 recpt.add_browser (apagedbrowserclass);
616 }
617
618 if (ahtmlbrowserclass == NULL) {
619 ahtmlbrowserclass = new htmlbrowserclass();
620 recpt.add_browser (ahtmlbrowserclass);
621 }
622
623 if (aphindbrowserclass == NULL) {
624 aphindbrowserclass = new phindbrowserclass();;
625 recpt.add_browser (aphindbrowserclass);
626 }
627
628 // set defaults
629 recpt.configure ("gsdlhome", gsdl_gsdlhome);
630 recpt.configure ("collecthome", gsdl_collecthome);
631 recpt.configure ("gdbmhome", gsdl_dbhome);
632 recpt.configure ("collection", collection);
633
634 int maxrequests = 1;
635
636 // configure collections (and receptionist) with collectinfo stuff
637 // different from the default
638 colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
639 colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
640
641 while (this_info != end_info) {
642 text_tarray tmpconf;
643 tmpconf.push_back ((*this_info).first);
644 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
645 tmpconf.push_back ((*this_info).second.gsdl_collecthome);
646 tmpconf.push_back ((*this_info).second.gsdl_dbhome);
647 recpt.configure ("collectinfo", tmpconf);
648 ++this_info;
649 }
650
651 // read in config files of each dbhome (in no particular order)
652 // those read in last will override those read earlier
653 // collections being used together in this way should be
654 // careful not to have main.cfg files that might
655 // interfere with each other.
656 text_tset::const_iterator thome = dbhomes.begin();
657 text_tset::const_iterator ehome = dbhomes.end();
658 while (thome != ehome) {
659 if (!main_cfg_read (recpt, *thome, collection)) {
660 // couldn't find the main configuration file
661 page_errormaincfg (*thome, collection);
662 return 0;
663 }
664 ++thome;
665 }
666
667 // w32server relies on gwcgi being set to "gsdl"
668 recpt.configure ("gwcgi", "gsdl");
669
670 // initialise the library software
671 if (!recpt.init(cerr)) {
672 // an error occurred during the initialisation
673 page_errorinit(gsdl_gsdlhome);
674 return 0;
675 }
676
677 // get memory information
678 MEMORYSTATUS memstatus;
679 memstatus.dwLength = sizeof(MEMORYSTATUS);
680 GlobalMemoryStatus(&memstatus);
681 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
682
683 return 1;
684}
685
686
687static void rememberpref (const text_t &tailstr) {
688 gsdl_enterlib = tailstr;
689}
690
691
692static void send_file_from_disk(text_t filename,
693 RequestInfoT *RInfo,
694 RequestFieldsT *RFields) {
695
696 // select appropriate mime type from file extension
697 text_t ext;
698 text_t::const_iterator end = filename.end();
699 text_t::const_iterator it = filename.begin();
700 text_t::const_iterator lastdot = end;
701 while ((it = findchar(it, end, '.')) != end) {
702 lastdot = it;
703 ++it;
704 }
705 if (lastdot < end) ext = substr(lastdot+1, end);
706
707 text_t mime = "unknown";
708 int len = ext.size();
709 if (len == 2) {
710 if ((ext[0] == 'p' || ext[0] == 'P') &&
711 (ext[1] == 's' || ext[1] == 'S'))
712 mime = "application/postscript";
713 } else if (len == 3) {
714 if ((ext[0] == 'g' || ext[0] == 'G') &&
715 (ext[1] == 'i' || ext[1] == 'I') &&
716 (ext[2] == 'f' || ext[2] == 'F')) {
717 mime = "image/gif";
718 } else if ((ext[0] == 'j' || ext[0] == 'J') &&
719 (ext[1] == 'p' || ext[1] == 'P') &&
720 (ext[2] == 'g' || ext[2] == 'G')) {
721 mime = "image/jpeg";
722 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
723 (ext[1] == 't' || ext[1] == 'T') &&
724 (ext[2] == 'm' || ext[2] == 'M')) {
725 mime = "text/html";
726 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
727 (ext[1] == 'd' || ext[1] == 'D') &&
728 (ext[2] == 'f' || ext[2] == 'F')) {
729 mime = "application/pdf";
730 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
731 (ext[1] == 'n' || ext[1] == 'N') &&
732 (ext[2] == 'g' || ext[2] == 'G')) {
733 mime = "image/png";
734 } else if ((ext[0] == 'd' || ext[0] == 'D') &&
735 (ext[1] == 'o' || ext[1] == 'O') &&
736 (ext[2] == 'c' || ext[2] == 'C')) {
737 mime = "application/msword";
738 } else if ((ext[0] == 'r' || ext[0] == 'R') &&
739 (ext[1] == 't' || ext[1] == 'T') &&
740 (ext[2] == 'f' || ext[2] == 'F')) {
741 mime = "application/rtf";
742 } else if ((ext[0] == 'x' || ext[0] == 'X') &&
743 (ext[1] == 'l' || ext[1] == 'L') &&
744 (ext[2] == 's' || ext[2] == 'S')) {
745 mime = "application/vnd.ms-excel";
746 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
747 (ext[1] == 'p' || ext[1] == 'P') &&
748 (ext[2] == 'T' || ext[2] == 'T')) {
749 mime = "application/vnd.ms-powerpoint";
750 } else if ((ext[0] == 'm' || ext[0] == 'M') &&
751 (ext[1] == 'p' || ext[1] == 'P') &&
752 (ext[2] == '3')) {
753 mime = "audio/mpeg";
754 }
755 } else if (len == 4) {
756 if ((ext[0] == 'j' || ext[0] == 'J') &&
757 (ext[1] == 'p' || ext[1] == 'P') &&
758 (ext[2] == 'e' || ext[2] == 'E') &&
759 (ext[3] == 'g' || ext[3] == 'G')) {
760 mime = "image/jpeg";
761 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
762 (ext[1] == 't' || ext[1] == 'T') &&
763 (ext[2] == 'm' || ext[2] == 'M') &&
764 (ext[3] == 'l' || ext[3] == 'L')) {
765 mime = "text/html";
766 }
767 }
768
769 // try to open the file
770 filename = filename_cat (current_gsdlhome, filename);
771 /* Feb 2002 - handle files with spaces in their name. */
772 text_t::iterator space_start;
773 space_start=findword(filename.begin(),filename.end(),"%20");
774 while (space_start != filename.end()) {
775 // we found a space...
776 text_t::iterator after_space=space_start+3;
777 text_t new_filename=substr(filename.begin(), space_start);
778 new_filename += " ";
779 new_filename += substr(after_space,filename.end());
780 filename=new_filename;
781 space_start=findword(filename.begin(),filename.end(),"%20");
782 }
783
784 char *filenamec = filename.getcstr();
785 TranslateEscapeString(filenamec); // Resolve any %xx values
786 FILE *thefile = fopen(filenamec, "rb");
787 delete []filenamec;
788 if (thefile == NULL) {
789 log_message("file not found\n");
790 send_retrieve_error(404, "File not found",
791 "Could not find the local file requested", RInfo);
792 return;
793 }
794 int nr;
795 char buffer[2048];
796 // send back required information
797 char *mimec = mime.getcstr();
798 if (send_header(mimec, RInfo) >= 0) {
799 if (RFields->MethodStr != "HEAD") {
800 for (;;) {
801 nr = fread(buffer, 1, 2048, thefile);
802 if (nr <= 0) break;
803 if (SendData(RInfo->ClientSocket,
804 (BYTE *)buffer, nr,
805 RInfo->ThreadNum) < 0) break;
806 }
807 }
808 }
809 delete []mimec;
810 fclose(thefile);
811}
812
813static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
814 RequestFieldsT *RequestFields) {
815
816 // parse the cgi arguments and produce the resulting page if there
817 // have been no errors so far
818 cgiargsclass args;
819 fileupload_tmap fileuploads;
820 text_tmap empty; // don't use this (it's for fastcgi on unix)
821 if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
822 page_errorparseargs(gsdl_gsdlhome);
823 return;
824 }
825
826 colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
827 if (it != translated_collectinfo.end()) {
828 current_gsdlhome = (*it).second.gsdl_gsdlhome;
829 } else {
830 current_gsdlhome = gsdl_gsdlhome;
831 }
832
833 // produce cgi header
834 response_t response;
835 text_t response_data;
836
837 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
838
839 if (response == location) {
840 // location response
841 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
842 char *response_data_c = response_data.getcstr();
843 send_header(response_data_c, RInfo);
844 delete []response_data_c;
845 return;
846 } else if (response == content) {
847 // content response
848 char *response_data_c = response_data.getcstr();
849 if (send_header(response_data_c, RInfo) < 0) {
850 delete []response_data_c;
851 return;
852 }
853 delete []response_data_c;
854 }
855 else if (response == undecided_location) {
856 // We know this is a relocation request but at the moment we don't know exactly where to
857 // Just output the start of the header and wait until later to output the target location
858 // Used for the "I'm feeling lucky" functionality
859 cout << "HTTP/1.0 302 Relocation\r\n";
860 cout << "Server: GSDL\r\n";
861 cout << "Content-type: text/html \r\n";
862 }
863 else {
864 // unknown response
865 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
866 return;
867 }
868
869 textstream.tsbreset();
870 textstream.setrequestinfo (RInfo);
871 if (!recpt.produce_content (args, cout, cerr)) {
872 page_errorcgipage(gsdl_gsdlhome);
873 return;
874 }
875 recpt.log_cgi_args (args, cerr, empty);
876
877 cout << flush;
878 cerr << flush;
879
880 ++libaccessnum;
881}
882
883static void handle_server_request(text_t &tailstr,
884 RequestInfoT *RequestInfo,
885 RequestFieldsT *RequestFields) {
886
887 text_t argstr;
888
889 // do any url adjustments necessary
890 if (tailstr.empty() || tailstr == "/") {
891 tailstr = "/gsdl";
892 }
893
894 text_t::const_iterator begin = tailstr.begin();
895 text_t::const_iterator end = tailstr.end();
896
897 // test to see if this is a library request or a local
898 // file request
899 if ((tailstr == "/gsdl") ||
900 ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
901
902 // library request
903
904 // argstr is the bit after the '?'
905 if (tailstr != "/gsdl") {
906 argstr = substr(begin+6, end);
907 }
908
909 // log the difference in access times
910 DWORD thislibaccesstime = GetTickCount();
911 if (gsdl_keep_log || gsdl_show_console) {
912 char logstr[256];
913 sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
914 log_message (logstr);
915 }
916 lastlibaccesstime = thislibaccesstime;
917
918 // log this request
919 if (gsdl_keep_log || gsdl_show_console) {
920 text_t logstr = "LOCAL LIB: " + tailstr + "\n";
921 char *logstrc = logstr.getcstr();
922 log_message (logstrc);
923 delete []logstrc;
924 }
925
926 handle_library_request (argstr, RequestInfo, RequestFields);
927
928 // remember the preferences
929 // rememberpref (tailstr);
930
931 // log memory information
932 if (gsdl_keep_log || gsdl_show_console) {
933 MEMORYSTATUS memstatus;
934 memstatus.dwLength = sizeof(MEMORYSTATUS);
935 GlobalMemoryStatus(&memstatus);
936 char logstr[256];
937 sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
938 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
939 log_message (logstr);
940 }
941
942 } else {
943 // local file
944 if (gsdl_keep_log || gsdl_show_console) {
945 text_t logstr = "LOCAL FILE: " + tailstr + "\n";
946 char *logstrc = logstr.getcstr();
947 log_message (logstrc);
948 delete []logstrc;
949 }
950 send_file_from_disk (tailstr, RequestInfo, RequestFields);
951 }
952}
953
954int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
955 RequestFieldsT *RequestFields)
956{
957 text_t protocol, machine, rest;
958 int port;
959
960 if (RequestFields->ContentLength > 0) {
961 // POST data
962 URIStr.push_back('?');
963 for (int i = 0; i < RequestFields->ContentLength; ++i) {
964 URIStr.push_back(RequestFields->Content[i]);
965 }
966 }
967
968 if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
969 // Alter local file request to address 'gsdl'
970 if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
971 else URIStr = "http://gsdl" + URIStr;
972 parse_url(URIStr, protocol, machine, &port, rest);
973 }
974
975 if (machine == "gsdl") {
976 // a local file request
977 handle_server_request(rest, RequestInfo, RequestFields);
978
979 } else {
980 send_retrieve_error(404, "File not found",
981 "Could not find the local file requested", RequestInfo);
982 }
983
984 return 1;
985}
Note: See TracBrowser for help on using the repository browser.