source: gsdl/trunk/runtime-src/src/w32server/cgiwrapper.cpp@ 16975

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

support for /collect in URL pointing to area designated by 'collecthome'

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 29.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;
338text_t current_collecthome;
339colinfo_tmap translated_collectinfo;
340
341statusaction *astatusaction = NULL;
342pageaction *apageaction = NULL;
343pingaction *apingaction = NULL;
344tipaction *atipaction = NULL;
345queryaction *aqueryaction = NULL;
346documentaction *adocumentaction = NULL;
347dynamicclassifieraction *adynamicclassifieraction = NULL;
348usersaction *ausersaction = NULL;
349extlinkaction *anextlinkaction = NULL;
350collectoraction *acollectoraction = NULL;
351authenaction *aauthenaction = NULL;
352phindaction *aphindaction = NULL;
353configaction *aconfigaction = NULL;
354vlistbrowserclass *avlistbrowserclass = NULL;
355hlistbrowserclass *ahlistbrowserclass = NULL;
356datelistbrowserclass *adatelistbrowserclass = NULL;
357invbrowserclass *ainvbrowserclass = NULL;
358pagedbrowserclass *apagedbrowserclass = NULL;
359htmlbrowserclass *ahtmlbrowserclass = NULL;
360phindbrowserclass *aphindbrowserclass = NULL;
361text_t userdbfile = NULL;
362userdbclass *udb = NULL;
363text_t keydbfile = NULL;
364keydbclass *kdb = NULL;
365
366// returns 1 if successful, 0 if unsuccessful (note that as well as being
367// called when the server first starts up this function is called when the
368// "restart library" button is pressed)
369int gsdl_init (bool atStartup) {
370
371 if (atStartup) {
372#if defined (GSDL_USE_IOS_H)
373 cerr = &logstream;
374 cout = &textstream;
375#else
376 cerr.rdbuf(&logstream);
377 cout.rdbuf(&textstream);
378#endif
379 }
380
381 // collection should be set to "" unless in collection specific mode -
382 // changing this to the name of the collection should be all that's
383 // required to create a collection specific receptionist
384 text_t collection = "";
385 text_tset dbhomes;
386 text_tset clhomes; // collecthome companion for dbhome
387 text_tset collections;
388
389 if (atStartup) {
390 // note the current time
391 lastlibaccesstime = GetTickCount();
392
393 // before we do the init we should make sure
394 // that we can find the relevant directories
395 if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
396 if (!checkdir (gsdl_collecthome + "\\")) return 0;
397 if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
398 }
399
400 // deleting cservers clears all the collection servers
401 if (cservers != NULL) delete cservers;
402
403 cservers = new collectset();
404
405 // get all collections from each gsdlhome (this relies
406 // on there not being more than one collection with the same
407 // name)
408 if (!collection.empty()) {
409 // collection specific receptionist - one collection, one gsdlhome
410 collections.insert (collection);
411 dbhomes.insert (gsdl_dbhome);
412 clhomes.insert (gsdl_collecthome);
413 collectioninfo_t tmp;
414 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
415 tmp.gsdl_collecthome = gsdl_collecthome;
416 tmp.gsdl_dbhome = gsdl_dbhome;
417 translated_collectinfo[collection] = tmp;
418
419 } else {
420
421 text_tset::const_iterator colhere;
422 text_tset::const_iterator colend;
423 text_tset these_collections;
424
425 // first volume gsdlhome's
426 colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
427 colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
428 while (this_info != end_info) {
429 if (dbhomes.find ((*this_info).second.gsdl_dbhome) == dbhomes.end()) {
430 these_collections.erase (these_collections.begin(), these_collections.end());
431 read_dir ((*this_info).second.gsdl_collecthome, these_collections);
432 colhere = these_collections.begin();
433 colend = these_collections.end();
434 while (colhere != colend) {
435 if ((collections.find (*colhere)) == collections.end()) {
436 // make sure the build.cfg file is at gsdlhome (as it's possible that
437 // the collection appears at this gsdlhome only because it's gdbm
438 // file is installed here -- it's real gdbm will therefore be
439 // somewhere else).
440 text_t build_cfg = filename_cat ((*this_info).second.gsdl_collecthome,
441 *colhere, "index", "build.cfg");
442 if (file_exists (build_cfg)) {
443 collections.insert (*colhere);
444
445 // since gsdl_collectinfo keys will be stuff like collection#1
446 // for a multiple volume collection we want to translate it
447 // so that the keys are the actual collection names
448 translated_collectinfo[*colhere] = (*this_info).second;
449 }
450 }
451 ++colhere;
452 }
453 dbhomes.insert ((*this_info).second.gsdl_dbhome);
454 clhomes.insert ((*this_info).second.gsdl_collecthome);
455 }
456 ++this_info;
457 }
458
459 // then if necessary the main dbhome (this should only happen if the
460 // gsdl.ini is a little screwed up and no volume dbhomes occurred)
461 if (dbhomes.find (gsdl_dbhome) == dbhomes.end()) {
462 these_collections.erase (these_collections.begin(), these_collections.end());
463 read_dir (filename_cat (gsdl_dbhome, "collect"), these_collections);
464 colhere = these_collections.begin();
465 colend = these_collections.end();
466 while (colhere != colend) {
467 collections.insert (*colhere);
468 collectioninfo_t tmp;
469 tmp.gsdl_gsdlhome = gsdl_gsdlhome;
470 tmp.gsdl_collecthome = gsdl_collecthome;
471 tmp.gsdl_dbhome = gsdl_dbhome;
472 translated_collectinfo[*colhere] = tmp;
473 ++colhere;
474 }
475 dbhomes.insert (gsdl_dbhome);
476 clhomes.insert (gsdl_collecthome);
477 }
478 }
479
480 text_tset::const_iterator thiscol = collections.begin();
481 text_tset::const_iterator endcol = collections.end();
482
483 while (thiscol != endcol) {
484
485 // ignore the modelcol
486 if (*thiscol == "modelcol") {
487 ++thiscol;
488 continue;
489 }
490
491 // create collection server and add to null protocol
492 text_t this_gsdlhome = gsdl_gsdlhome;
493 text_t this_collecthome = gsdl_collecthome;
494 text_t this_dbhome = gsdl_dbhome;
495 colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
496 assert (it != translated_collectinfo.end());
497 this_gsdlhome = (*it).second.gsdl_gsdlhome;
498 this_collecthome = (*it).second.gsdl_collecthome;
499 this_dbhome = (*it).second.gsdl_dbhome;
500
501 cservers->add_collection (*thiscol, this_gsdlhome, this_collecthome);
502
503 ++thiscol;
504 }
505
506 // set up the null protocol
507 nproto.set_collectset(cservers);
508
509 if ((ausersaction == NULL) && (aauthenaction == NULL)){
510 userdbfile = filename_cat(gsdl_gsdlhome, "etc", "users.db");
511 udb = new userdbclass(userdbfile);
512 keydbfile = filename_cat(gsdl_gsdlhome, "etc", "key.db");
513 kdb = new keydbclass(keydbfile);
514 }
515 // add the protocol to the receptionist
516 if (atStartup) recpt.add_protocol (&nproto);
517
518 // the list of actions.
519 if (astatusaction == NULL) {
520 astatusaction = new statusaction();
521 astatusaction->set_receptionist (&recpt);
522 recpt.add_action (astatusaction);
523 }
524
525 if (apageaction == NULL) {
526 apageaction = new pageaction();
527 apageaction->set_receptionist (&recpt);
528 recpt.add_action (apageaction);
529 }
530
531 if (apingaction == NULL) {
532 apingaction = new pingaction();
533 recpt.add_action (apingaction);
534 }
535
536 if (atipaction == NULL) {
537 atipaction = new tipaction();
538 recpt.add_action (atipaction);
539 }
540
541 if (aqueryaction == NULL) {
542 aqueryaction = new queryaction();
543 aqueryaction->set_receptionist (&recpt);
544 recpt.add_action (aqueryaction);
545 }
546
547 if (adocumentaction == NULL) {
548 adocumentaction = new documentaction();
549 adocumentaction->set_receptionist (&recpt);
550 recpt.add_action (adocumentaction);
551 }
552
553 if (ausersaction == NULL) {
554 ausersaction = new usersaction();
555 ausersaction->set_userdb(udb);
556 recpt.add_action (ausersaction);
557 }
558
559 if (anextlinkaction == NULL) {
560 anextlinkaction = new extlinkaction();
561 recpt.add_action (anextlinkaction);
562 }
563
564 if (acollectoraction == NULL) {
565 acollectoraction = new collectoraction();
566 acollectoraction->set_receptionist (&recpt);
567 recpt.add_action (acollectoraction);
568 }
569
570 if (aauthenaction == NULL) {
571 aauthenaction = new authenaction();
572 aauthenaction->set_userdb(udb);
573 aauthenaction->set_keydb(kdb);
574 aauthenaction->set_receptionist(&recpt);
575 recpt.add_action (aauthenaction);
576 }
577
578 if (aphindaction == NULL) {
579 aphindaction = new phindaction();
580 recpt.add_action (aphindaction);
581 }
582
583 if (aconfigaction == NULL) {
584 aconfigaction = new configaction();
585 aconfigaction->set_receptionist(&recpt);
586 recpt.add_action (aconfigaction);
587 }
588
589 if (adynamicclassifieraction == NULL) {
590 adynamicclassifieraction = new dynamicclassifieraction();
591 adynamicclassifieraction->set_receptionist(&recpt);
592 recpt.add_action (adynamicclassifieraction);
593 }
594
595
596 // list of browsers
597 if (avlistbrowserclass == NULL) {
598 avlistbrowserclass = new vlistbrowserclass();
599 recpt.add_browser (avlistbrowserclass);
600 recpt.setdefaultbrowser ("VList");
601 }
602
603 if (ahlistbrowserclass == NULL) {
604 ahlistbrowserclass = new hlistbrowserclass();
605 recpt.add_browser (ahlistbrowserclass);
606 }
607
608 if (adatelistbrowserclass == NULL) {
609 adatelistbrowserclass = new datelistbrowserclass();
610 recpt.add_browser (adatelistbrowserclass);
611 }
612
613 if (ainvbrowserclass == NULL) {
614 ainvbrowserclass = new invbrowserclass();
615 recpt.add_browser (ainvbrowserclass);
616 }
617
618 if (apagedbrowserclass == NULL) {
619 apagedbrowserclass = new pagedbrowserclass();
620 recpt.add_browser (apagedbrowserclass);
621 }
622
623 if (ahtmlbrowserclass == NULL) {
624 ahtmlbrowserclass = new htmlbrowserclass();
625 recpt.add_browser (ahtmlbrowserclass);
626 }
627
628 if (aphindbrowserclass == NULL) {
629 aphindbrowserclass = new phindbrowserclass();;
630 recpt.add_browser (aphindbrowserclass);
631 }
632
633 // set defaults
634 recpt.configure ("gsdlhome", gsdl_gsdlhome);
635 recpt.configure ("collecthome", gsdl_collecthome);
636 recpt.configure ("gdbmhome", gsdl_dbhome);
637 recpt.configure ("collection", collection);
638
639 int maxrequests = 1;
640
641 // configure collections (and receptionist) with collectinfo stuff
642 // different from the default
643 colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
644 colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
645
646 while (this_info != end_info) {
647 text_tarray tmpconf;
648 tmpconf.push_back ((*this_info).first);
649 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
650 tmpconf.push_back ((*this_info).second.gsdl_collecthome);
651 tmpconf.push_back ((*this_info).second.gsdl_dbhome);
652 recpt.configure ("collectinfo", tmpconf);
653 ++this_info;
654 }
655
656 // read in config files of each dbhome (in no particular order)
657 // those read in last will override those read earlier
658 // collections being used together in this way should be
659 // careful not to have main.cfg files that might
660 // interfere with each other.
661 text_tset::const_iterator thome = dbhomes.begin();
662 text_tset::const_iterator ehome = dbhomes.end();
663 text_tset::const_iterator tchome = clhomes.begin(); // collecthome companion for dbhome
664
665 while (thome != ehome) {
666 if (!main_cfg_read (recpt, *thome, *tchome, collection)) {
667 // couldn't find the main configuration file
668 page_errormaincfg (*thome, collection);
669 return 0;
670 }
671 ++thome;
672 ++tchome;
673 }
674
675 // w32server relies on gwcgi being set to "gsdl"
676 recpt.configure ("gwcgi", "gsdl");
677
678 // initialise the library software
679 if (!recpt.init(cerr)) {
680 // an error occurred during the initialisation
681 page_errorinit(gsdl_gsdlhome);
682 return 0;
683 }
684
685 // get memory information
686 MEMORYSTATUS memstatus;
687 memstatus.dwLength = sizeof(MEMORYSTATUS);
688 GlobalMemoryStatus(&memstatus);
689 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
690
691 return 1;
692}
693
694
695static void rememberpref (const text_t &tailstr) {
696 gsdl_enterlib = tailstr;
697}
698
699
700static void send_file_from_disk(text_t filename,
701 RequestInfoT *RInfo,
702 RequestFieldsT *RFields) {
703
704 // select appropriate mime type from file extension
705 text_t ext;
706 text_t::const_iterator end = filename.end();
707 text_t::const_iterator it = filename.begin();
708 text_t::const_iterator lastdot = end;
709 while ((it = findchar(it, end, '.')) != end) {
710 lastdot = it;
711 ++it;
712 }
713 if (lastdot < end) ext = substr(lastdot+1, end);
714
715 text_t mime = "unknown";
716 int len = ext.size();
717 if (len == 2) {
718 if ((ext[0] == 'p' || ext[0] == 'P') &&
719 (ext[1] == 's' || ext[1] == 'S'))
720 mime = "application/postscript";
721 } else if (len == 3) {
722 if ((ext[0] == 'g' || ext[0] == 'G') &&
723 (ext[1] == 'i' || ext[1] == 'I') &&
724 (ext[2] == 'f' || ext[2] == 'F')) {
725 mime = "image/gif";
726 } else if ((ext[0] == 'j' || ext[0] == 'J') &&
727 (ext[1] == 'p' || ext[1] == 'P') &&
728 (ext[2] == 'g' || ext[2] == 'G')) {
729 mime = "image/jpeg";
730 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
731 (ext[1] == 't' || ext[1] == 'T') &&
732 (ext[2] == 'm' || ext[2] == 'M')) {
733 mime = "text/html";
734 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
735 (ext[1] == 'd' || ext[1] == 'D') &&
736 (ext[2] == 'f' || ext[2] == 'F')) {
737 mime = "application/pdf";
738 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
739 (ext[1] == 'n' || ext[1] == 'N') &&
740 (ext[2] == 'g' || ext[2] == 'G')) {
741 mime = "image/png";
742 } else if ((ext[0] == 'd' || ext[0] == 'D') &&
743 (ext[1] == 'o' || ext[1] == 'O') &&
744 (ext[2] == 'c' || ext[2] == 'C')) {
745 mime = "application/msword";
746 } else if ((ext[0] == 'r' || ext[0] == 'R') &&
747 (ext[1] == 't' || ext[1] == 'T') &&
748 (ext[2] == 'f' || ext[2] == 'F')) {
749 mime = "application/rtf";
750 } else if ((ext[0] == 'x' || ext[0] == 'X') &&
751 (ext[1] == 'l' || ext[1] == 'L') &&
752 (ext[2] == 's' || ext[2] == 'S')) {
753 mime = "application/vnd.ms-excel";
754 } else if ((ext[0] == 'p' || ext[0] == 'P') &&
755 (ext[1] == 'p' || ext[1] == 'P') &&
756 (ext[2] == 'T' || ext[2] == 'T')) {
757 mime = "application/vnd.ms-powerpoint";
758 } else if ((ext[0] == 'm' || ext[0] == 'M') &&
759 (ext[1] == 'p' || ext[1] == 'P') &&
760 (ext[2] == '3')) {
761 mime = "audio/mpeg";
762 }
763 } else if (len == 4) {
764 if ((ext[0] == 'j' || ext[0] == 'J') &&
765 (ext[1] == 'p' || ext[1] == 'P') &&
766 (ext[2] == 'e' || ext[2] == 'E') &&
767 (ext[3] == 'g' || ext[3] == 'G')) {
768 mime = "image/jpeg";
769 } else if ((ext[0] == 'h' || ext[0] == 'H') &&
770 (ext[1] == 't' || ext[1] == 'T') &&
771 (ext[2] == 'm' || ext[2] == 'M') &&
772 (ext[3] == 'l' || ext[3] == 'L')) {
773 mime = "text/html";
774 }
775 }
776
777 // try to open the file
778 //cerr << "*** filename = " << filename.getcstr() << endl;
779 //cerr << "**** collect_home = " << current_collecthome.getcstr() << endl;
780
781 if (filename.size()>=9) {
782 text_t prefix = substr(filename.begin(),filename.begin()+9);
783 //cerr << "**** prefix = " << prefix.getcstr() << endl;
784
785 text_t tail = substr(filename.begin()+9,filename.end());
786 //cerr << "**** tail = " << tail.getcstr() << endl;
787
788 if (prefix == "/collect/") {
789 filename = filename_cat (current_collecthome, tail);
790 }
791 else {
792 filename = filename_cat (current_gsdlhome, filename);
793 }
794 }
795
796 cerr << "#### filename = " << filename.getcstr() << endl;
797
798 /* Feb 2002 - handle files with spaces in their name. */
799 text_t::iterator space_start;
800 space_start=findword(filename.begin(),filename.end(),"%20");
801 while (space_start != filename.end()) {
802 // we found a space...
803 text_t::iterator after_space=space_start+3;
804 text_t new_filename=substr(filename.begin(), space_start);
805 new_filename += " ";
806 new_filename += substr(after_space,filename.end());
807 filename=new_filename;
808 space_start=findword(filename.begin(),filename.end(),"%20");
809 }
810
811 char *filenamec = filename.getcstr();
812 TranslateEscapeString(filenamec); // Resolve any %xx values
813 FILE *thefile = fopen(filenamec, "rb");
814 delete []filenamec;
815 if (thefile == NULL) {
816 log_message("file not found\n");
817 send_retrieve_error(404, "File not found",
818 "Could not find the local file requested", RInfo);
819 return;
820 }
821 int nr;
822 char buffer[2048];
823 // send back required information
824 char *mimec = mime.getcstr();
825 if (send_header(mimec, RInfo) >= 0) {
826 if (RFields->MethodStr != "HEAD") {
827 for (;;) {
828 nr = fread(buffer, 1, 2048, thefile);
829 if (nr <= 0) break;
830 if (SendData(RInfo->ClientSocket,
831 (BYTE *)buffer, nr,
832 RInfo->ThreadNum) < 0) break;
833 }
834 }
835 }
836 delete []mimec;
837 fclose(thefile);
838}
839
840static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
841 RequestFieldsT *RequestFields) {
842
843 // parse the cgi arguments and produce the resulting page if there
844 // have been no errors so far
845 cgiargsclass args;
846 fileupload_tmap fileuploads;
847 text_tmap empty; // don't use this (it's for fastcgi on unix)
848 if (!recpt.parse_cgi_args (argstr, fileuploads, args, cerr, empty)) {
849 page_errorparseargs(gsdl_gsdlhome);
850 return;
851 }
852
853 colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
854 if (it != translated_collectinfo.end()) {
855 current_gsdlhome = (*it).second.gsdl_gsdlhome;
856 current_collecthome = (*it).second.gsdl_collecthome;
857 } else {
858 current_gsdlhome = gsdl_gsdlhome;
859 current_collecthome = gsdl_collecthome;
860 }
861
862 // produce cgi header
863 response_t response;
864 text_t response_data;
865
866 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
867
868 if (response == location) {
869 // location response
870 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
871 char *response_data_c = response_data.getcstr();
872 send_header(response_data_c, RInfo);
873 delete []response_data_c;
874 return;
875 } else if (response == content) {
876 // content response
877 char *response_data_c = response_data.getcstr();
878 if (send_header(response_data_c, RInfo) < 0) {
879 delete []response_data_c;
880 return;
881 }
882 delete []response_data_c;
883 }
884 else if (response == undecided_location) {
885 // We know this is a relocation request but at the moment we don't know exactly where to
886 // Just output the start of the header and wait until later to output the target location
887 // Used for the "I'm feeling lucky" functionality
888 cout << "HTTP/1.0 302 Relocation\r\n";
889 cout << "Server: GSDL\r\n";
890 cout << "Content-type: text/html \r\n";
891 }
892 else {
893 // unknown response
894 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
895 return;
896 }
897
898 textstream.tsbreset();
899 textstream.setrequestinfo (RInfo);
900 if (!recpt.produce_content (args, cout, cerr)) {
901 page_errorcgipage(gsdl_gsdlhome);
902 return;
903 }
904 recpt.log_cgi_args (args, cerr, empty);
905
906 cout << flush;
907 cerr << flush;
908
909 ++libaccessnum;
910}
911
912static void handle_server_request(text_t &tailstr,
913 RequestInfoT *RequestInfo,
914 RequestFieldsT *RequestFields) {
915
916 text_t argstr;
917
918 // do any url adjustments necessary
919 if (tailstr.empty() || tailstr == "/") {
920 tailstr = "/gsdl";
921 }
922
923 text_t::const_iterator begin = tailstr.begin();
924 text_t::const_iterator end = tailstr.end();
925
926 // test to see if this is a library request or a local
927 // file request
928 if ((tailstr == "/gsdl") ||
929 ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
930
931 // library request
932
933 // argstr is the bit after the '?'
934 if (tailstr != "/gsdl") {
935 argstr = substr(begin+6, end);
936 }
937
938 // log the difference in access times
939 DWORD thislibaccesstime = GetTickCount();
940 if (gsdl_keep_log || gsdl_show_console) {
941 char logstr[256];
942 sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
943 log_message (logstr);
944 }
945 lastlibaccesstime = thislibaccesstime;
946
947 // log this request
948 if (gsdl_keep_log || gsdl_show_console) {
949 text_t logstr = "LOCAL LIB: " + tailstr + "\n";
950 char *logstrc = logstr.getcstr();
951 log_message (logstrc);
952 delete []logstrc;
953 }
954
955 handle_library_request (argstr, RequestInfo, RequestFields);
956
957 // remember the preferences
958 // rememberpref (tailstr);
959
960 // log memory information
961 if (gsdl_keep_log || gsdl_show_console) {
962 MEMORYSTATUS memstatus;
963 memstatus.dwLength = sizeof(MEMORYSTATUS);
964 GlobalMemoryStatus(&memstatus);
965 char logstr[256];
966 sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n",
967 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
968 log_message (logstr);
969 }
970
971 } else {
972 // local file
973 if (gsdl_keep_log || gsdl_show_console) {
974 text_t logstr = "LOCAL FILE: " + tailstr + "\n";
975 char *logstrc = logstr.getcstr();
976 log_message (logstrc);
977 delete []logstrc;
978 }
979 send_file_from_disk (tailstr, RequestInfo, RequestFields);
980 }
981}
982
983int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
984 RequestFieldsT *RequestFields)
985{
986 text_t protocol, machine, rest;
987 int port;
988
989 if (RequestFields->ContentLength > 0) {
990 // POST data
991 URIStr.push_back('?');
992 for (int i = 0; i < RequestFields->ContentLength; ++i) {
993 URIStr.push_back(RequestFields->Content[i]);
994 }
995 }
996
997 if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
998 // Alter local file request to address 'gsdl'
999 if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
1000 else URIStr = "http://gsdl" + URIStr;
1001 parse_url(URIStr, protocol, machine, &port, rest);
1002 }
1003
1004 if (machine == "gsdl") {
1005 // a local file request
1006 handle_server_request(rest, RequestInfo, RequestFields);
1007
1008 } else {
1009 send_retrieve_error(404, "File not found",
1010 "Could not find the local file requested", RequestInfo);
1011 }
1012
1013 return 1;
1014}
Note: See TracBrowser for help on using the repository browser.