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

Last change on this file since 3020 was 3020, checked in by jrm21, 22 years ago

Check to see if there is a URI-encoded space in the name of an associated
file (eg /collect/my%20col/index/assoc/0/0.png). Won't work if there are
more than 1 space though....

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