source: gsdl/tags/gsdl-2_74-distribution/src/w32server/cgiwrapper.cpp@ 14389

Last change on this file since 14389 was 14389, checked in by oranfry, 17 years ago

brought in last change from the trunk

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