forked from verhas/ScriptBasic
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcgi.c
More file actions
2085 lines (1815 loc) · 59.2 KB
/
cgi.c
File metadata and controls
2085 lines (1815 loc) · 59.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
FILE: cgi.c
HEADER: cgi.h
Version: 2.0
This code can be used to hadle web communication between
the server and the application. Using the functions provided
in this file you can write code runs with CGI as well as ISAPI.
This code was developed to be used in the ScriptBasic project, but
this code can be used as a stand-alone product embedded into other
programs. This is GNU GPL protected.
TO_HEADER:
typedef struct _SymbolList {
char *symbol;
FILE *fp; // pointer to the temporary file
char *file; // in case this is an uploaded file name
char *value;
long len; // length of the value or the saved temporary file
struct _SymbolList *pHeaders; // in case of multipart
struct _SymbolList *next;
} SymbolList, *pSymbolList;
typedef struct _DebugStore {
char *ServerSoftware;
char *ServerName;
char *GatewayInterface;
char *ServerProtocol;
char *ServerPort;
char *RequestMethod;
char *PathInfo;
char *PathTranslated;
char *ScriptName;
char *QueryString;
char *RemoteHost;
char *RemoteAddress;
char *AuthType;
char *RemoteUser;
char *RemoteIdent;
char *ContentType;
char *ContentLength;
char *UserAgent;
char *Cookie;
FILE *fpDebugInput;
} DebugStore, *pDebugStore;
typedef struct _CgiObject {
void *(*maf)(long size, void *pSegment);
void (*mrf)(void *MemoryToFree, void *pSegment);
void *pSegment;
#define CGI_INTERFACE_CGI 0x00000000 // this is the only implemented so far
#define CGI_INTERFACE_ISAPI 0x00000001
#define CGI_INTERFACE_NSAPI 0x00000002
#define CGI_INTERFACE_FCGI 0x00000003
#define CGI_INTERFACE_DEBUG 0x00000004 // read all information from a debug file
long fInterface; // constant defining the interface type
#ifdef WIN32
LPEXTENSION_CONTROL_BLOCK lpECB;
char *pszNextChar;
char *pszLocalBuffer;
DWORD cbAvailable;
DWORD dwIsapiBufferSize;
#else
#define LPEXTENSION_CONTROL_BLOCK void *
#endif
void *pEmbed; // embedder pointer for caller defined stdin/stdout and env functions
int (*pfStdIn)(void *); // user defined stdin function gets pEmbed as argument
void (*pfStdOut)(int, void*); // user defined stdout function gets pEmbed as second argument
char *(*pfEnv)(void *,char *,long); //user defined environment function
char *pszDebugFile; // the debug file if fInterface is CGI_INTERFACE_DEBUG, otherwise ignored
pDebugStore pDebugInfo; // points to the allocated struct that stores CGI info read from the debug file
char *pszBoundary; // multipart boundary string
unsigned long cbBoundary; // length of the boundary
unsigned char *pszBuffer; // buffer to store characters
unsigned long cbBuffer; // the actual size of the buffer
unsigned long cbFill; // the number of characters stored in the buffer at the moment
unsigned long lBufferPosition; // the current buffer position when returning characters
int (*CharacterInput)(struct _CgiObject *p);
void *pInputParameter; // the parameter the input function can use
unsigned long lContentLength; // the length of the POST param (used by the CharacterInput function)
pSymbolList pGetParameters; // point to GET parameters
pSymbolList pPostParameters; // point to POST parameters
unsigned long lBufferIncrease; // increase the buffer using this increment when buffer is small
unsigned long lBufferMax; // never exceed this size with the buffer
unsigned long lContentMax; // maximal content-length we deal with
unsigned long lFileMax; // maximal file length we deal with
#define CGI_METHOD_NONE 0x00000000
#define CGI_METHOD_GET 0x00000001
#define CGI_METHOD_POST 0x00000002
#define CGI_METHOD_UPL 0x00000004 // upload "method" this is a post method,
//but here we treat it if it was a separate method
// these methods are not implemented yet
#define CGI_METHOD_PUT 0x00000008
#define CGI_METHOD_DEL 0x00000010
#define CGI_METHOD_COPY 0x00000020
#define CGI_METHOD_MOVE 0x00000040
#define CGI_METHOD_HEAD 0x00000080
long fMethods; // allowed methods, each bit set is an allowed method
} CgiObject, *pCgiObject;
#define CGI_ERROR_BUFFER_OVERFLOW 0x00080001
#define CGI_ERROR_BIG_CONTENT 0x00080002
#define CGI_ERROR_INVALID_METHOD 0x00080003
#define CGI_ERROR_NO_DEBUG_FILE 0x00080004
#define CGI_ERROR_NOTIMP 0x00080005
#define CGI_ERROR_EOF 0x00080006
#define CGI_ERROR_ILLF_MULTI 0x00080007
#define CGI_ERROR_FILEMAX 0x00080008
#define CGI_ERROR_MEMORY_LOW 0x00080009
#define CGI_ERROR_METHOD_NOTALL 0x0008000A
#define CGI_ERROR_ILLF_MULTI1 0x00080017
#define CGI_ERROR_ILLF_MULTI2 0x00080027
#define CGI_ERROR_ILLF_MULTI3 0x00080037
#define CGI_ERROR_ILLF_MULTI4 0x00080047
#define CGI_ERROR_ILLF_MULTI5 0x00080057
#define CGI_ERROR_ILLF_MULTI6 0x00080067
#define CGI_ERROR_ILLF_MULTI7 0x00080077
//this is a safe macro implementation of the functions
#define cgi_EmptyBuffer(x) ((x)->cbFill=0)
#define cgi_BufferFull(x) ((x)->cbFill == (x)->cbBuffer)
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#ifdef WIN32
#include <io.h>
#include <httpext.h>
#endif
#include "cgi.h"
#define _getenv(X) (pCO->pfEnv ? pCO->pfEnv(pCO->pEmbed,(X),0) : getenv(X))
#if (!defined(_WIN32) && !defined(__MACOS__))
static int stricmp(char *a, char *b){
char ca,cb;
while( 1 ){
ca = *a++;
cb = *b++;
ca = isupper(ca) ? tolower(ca) : ca;
cb = isupper(cb) ? tolower(cb) : cb;
if( ca == (char)0 && cb == (char)0 )return 0;
if( ca != cb )return ca-cb;
}
}
#endif
#define CR '\r'
#define LF '\n'
/* initial buffer size */
#define BUFFER_INCREASE 1024
#define BUFFER_MAX 10240
/* 10MB */
#define CONTENT_MAX 0xA00000
#define FILE_MAX 0xA00000
/* 40KB */
#define ISAPI_BUFFER 0xA000
#define DEBUGFP (pCO->pDebugInfo->fpDebugInput)
#define GETCHAR() (pCO->CharacterInput(pCO))
#define ALLOC(x) (pCO->maf((x),pCO->pSegment))
#define FREE(x) (pCO->mrf((x),pCO->pSegment))
static char x2c(char *what){
register char digit;
#define TOHEX(x) ((x) >= 'A' ? (((x) & 0xdf) - 'A')+10 : ((x) - '0'))
digit = TOHEX(*what);
digit *= 16;
what++;
digit += TOHEX(*what);
return digit;
#undef TOHEX
}
static void unescape(char *s, long *len){
char *p;
long rest;
p = s;
rest = *len;
while( rest ){
if( *p == '+' )*p = ' ';
p++;
rest --;
}
p = s;
rest = *len;
while( rest ){
*p = *s;
if( *p == '%' ){
s++;rest--;
*p = x2c(s);
s++;
rest--;
(*len) -= 2;
}
p++;
s++;
rest--;
}
}
static void *my_maf(long size, void *p){
return malloc(size);
}
static void my_mrf(void *q, void*p){
free(q);
}
#ifdef WIN32
static int IsapiGetChar(pCgiObject pCO){
unsigned char ch; /* it IS important that this is unsigned otherwise a 255
would mean EOF */
if( pCO->lContentLength == 0 )return EOF;
if( pCO->cbAvailable ){
pCO->cbAvailable--;
ch = *(pCO->pszNextChar);
pCO->lContentLength --;
pCO->pszNextChar ++;
return (unsigned int)ch;
}
if( pCO->pszLocalBuffer == NULL ){
if( pCO->dwIsapiBufferSize > pCO->lContentLength )
pCO->dwIsapiBufferSize = pCO->lContentLength;
pCO->pszLocalBuffer = ALLOC(pCO->dwIsapiBufferSize);
if( pCO->pszLocalBuffer == NULL )return EOF;
}
pCO->pszNextChar = pCO->pszLocalBuffer;
pCO->cbAvailable = pCO->dwIsapiBufferSize;
if( pCO->lpECB->ReadClient(pCO->lpECB->ConnID,pCO->pszLocalBuffer,&(pCO->cbAvailable)) && pCO->cbAvailable ){
ch = *(pCO->pszNextChar);
pCO->lContentLength --;
pCO->cbAvailable--;
pCO->pszNextChar ++;
return (unsigned int)ch;
}
/* We will get here only if the client pressed the STOP button on the browser. */
return EOF;
}
#endif
static int CgiGetChar(pCgiObject pCO){
int ch;
#ifdef WIN32
if( ! pCO->pfStdIn ){
setmode(fileno(stdin), O_BINARY); /* define stdin as binary */
_fmode = O_BINARY; /* default all file I/O as binary */
}
#endif
if( pCO->lContentLength ){
pCO->lContentLength --;
if( pCO->pfStdIn )
ch = pCO->pfStdIn(pCO->pEmbed);
else
ch = getchar();
return ch;
}
return EOF;
}
static void CgiPutChar(pCgiObject pCO, int ch){
if( pCO->pfStdOut )
pCO->pfStdOut(ch,pCO->pEmbed);
else
putc(ch,stdout);
}
static int DebugGetChar(pCgiObject pCO){
int ch;
#ifdef WIN32
setmode(fileno(DEBUGFP), O_BINARY); /* define stdin as binary */
_fmode = O_BINARY; /* default all file I/O as binary */
#endif
ch = getc(DEBUGFP);
return ch;
}
/*POD
=H CGI handling
This package contains functions that help you handle CGI (later NSAPI, ISAPI and FCGI)
input in Web programs. The functions are written in a well defined manner, documented,
thread aware.
The functions to be used by external programs (the public functions) have abstract in this
documentation. Other functions are listed and documented here, because they have to be
documented for maintenance purposes. Some very small, almost inline functions are declared
as static and are documented only in the source code.
(zchar string means a string terminted by a character of code zero)
Note that all function names are preceeded with the characters T<cgi_>
Topics:
CUT*/
/*POD
=section InitCgi
=H Initialize a CgiObject with default values
=abstract
This function initializes a CgiObject filling the default values
to handle the http request parameters via the CGI interface.
=end
This function initializes a CgiObject filling the default values
to handle the http request parameters via the CGI interface.
To handle CGI input the caller program should have a variable
of type T<CgiObject>. This T<struct> variable will contain all
information neccessary to handle the CGI input, and all functions
request pointer to this variable as first argument. You can think
of this T<struct> as the container for the class variables (except that
this is written in C and not C++).
T<mrf>
T<maf>
The memory handling functions are initialized to point to a function
using T<malloc> and T<free>. You can change the fields T<maf> and T<mrf>
to point to a T<m>emory T<a>llocation T<f>unction and to a T<m>emory
T<r>eleasing T<f>unction that are similar to T<malloc> and T<free>, but
also accept a second T<void *> argument. This T<void *> argument may help
to use thread local allocation, or to use segmented allocation, where
all memory chunks can be released with a single call using the T<void *>
pointer. (See the http://www.emma.hu/scriptbasic application source and
get the file T<myalloc.c> for example.)
T<CharacterInput>
The field T<CharacterInput> should point to a function that gets a pointer
to the T<CgiObject> variable and returns an int, which is the next character
or EOF in case no more input is available. This field is initialized to
point to local function that reads the standard input (binary mode on Windows)
but may be reseto to point to any other function in case you want to read a file
for debugging purposes instead of the stdin.
T<lBufferIncrease>
The field T<lBufferIncrease> initialized to T<BUFFER_INCREASE>. (1KByte) This is the
initial size of the buffer and this is the increase whenever the buffer seems to be
small.
T<lBufferMax>
The fiels T<lBufferMax> is initialized to T<BUFFER_MAX>. (10KByte) This is the maximal
size of the buffer. If the buffer needs to be larger than this size the program does
not process the CGI input.
The buffer should be large enough to handle POST data (but not uploaded files) and multipart
headers (one at a time).
T<lContentMax>
The fiels T<lContentMax> is initialized to T<CONTENT_MAX>. (10MByte) This is the maximal size
of the CGI input the program handles. Whenever the header field T<Content-Length> is
larger than this size the program does not process the CGI input.
T<lFileMax>
The filed T<lFileMax> is initialized to T<FILE_MAX>. (10MByte) This is the maximal size
of an uploaded file. Whenever a file is larger than this size the program does not process
the CGI input.
=hrule
These parameters can be altered after calling this initialization function. These
values help the program to minimize the effect of a denial of service attack sending
huge amount of data to web scripts that do not expect to handle them.
/*FUNCTION*/
void cgi_InitCgi(pCgiObject pCO
){
/*noverbatim
CUT*/
pCO->maf = my_maf;
pCO->mrf = my_mrf;
pCO->pSegment = NULL;
pCO->fInterface = CGI_INTERFACE_CGI;
pCO->pszBoundary = NULL;
pCO->cbBoundary = 0;
pCO->pszBuffer = NULL;
pCO->cbBuffer = 0;
pCO->cbFill = 0;
pCO->lBufferPosition = 0;
pCO->CharacterInput = CgiGetChar;
pCO->pInputParameter = NULL;
pCO->lContentLength = 0;
pCO->lBufferIncrease = BUFFER_INCREASE;
pCO->lBufferMax = BUFFER_MAX;
pCO->pGetParameters = NULL;
pCO->pPostParameters = NULL;
pCO->lContentMax = CONTENT_MAX;
pCO->lFileMax = FILE_MAX;
#ifdef WIN32
pCO->dwIsapiBufferSize = ISAPI_BUFFER;
#endif
pCO->fMethods = CGI_METHOD_GET | CGI_METHOD_POST | CGI_METHOD_UPL;
pCO->pszDebugFile = NULL;
pCO->pfStdIn = NULL;
pCO->pfStdOut = NULL;
pCO->pfEnv = NULL;
pCO->pEmbed = NULL;
}
#ifdef WIN32
/*POD
=section InitIsapi
=H Initialize a CgiObject with default values
=abstract
This function initializes a CgiObject filling the default values
to handle the http request parameters via the ISAPI interface.
=end
This function initializes a CgiObject filling the default values
to handle the http request parameters via the ISAPI interface.
It actually does nothing else, but calls the CGI initialization function
R<InitCgi> and then alters the field T<fInterface> of the CGI object
to signal that this is an ISAPI interface handling case now.
/*FUNCTION*/
void cgi_InitIsapi(pCgiObject pCO,
LPEXTENSION_CONTROL_BLOCK lpECB
){
/*noverbatim
CUT*/
cgi_InitCgi(pCO);
pCO->lpECB = lpECB;
pCO->CharacterInput = IsapiGetChar;
pCO->pszNextChar = lpECB->lpbData;
pCO->cbAvailable = lpECB->cbAvailable;
pCO->fInterface = CGI_INTERFACE_ISAPI;
pCO->pszLocalBuffer = NULL;
pCO->pfStdIn = NULL;
pCO->pfStdOut = NULL;
pCO->pfEnv = NULL;
pCO->pEmbed = NULL;
}
#else
void cgi_InitIsapi(pCgiObject pCO,
LPEXTENSION_CONTROL_BLOCK lpECB
){
/* on UNIX we do nothing */
}
#endif
/*POD
=section ReadHttpRequest
=H Read the http request data
=abstract
This function reads the http request data and stores in linked lists available to query the
values.
=end
The application program should call this function to process the CGI input data. The parameter
T<pCO> should point to an initialized R<InitCgi> structure. The function decides what type of
input handling is needed, reads the http request and stores them in the appropriate fields
avaiable for later query.
/*FUNCTION*/
long cgi_ReadHttpRequest(pCgiObject pCO
){
/*noverbatim
CUT*/
char LocalBuffer[1024],*s,*r;
long w;
switch( pCO->fInterface ){
case CGI_INTERFACE_ISAPI:
/* ISAPI methods need tamporary space to store the header
variables. This is needed because the ISAPI interface does
not return a pointer to a constant string but rather copies
the value to a buffer that we have to provide. The pointers
in the DebugStore are just fine for the purpose. */
pCO->pDebugInfo = ALLOC(sizeof(DebugStore));
if( pCO->pDebugInfo == NULL )return CGI_ERROR_MEMORY_LOW;
memset(pCO->pDebugInfo,0,sizeof(DebugStore));
case CGI_INTERFACE_CGI:
case CGI_INTERFACE_DEBUG:
RetryWithDebugMode:
if( NULL != (s = cgi_RequestMethod(pCO)) ){
w = 0;
if( !strcmp(s,"GET") )w = CGI_METHOD_GET;
else
if( !strcmp(s,"HEAD") )w = CGI_METHOD_HEAD;
if( w ){
if( ! (pCO->fMethods&w) )return CGI_ERROR_METHOD_NOTALL;
return cgi_GetGetParameters(pCO);
}
}
if( s && !strcmp(s,"POST") ){
if( ! (pCO->fMethods&CGI_METHOD_POST) )return CGI_ERROR_METHOD_NOTALL;
r=cgi_ContentLength(pCO);
pCO->lContentLength = r ? atol( r ) : 0 ;
if( pCO->lContentLength > pCO->lContentMax )return CGI_ERROR_BIG_CONTENT;
if( (r=cgi_ContentType(pCO)) && ! memcmp(r,"multipart/form-data",19) ){
if( ! (pCO->fMethods&CGI_METHOD_UPL) )return CGI_ERROR_METHOD_NOTALL;
return cgi_GetMultipartParameters(pCO);
}
else return cgi_GetPostParameters(pCO);
}
/* if it is already DEBUG then there is no way out */
if( pCO->fInterface == CGI_INTERFACE_DEBUG )return CGI_ERROR_INVALID_METHOD;
/* if this is neither GET nor POST then we try to switch to debug more */
pCO->fInterface = CGI_INTERFACE_DEBUG;
#define READL(x) if( fgets(LocalBuffer,1024,DEBUGFP) ){\
LocalBuffer[w=strlen(LocalBuffer)-2] = (char)0; /* remove terminating \r\n (we read binary)*/ \
pCO->pDebugInfo->x = ALLOC(w);\
if( pCO->pDebugInfo->x == NULL )return CGI_ERROR_MEMORY_LOW;\
strcpy(pCO->pDebugInfo->x,LocalBuffer);\
}else pCO->pDebugInfo->x = "";
pCO->pDebugInfo = ALLOC(sizeof(DebugStore));
if( pCO->pDebugInfo == NULL )return CGI_ERROR_MEMORY_LOW;
if( pCO->pszDebugFile == NULL )return CGI_ERROR_NO_DEBUG_FILE;
DEBUGFP = fopen(pCO->pszDebugFile,"rb");
if( DEBUGFP == NULL )return CGI_ERROR_NO_DEBUG_FILE;
READL(ServerSoftware);
READL(ServerName);
READL(GatewayInterface);
READL(ServerProtocol);
READL(ServerPort);
READL(RequestMethod);
READL(PathInfo);
READL(PathTranslated);
READL(ScriptName);
READL(QueryString);
READL(RemoteHost);
READL(RemoteAddress);
READL(AuthType);
READL(RemoteUser);
READL(RemoteIdent);
READL(ContentType);
READL(ContentLength);
READL(UserAgent);
READL(Cookie);
pCO->CharacterInput = DebugGetChar;
goto RetryWithDebugMode;
case CGI_INTERFACE_NSAPI:
return CGI_ERROR_NOTIMP;
case CGI_INTERFACE_FCGI:
return CGI_ERROR_NOTIMP;
}
return CGI_ERROR_INVALID_METHOD;
}
/*POD
=section PostParam
=H Query a POST parameter
=abstract
Use this function to get the value of a POST parameter
=end
The argument T<pszParam> should point to a zchar string
containing the name of a POST parameter. The function returns
the pointer to a constant string containing the value fo the parameter
or NULL if there is no such parameter.
/*FUNCTION*/
char *cgi_PostParam(pCgiObject pCO,
char *pszParam
){
/*noverbatim
If there are more parameters with the same name only the first occurence is retrieved. Use the
function R<PostParamEx> to iterate through all the parameters with a single name.
CUT*/
pSymbolList p;
p = pCO->pPostParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->value ? p->value : "";
p = p->next;
}
return NULL;
}
/*POD
=section GetParam
=H Query a GET parameter
=abstract
Use this function to get the value of a GET parameter
=end
The argument T<pszParam> should point to a zchar string
containing the name of a GET parameter. The function returns
the pointer to a constant string containing the value fo the parameter
or NULL if there is no such parameter.
/*FUNCTION*/
char *cgi_GetParam(pCgiObject pCO,
char *pszParam
){
/*noverbatim
If there are more parameters with the same name only the first occurence is retrieved. Use the
function R<GetParamEx> to iterate through all the parameters with a single name.
CUT*/
pSymbolList p;
p = pCO->pGetParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->value ? p->value : "";
p = p->next;
}
return NULL;
}
/*POD
=section PostParamEx
=H Query POST parameter extended
=abstract
Use this function to get the next value of a POST parameter if the parameter is expected to be present
in the HTTP request more than once.
=end
This function gets the next value of the POST parameter. The name of the POST parameter should be
given by the string T<pszParam>. If T<pszParam> is NULL the next parameter is returned without name comparison.
This way a program can retrieve all the CGI parameters.
The pointer T<p> should point to a pointer. This pointer
(the one that T<p> points to and not T<p>) should be
initialized to NULL before the first call and should not be modified between calls.
The function searches the next occurence of the parameter and returns a pointer to the constant
string containing the value of theparameter or NULL if the parameter has no more occurence.
/*FUNCTION*/
char *cgi_PostParamEx(pCgiObject pCO,
char *pszParam,
pSymbolList *p
){
/*noverbatim
If a parameter is not expected to appear more than once use the function R<PostParam>.
CUT*/
if( *p == NULL )
*p = pCO->pPostParameters;
else
*p = (*p)->next;
while( *p ){
if( !pszParam || !strcmp((*p)->symbol,pszParam) )
return (*p)->value ? (*p)->value : "";
*p = (*p)->next;
}
return NULL;
}
/*POD
=section GetParamEx
=H Query GET parameter extended
=abstract
Use this function to get the next value of a GET parameter if the parameter is expected to be present
in the HTTP request more than once.
=end
This function gets the next value of the GET parameter. The name of the GET parameter should be
given by the string T<pszParam>. If T<pszParam> is NULL the next parameter is returned without name comparison.
This way a program can retrieve all the CGI parameters.
The pointer T<p> should point to a pointer. This pointer
(the one that T<p> points to and not T<p>) should be
initialized to NULL before the first call and should not be modified between calls.
The function searches the next occurence of the parameter and returns a pointer to the constant
string containing the value of theparameter or NULL if the parameter has no more occurence.
/*FUNCTION*/
char *cgi_GetParamEx(pCgiObject pCO,
char *pszParam,
pSymbolList *p
){
/*noverbatim
If a parameter is not expected to appear more than once use the function R<GetParam>.
CUT*/
if( *p == NULL )
*p = pCO->pGetParameters;
else
*p = (*p)->next;
while( *p ){
if( !pszParam || !strcmp((*p)->symbol,pszParam) )
return (*p)->value ? (*p)->value : "";
*p = (*p)->next;
}
return NULL;
}
/*POD
=section FILEp
=H Query a POST parameter
=abstract
Use this function to get the file pointer to the temporary uploaded file.
=end
The argument T<pszParam> should point to a zchar string
containing the name of a POST parameter, which is an uploaded
file and is stored in a temporary file.
/*FUNCTION*/
FILE *cgi_FILEp(pCgiObject pCO,
char *pszParam
){
/*noverbatim
CUT*/
pSymbolList p;
p = pCO->pPostParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->fp;
p = p->next;
}
return NULL;
}
/*POD
=section OriginalFileName
=H Query a POST parameter
=abstract
Use this function to get the file name of an uploaded file.
=end
The argument T<pszParam> should point to a zchar string
containing the name of a POST parameter, which is an uploaded
file and is stored in a temporary file.
The return value points to a zchar string containing the original
file name as it was given in the header T<Content-Disposition>.
/*FUNCTION*/
char *cgi_OriginalFileName(pCgiObject pCO,
char *pszParam
){
/*noverbatim
CUT*/
pSymbolList p;
p = pCO->pPostParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->file;
p = p->next;
}
return NULL;
}
/*POD
=section FileLength
=H Query the length of an uploaded file
=abstract
Use this function to get the length of an uploaded file.
=end
The argument T<pszParam> should point to a zchar string
containing the name of a POST parameter, which is an uploaded
file and is stored in a temporary file.
The return value is a long, which is the number of characters in the
uploaded file.
/*FUNCTION*/
long cgi_FileLength(pCgiObject pCO,
char *pszParam
){
/*noverbatim
CUT*/
pSymbolList p;
p = pCO->pPostParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->len;
p = p->next;
}
return 0;
}
/*POD
=section PartHeader
=H Query a POST parameter
=abstract
Use this function to get the pointer to the header of a multipart part.
=end
The argument T<pszParam> should point to a zchar string
containing the name of a POST parameter, which is an uploaded
file and is stored in a temporary file.
The return value points to header list. This pointer should be used as an argument to
the function R<Header>.
/*FUNCTION*/
pSymbolList cgi_PartHeader(pCgiObject pCO,
char *pszParam
){
/*noverbatim
CUT*/
pSymbolList p;
p = pCO->pPostParameters;
while( p ){
if( !strcmp(p->symbol,pszParam) )return p->pHeaders;
p = p->next;
}
return NULL;
}
/*POD
=section Header
=H Get a header value
This function returns a pointer to a zero terminated string containing
the value associated with the reqiested header field, or returns NULL
if the header was not present.
The argument T<symbol> shoud point to a ZCHAR string containing the
header symbol we search. The header is searched case insensitive, therefore
T<Content-Type> and T<Content-type> are equivalent.
B<Never use the trailing colon> after the header name.
The third parameter T<pHeader> should point to a header list. Such a hreader
list ids returned by the function R<ReadHeader> when a multipart form data
is read and stored for the uploaded file information.
/*FUNCTION*/
char *cgi_Header(pCgiObject pCO,
char *symbol,
pSymbolList pHeader
){
/*noverbatim
CUT*/
while( pHeader ){
if( ! stricmp(pHeader->symbol,symbol) )return pHeader->value;
pHeader = pHeader->next;
}
return NULL;
}
/*POD
=section Environment
=H Functions to return the usual environment variables
=abstract
Get the values of several CGI environment variables.
=end
These functions return the usual environment variables
of a CGI program. The CGI code should call these functions
and don't call T<getenv> directly because calling these
functions hide the interface and the application programs
can be easily ported to run using ISAPI, NSAPI, FCGI etc.
The functions provided:
=itemize
=item T<ServerSoftware>
=item T<ServerName>
=item T<GatewayInterface>
=item T<ServerProtocol>
=item T<ServerPort>
=item T<RequestMethod>
=item T<PathInfo>
=item T<PathTranslated>
=item T<ScriptName>
=item T<QueryString>
=item T<RemoteHost>
=item T<RemoteAddress>
=item T<AuthType>
=item T<RemoteUser>
=item T<RemoteIdent>
=item T<ContentType>
=item T<ContentLength>
=item T<UserAgent>
=item T<Cookie>
=noitemize
CUT*/
#define ISAPIVAR(X,Y) \
if( pCO->pDebugInfo->X )return pCO->pDebugInfo->X;\
{ DWORD cbBuffer;\
cbBuffer = 0;\
pCO->lpECB->GetServerVariable(pCO->lpECB->ConnID,Y,NULL,&cbBuffer);\
if( cbBuffer == 0 )return NULL;\
pCO->pDebugInfo->X = ALLOC(cbBuffer);\
if( pCO->pDebugInfo->X == NULL )return NULL;\
pCO->lpECB->GetServerVariable(pCO->lpECB->ConnID,Y,pCO->pDebugInfo->X,&cbBuffer);\
return pCO->pDebugInfo->X;}
/*FUNCTION*/
char *cgi_Referer(pCgiObject pCO
){
switch( pCO->fInterface ){
case CGI_INTERFACE_CGI:
return _getenv("HTTP_REFERER");
#ifdef WIN32
case CGI_INTERFACE_ISAPI:
ISAPIVAR(Cookie,"HTTP_REFERER")
#endif
case CGI_INTERFACE_NSAPI:
return NULL;
case CGI_INTERFACE_FCGI:
return NULL;
case CGI_INTERFACE_DEBUG:
return NULL;
}
return NULL;
}
/*FUNCTION*/
char *cgi_Cookie(pCgiObject pCO
){
switch( pCO->fInterface ){
case CGI_INTERFACE_CGI:
return _getenv("HTTP_COOKIE");
#ifdef WIN32
case CGI_INTERFACE_ISAPI:
ISAPIVAR(Cookie,"HTTP_COOKIE")
#endif
case CGI_INTERFACE_NSAPI:
return NULL;
case CGI_INTERFACE_FCGI:
return NULL;
case CGI_INTERFACE_DEBUG:
return pCO->pDebugInfo->Cookie;
}
return NULL;
}
/*FUNCTION*/
char *cgi_ServerSoftware(pCgiObject pCO
){
switch( pCO->fInterface ){
case CGI_INTERFACE_CGI:
return _getenv("SERVER_SOFTWARE");
#ifdef WIN32
case CGI_INTERFACE_ISAPI:
ISAPIVAR(ServerSoftware,"SERVER_SOFTWARE")
#endif
case CGI_INTERFACE_NSAPI:
return NULL;
case CGI_INTERFACE_FCGI:
return NULL;
case CGI_INTERFACE_DEBUG:
return pCO->pDebugInfo->ServerSoftware;
}
return NULL;
}
/*FUNCTION*/
char *cgi_ServerName(pCgiObject pCO
){
switch( pCO->fInterface ){
case CGI_INTERFACE_CGI:
return _getenv("SERVER_NAME");
#ifdef WIN32
case CGI_INTERFACE_ISAPI:
ISAPIVAR(ServerName,"SERVER_NAME")
#endif
case CGI_INTERFACE_NSAPI:
return NULL;
case CGI_INTERFACE_FCGI:
return NULL;