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

Last change on this file since 1193 was 1193, checked in by sjboddie, 24 years ago

a few small changes to get an initial release of the local library

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1#include <windows.h>
2#include <string.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <assert.h>
6#include <direct.h>
7#include "cgiwrapper.h"
8#include "netio.h"
9#include "wincgiutils.h"
10#include "settings.h"
11#include "fileutil.h"
12
13#include "gsdlconf.h"
14#include "recptconfig.h"
15
16#if defined (GSDL_USE_OBJECTSPACE)
17#include <ospace\std\iostream>
18#include <ospace\std\fstream>
19#elif defined (GSDL_USE_IOS_H)
20#include <iostream.h>
21#include <fstream.h>
22#else
23#include <iostream>
24#include <fstream>
25#endif
26
27#include "receptionist.h"
28#include "nullproto.h"
29#include "collectserver.h"
30#include "infodbclass.h"
31#include "mggdbmsource.h"
32
33// actions
34#include "statusaction.h"
35#include "pageaction.h"
36#include "pingaction.h"
37#include "queryaction.h"
38#include "documentaction.h"
39#include "tipaction.h"
40#include "authenaction.h"
41#include "usersaction.h"
42#include "extlinkaction.h"
43#include "buildaction.h"
44#include "delhistoryaction.h"
45
46// browsers
47#include "vlistbrowserclass.h"
48#include "hlistbrowserclass.h"
49#include "datelistbrowserclass.h"
50#include "invbrowserclass.h"
51#include "pagedbrowserclass.h"
52#include "htmlbrowserclass.h"
53
54// filters
55#include "filter.h"
56#include "browsefilter.h"
57#include "queryfilter.h"
58#include "phrasequeryfilter.h"
59
60// the number of times the library has been accessed
61int libaccessnum = 0;
62
63// used to output the text from receptionist
64class textstreambuf : public streambuf
65{
66public:
67 textstreambuf ();
68 int sync ();
69 int overflow (int ch);
70 int underflow () {return EOF;}
71
72 void tsbreset() {RInfo=NULL;casostr=NULL;}
73 void setrequestinfo (RequestInfoT *theRInfo) {RInfo=theRInfo;}
74 void cascadeoutput (ostream *thecasostr) {casostr=thecasostr;}
75
76private:
77 RequestInfoT *RInfo;
78 ostream *casostr;
79};
80
81textstreambuf::textstreambuf() {
82 tsbreset();
83 if (base() == ebuf()) allocate();
84 setp (base(), ebuf());
85};
86
87int textstreambuf::sync () {
88 if ((RInfo != NULL) &&
89 (Send_String_N(pbase(), out_waiting(), RInfo) < 0)) {
90 RInfo = NULL;
91 }
92
93 if (casostr != NULL) {
94 char *thepbase=pbase();
95 for (int i=0;i<out_waiting();i++) (*casostr).put(thepbase[i]);
96 }
97
98 setp (pbase(), epptr());
99
100 return 0;
101}
102
103int textstreambuf::overflow (int ch) {
104 if (sync () == EOF) return EOF;
105 if (ch != EOF) sputc (ch);
106 return 0;
107}
108
109
110// used to output all the log and error messages
111// from receptionist
112class logstreambuf : public streambuf
113{
114public:
115 logstreambuf ();
116 int sync ();
117 int overflow (int ch);
118 int underflow () {return EOF;}
119};
120
121logstreambuf::logstreambuf () {
122 if (base() == ebuf()) allocate();
123 setp (base(), ebuf());
124}
125
126int logstreambuf::sync () {
127 if (gsdl_keep_log || gsdl_show_console) {
128 log_message ("LOCAL LIB MESSAGE: ");
129 log_message_N (pbase(), out_waiting());
130 }
131
132 setp (pbase(), epptr());
133 return 0;
134}
135
136int logstreambuf::overflow (int ch) {
137 if (sync () == EOF) return EOF;
138 if (ch != EOF) sputc (ch);
139 return 0;
140}
141
142
143
144#ifndef MAX_FILENAME_SIZE
145#define MAX_FILENAME_SIZE 2048
146#endif
147
148
149receptionist recpt;
150nullproto nproto;
151textstreambuf textstream;
152logstreambuf logstream;
153DWORD lastlibaccesstime;
154DWORD baseavailvirtual;
155
156static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection) {
157
158 if (collection.empty()) {
159 text_t message = "Error\n\n"
160 "The main.cfg configuration file could not be found. This file\n"
161 "should contain configuration information relating to the\n"
162 "setup of the interface. As this program is not being run\n"
163 "in collection specific mode the file should reside at\n" +
164 gsdlhome + "\\etc\\main.cfg.\n";
165
166 MessageBox(NULL, message.getcstr(),
167 "Greenstone Digital Library Software"
168 ,MB_OK|MB_SYSTEMMODAL);
169 } else {
170 text_t message = "Neither the collect.cfg or main.cfg configuration files could\n"
171 "be found. This file should contain configuration information\n"
172 "relating to the setup of the interface. As this cgi script is\n"
173 "being run in collection specific mode the file should reside\n"
174 "at either " + gsdlhome + "\\collect\\" + collection + "\\etc\\collect.cfg,\n" +
175 gsdlhome + "\\etc\\collect.cfg or " + gsdlhome + "\\etc\\main.cfg.\n";
176
177 MessageBox(NULL, message.getcstr(),
178 "Greenstone Digital Library Software"
179 ,MB_OK|MB_SYSTEMMODAL);
180 }
181}
182
183static void page_errorinit (const text_t &/*gsdlhome*/) {
184
185 text_t message = "Error\n\n"
186 "An error occurred during the initialisation of the Greenstone Digital\n"
187 "Library software. It is likely that the software has not been setup\n"
188 "correctly.\n";
189
190 MessageBox(NULL, message.getcstr(),
191 "Greenstone Digital Library Software"
192 ,MB_OK|MB_SYSTEMMODAL);
193}
194
195static void page_errorparseargs (const text_t &gsdlhome) {
196
197 text_t message = "Error\n\n"
198 "An error occurred during the parsing of the cgi arguments.\n";
199
200 MessageBox(NULL, message.getcstr(),
201 "Greenstone Digital Library Software"
202 ,MB_OK|MB_SYSTEMMODAL);
203}
204
205static void page_errorcgipage (const text_t &gsdlhome) {
206
207 text_t message = "Error\n\n"
208 "An error occurred during the construction of the cgi page.\n";
209
210 MessageBox(NULL, message.getcstr(),
211 "Greenstone Digital Library Software"
212 ,MB_OK|MB_SYSTEMMODAL);
213}
214
215// returns 0 if the directories can't be found
216// and the user wants to quit (it returns 1
217// if everything is ok)
218int checkdir (const text_t &thedir) {
219 UINT curerrormode;
220 int drive = _getdrive();
221 char cwd[1024];
222 char rootpath[4];
223 UINT drivetype;
224 char *cstrthedir = thedir.getcstr();
225 int returnvalue = 1;
226
227 // make sure no rude error messages are presented to the user
228 curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
229
230 // get the drive name
231 if (thedir.size() >= 2 && thedir[1] == ':') {
232 if (thedir[0] >= 'a' && thedir[0] <= 'z') {
233 drive = thedir[0] - 'a' + 1;
234
235 } else if (thedir[0] >= 'A' && thedir[0] <= 'Z') {
236 drive = thedir[0] - 'A' + 1;
237 }
238 }
239
240 // find the drive type
241 rootpath[0] = drive + 'A' - 1;
242 rootpath[1] = ':';
243 rootpath[2] = '\\';
244 rootpath[3] = '\0';
245 drivetype = GetDriveType (rootpath);
246
247 // try and set this directory to be the current working
248 // directory
249 _getcwd(cwd, 1024);
250 while (_chdir(cstrthedir) != 0) {
251 // failed
252 if (drivetype == DRIVE_CDROM) {
253 // message to insert the cdrom
254 if (MessageBox (NULL,
255 "Please insert the Greenstone Digital Library\n"
256 "CD-ROM into the CD-ROM drive and press 'OK'.\n\n"
257 "If you don't have the CD-ROM press 'Cancel' to exit\n"
258 "this program.", "Greenstone Digital Library Software",
259 MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL) {
260
261 returnvalue = 0;
262 break;
263 }
264
265 } else {
266 // message saying that the system was unable
267 // to find a certain directory
268 text_t message = "Failed to find the directory:\n\n" + thedir;
269 message += "\n\n"
270 "This directory is needed for the successful operation\n"
271 "of this software. Make sure it hasn't been deleted or\n"
272 "moved, and restart the software. You may need to\n"
273 "reinstall this software to correct the problem.";
274 char *cstrmessage = message.getcstr();
275
276 MessageBox (NULL, cstrmessage, "Greenstone Digital Library Software",
277 MB_OK | MB_TASKMODAL);
278
279 delete cstrmessage;
280
281 returnvalue = 0;
282 break;
283 }
284 }
285
286 // revert to the previous error and cwd states
287 _chdir(cwd);
288 SetErrorMode(curerrormode);
289
290 // free the allocated C string
291 delete cstrthedir;
292
293 return returnvalue;
294}
295
296
297// c-string version of checkdir for the outside
298// world
299int cstrcheckdir (char *cstrthedir) {
300 return checkdir (cstrthedir);
301}
302
303
304// returns 1 if successful, 0 if unsuccessful
305int gsdl_init () {
306 cerr = &logstream;
307 cout = &textstream;
308
309 // collection should be set to "" unless in
310 // collection specific mode
311 text_t collection = "";
312 text_tset gsdlhomes;
313 text_tarray collections;
314 colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
315 colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
316
317 // note the current time
318 lastlibaccesstime = GetTickCount();
319
320 // before we do the init we should make sure
321 // that we can find the relevant directories
322 if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
323 if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
324
325 if (collection.empty()) {
326
327 // get all collections from each gsdlhome (this relies
328 // on there not being more than one collection with the same
329 // name)
330 read_dir (filename_cat (gsdl_gsdlhome, "collect"), collections);
331 gsdlhomes.insert (gsdl_gsdlhome);
332 while (this_info != end_info) {
333 if (gsdlhomes.find ((*this_info).second.gsdl_gsdlhome) == gsdlhomes.end()) {
334 read_dir (filename_cat ((*this_info).second.gsdl_gsdlhome, "collect"), collections);
335 gsdlhomes.insert ((*this_info).second.gsdl_gsdlhome);
336 }
337 this_info ++;
338 }
339 } else {
340 collections.push_back (collection);
341 }
342
343 text_tarray::const_iterator thiscol = collections.begin();
344 text_tarray::const_iterator endcol = collections.end();
345
346 while (thiscol != endcol) {
347
348 // this memory is created but never destroyed
349 // we're also not doing any error checking to make sure we didn't
350 // run out of memory
351 collectserver *cserver = new collectserver();
352 gdbmclass *gdbmhandler = new gdbmclass();
353 mgsearchclass *mgsearch = new mgsearchclass();
354
355 // add a null filter
356 filterclass *filter = new filterclass();
357 cserver->add_filter (filter);
358
359 // add a browse filter
360 browsefilterclass *browsefilter = new browsefilterclass();
361 browsefilter->set_gdbmptr (gdbmhandler);
362 cserver->add_filter (browsefilter);
363
364 // add a query filter
365 queryfilterclass *queryfilter = new queryfilterclass();
366 queryfilter->set_gdbmptr (gdbmhandler);
367 queryfilter->set_mgsearchptr (mgsearch);
368 cserver->add_filter (queryfilter);
369
370 // add an mg and gdbm source
371 mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass();
372 mggdbmsource->set_gdbmptr (gdbmhandler);
373 mggdbmsource->set_mgsearchptr (mgsearch);
374 cserver->add_source (mggdbmsource);
375
376 // inform collection server and everything it contains about
377 // its collection name
378 cserver->configure ("collection", *thiscol);
379
380 nproto.add_collectserver (cserver);
381
382 thiscol ++;
383 }
384
385 // add the protocol to the receptionist
386 recpt.add_protocol (&nproto);
387
388 // add other converters
389 utf8inconvertclass *utf8inconvert = new utf8inconvertclass();
390 utf8outconvertclass *utf8outconvert = new utf8outconvertclass();
391 recpt.add_converter ("u", utf8inconvert, utf8outconvert);
392
393 mapinconvertclass *gbinconvert = new mapinconvertclass();
394 gbinconvert->setmapfile (gsdl_gsdlhome, "gbku", 0x25a1);
395 mapoutconvertclass *gboutconvert = new mapoutconvertclass();
396 gboutconvert->setmapfile (gsdl_gsdlhome, "ugbk", 0xa1f5);
397 recpt.add_converter ("g", gbinconvert, gboutconvert);
398
399 // the list of actions.
400 statusaction *astatusaction = new statusaction();
401 astatusaction->set_receptionist (&recpt);
402 recpt.add_action (astatusaction);
403
404 pageaction *apageaction = new pageaction();
405 recpt.add_action (apageaction);
406
407 pingaction *apingaction = new pingaction();
408 recpt.add_action (apingaction);
409
410 tipaction *atipaction = new tipaction();
411 recpt.add_action (atipaction);
412
413 queryaction *aqueryaction = new queryaction();
414 recpt.add_action (aqueryaction);
415
416 documentaction *adocumentaction = new documentaction();
417 recpt.add_action (adocumentaction);
418
419 usersaction *ausersaction = new usersaction();
420 recpt.add_action (ausersaction);
421
422 extlinkaction *anextlinkaction = new extlinkaction();
423 recpt.add_action (anextlinkaction);
424
425 buildaction *abuildaction = new buildaction();
426 abuildaction->set_receptionist (&recpt);
427 recpt.add_action (abuildaction);
428
429 authenaction *aauthenaction = new authenaction();
430 aauthenaction->set_receptionist(&recpt);
431 recpt.add_action (aauthenaction);
432
433 delhistoryaction *adelhistoryaction = new delhistoryaction();
434 recpt.add_action (adelhistoryaction);
435
436
437 // list of browsers
438 vlistbrowserclass *avlistbrowserclass = new vlistbrowserclass();
439 recpt.add_browser (avlistbrowserclass);
440 recpt.setdefaultbrowser ("VList");
441
442 hlistbrowserclass *ahlistbrowserclass = new hlistbrowserclass();
443 recpt.add_browser (ahlistbrowserclass);
444
445 datelistbrowserclass *adatelistbrowserclass = new datelistbrowserclass();
446 recpt.add_browser (adatelistbrowserclass);
447
448 invbrowserclass *ainvbrowserclass = new invbrowserclass();
449 recpt.add_browser (ainvbrowserclass);
450
451 pagedbrowserclass *apagedbrowserclass = new pagedbrowserclass();
452 recpt.add_browser (apagedbrowserclass);
453
454 htmlbrowserclass *ahtmlbrowserclass = new htmlbrowserclass();
455 recpt.add_browser (ahtmlbrowserclass);
456
457 // set defaults
458 recpt.configure ("gsdlhome", gsdl_gsdlhome);
459 recpt.configure ("collection", collection);
460
461 int maxrequests = 1;
462 text_tset seenhomes;
463 this_info = gsdl_collectinfo.begin();
464
465 // configure any collections with gsdlhome (or gdbmhome)
466 // different from the default
467 while (this_info != end_info) {
468 if (((*this_info).second.gsdl_gsdlhome != gsdl_gsdlhome) ||
469 ((*this_info).second.gsdl_gdbmhome != gsdl_gdbmhome) &&
470 (seenhomes.find ((*this_info).second.gsdl_gsdlhome +
471 (*this_info).second.gsdl_gdbmhome) == seenhomes.end())) {
472 text_tarray tmpconf;
473 tmpconf.push_back ((*this_info).first);
474 tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
475 tmpconf.push_back ((*this_info).second.gsdl_gdbmhome);
476 recpt.configure ("collectinfo", tmpconf);
477 seenhomes.insert ((*this_info).second.gsdl_gsdlhome +
478 (*this_info).second.gsdl_gdbmhome);
479 }
480 this_info ++;
481 }
482
483 // read in config files of each gsdlhome (in no particular order)
484 // those read in last will override those read earlier
485 // collections being used together in this way should be
486 // careful not to have main.cfg files that might
487 // screw with each other.
488 text_tset::const_iterator thome = gsdlhomes.begin();
489 text_tset::const_iterator ehome = gsdlhomes.end();
490 while (thome != ehome) {
491 if (!main_cfg_read (recpt, *thome, collection)) {
492 // couldn't find the main configuration file
493 page_errormaincfg (*thome, collection);
494 return 0;
495 }
496 thome ++;
497 }
498
499 // w32server relies on gwcgi being set to "gw"
500 recpt.configure ("gwcgi", "gw");
501
502 // initialise the library software
503 if (!recpt.init(cerr)) {
504 // an error occurred during the initialisation
505 page_errorinit(gsdl_gsdlhome);
506 return 0;
507 }
508
509 // get memory information
510 MEMORYSTATUS memstatus;
511 memstatus.dwLength = sizeof(MEMORYSTATUS);
512 GlobalMemoryStatus(&memstatus);
513 baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
514
515 return 1;
516}
517
518
519static void rememberpref (char *tailstr) {
520
521 // gsdl_enterlib = tailstr;
522}
523
524
525static void send_file_from_disk(char *filename,
526 RequestInfoT *RInfo,
527 RequestFieldsT *RFields)
528{
529 int len, nr; char *tail, *kind;
530 FILE *thefile;
531
532 // select appropriate mime type from file name
533 len = strlen(filename);
534 while (len > 0 && filename[len-1] != '.') len--;
535 kind = "unknown";
536 if (len > 0) {
537 tail = &filename[len];
538 if (stricmp("gif",tail) == 0) kind = "image/gif";
539 else if (stricmp("jpg",tail) == 0 ||
540 stricmp("jpeg",tail) == 0) kind = "image/jpeg";
541 else if (stricmp("htm",tail) == 0 ||
542 stricmp("html",tail) == 0) kind = "text/html";
543 }
544
545 // set up file name
546 text_t filenamet = text_t(gsdl_gsdlhome) + filename;
547 text_t::iterator here = filenamet.begin();
548 text_t::iterator end = filenamet.end();
549 while (here != end) {
550 if (*here == '/') *here = '\\';
551 here ++;
552 }
553
554 filename = filenamet.getcstr();
555
556 // try to open it
557 thefile = fopen(filename, "rb");
558 if (thefile == NULL) {
559 log_message("file not found\n");
560 send_retrieve_error(404, "File not found",
561 "Could not find the local file requested", RInfo);
562 return;
563 }
564
565 char buffer[2048];
566 // send back required information
567 if (send_header(kind, RInfo) >= 0) {
568 if (strcmpi(RFields->MethodStr, "HEAD") != 0) {
569 for (;;) {
570 nr = fread(buffer, 1, 2048, thefile);
571 if (nr <= 0) break;
572 if (SendData(RInfo->ClientSocket,
573 (BYTE *)buffer, nr,
574 RInfo->ThreadNum) < 0) break;
575 }
576 }
577 }
578 fclose(thefile);
579}
580
581static void handle_library_request(char *TailStr, RequestInfoT *RInfo,
582 RequestFieldsT *RequestFields) {
583 // check for a "?" at the start of the tail string
584 if (*TailStr == '?') TailStr++;
585
586 outconvertclass text_t2ascii;
587
588 // parse the cgi arguments and produce the resulting page if there
589 // has been no errors so far
590 cgiargsclass args;
591 text_tmap empty; // don't use this (it's for fastcgi on unix)
592 if (!recpt.parse_cgi_args (TailStr, args, cerr, empty)) {
593 page_errorparseargs(gsdl_gsdlhome);
594 return;
595 }
596
597 // produce cgi header
598 response_t response;
599 text_t response_data;
600
601 recpt.get_cgihead_info (args, response, response_data, cerr, empty);
602
603 if (response == location) {
604 // location response
605 response_data = "@" + recpt.expandmacros (response_data, args, cerr);
606 char *response_data_c = response_data.getcstr();
607 send_header(response_data_c, RInfo);
608 delete response_data_c;
609 return;
610 } else if (response == content) {
611 // content response
612 char *response_data_c = response_data.getcstr();
613 if (send_header(response_data_c, RInfo) < 0) {
614 delete response_data_c;
615 return;
616 }
617 delete response_data_c;
618 } else {
619 // unknown response
620 cerr << "Error: get_cgihead_info returned an unknown response type.\n";
621 return;
622 }
623
624 textstream.tsbreset();
625 textstream.setrequestinfo (RInfo);
626
627 if (!recpt.produce_content (args, cout, cerr)) {
628 page_errorcgipage(gsdl_gsdlhome);
629 return;
630 }
631 recpt.log_cgi_args (args, cerr, empty);
632
633 cout << flush;
634 cerr << flush;
635
636 libaccessnum++;
637}
638
639static void handle_server_request(char *initialTailStr,
640 RequestInfoT *RequestInfo,
641 RequestFieldsT *RequestFields) {
642 char tmpstr[1024];
643 char tailstr[MAX_URL_SIZE];
644
645 // do any url adjustments necessary
646 if (strcmp(initialTailStr, "/") == 0) {
647 strcpy (tailstr, "/cgi-bin/gw");
648 } else strcpy (tailstr, initialTailStr);
649
650 // test to see if this is a library request or a local
651 // file request
652 if ((strncmp(tailstr, "/cgi-bin/gw", 11) == 0) &&
653 ((tailstr[11] == '\0') || (tailstr[11] == '?'))) {
654 // library request
655
656 // log the difference in access times
657 DWORD thislibaccesstime = GetTickCount();
658 if (gsdl_keep_log||gsdl_show_console) {
659 sprintf(tmpstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
660 log_message (tmpstr);
661 }
662 lastlibaccesstime = thislibaccesstime;
663
664 // log this request
665 if (gsdl_keep_log||gsdl_show_console) {
666 sprintf (tmpstr, "LOCAL LIB: %s\n", tailstr);
667 log_message (tmpstr);
668 }
669
670 handle_library_request (&tailstr[11], RequestInfo, RequestFields);
671
672 // remember the preferences
673 rememberpref (tailstr);
674
675 // log memory information
676 if (gsdl_keep_log||gsdl_show_console) {
677 MEMORYSTATUS memstatus;
678 memstatus.dwLength = sizeof(MEMORYSTATUS);
679 GlobalMemoryStatus(&memstatus);
680 sprintf (tmpstr, "BDELTA AVAIL VIRTUAL: %i K\n",
681 (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
682 log_message (tmpstr);
683 }
684
685 } else {
686 // local file
687 if (gsdl_keep_log||gsdl_show_console) {
688 sprintf (tmpstr, "LOCAL FILE: %s\n", tailstr);
689 log_message (tmpstr);
690 }
691 send_file_from_disk (tailstr, RequestInfo, RequestFields);
692 }
693}
694
695static void fix_prefix(char *dest, char *pref, char *suff)
696{
697 strcpy(dest,pref);
698 if (*suff != '/') strcat(dest,"/");
699 if (strlen(dest) + strlen(suff) + 1 > MAX_URL_SIZE)
700 strcpy(dest,"http://gsdl/name-too-long");
701 else
702 strcat(dest,suff);
703}
704
705int ExamineURIStr(char *URIStr,RequestInfoT *RequestInfo,
706 RequestFieldsT *RequestFields)
707{
708 char *protocol, *machine, *rest; int port;
709 char URICopyA[MAX_URL_SIZE], URICopyB[MAX_URL_SIZE];
710 strcpy(URICopyA,URIStr);
711
712 if (parse_url(URICopyA,&protocol,&machine,&port,&rest)!=http_ok) {
713 /* Alter local file request to address 'gsdl' */
714 fix_prefix(URICopyB, "http://gsdl", URIStr);
715 URIStr = URICopyB;
716 strcpy(URICopyA, URICopyB);
717 parse_url(URICopyA,&protocol,&machine,&port,&rest);
718 }
719
720 if (strncmp(machine, "gsdl", 5) == 0) {
721 // a local file request
722 handle_server_request(rest, RequestInfo, RequestFields);
723
724 } else {
725 send_retrieve_error(404, "File not found",
726 "Could not find the local file requested", RequestInfo);
727 }
728
729 return 1;
730}
Note: See TracBrowser for help on using the repository browser.