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

Last change on this file since 12761 was 12761, checked in by mdewsnip, 18 years ago

Fixed problem accessing non-ASCII files.

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