123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- unit uncgi;
- {
- $Id$
- UNCGI UNIT 2.0.11
- ----------------
- }
- {$ASSERTIONS ON}
- interface
- uses
- strings
- {$IFDEF OS2}
- ,DosCalls
- {$ENDIF OS2}
- ;
- {***********************************************************************}
- const
- maxquery = 100;
- uncgi_version = 'UNCGI 2.1.1';
- uncgi_year = '1999';
- maintainer_name = 'Your Name Here';
- maintainer_email= '[email protected]';
- Type
- cgi_error_proc = procedure (Const Proc,Err : String);
- PCgiVar=^TCgiVar;
- TCgiVar=Record
- Name:PChar;
- NbrValues:LongInt;
- Value:PPChar
- end;
- var
- cgiEnvC:LongInt;
- cgiEnvP:PCgiVar;
- get_nodata : boolean;
- query_read : Cardinal;
- uncgi_error : cgi_error_proc;
- {***********************************************************************}
- { FUNCTION
- This function returns the REQUEST METHOD of the CGI-BIN script
- Input - Nothing
- Output - [GET|POST]
- }
- function http_request_method: pchar;
- { FUNCTION
- This function returns the "referring" page. i.e. the page you followed
- the link to this CGI-BIN from
- Input - Nothing
- Output - [http://somewhere.a.tld]
- }
- function http_referer: pchar;
- { FUNCTION
- This function returns the IP address of the client.
- Input - Nothing
- Output - an internet IP address.
- }
- function http_remote: pchar;
- { FUNCTION
- This function returns the users's USER AGENT, the browser name etc.
- Input - Nothing
- Output - user agent string
- }
- function http_useragent: pchar;
- { FUNCTION
- This function returns a value from an id=value pair
- Input - The identifier you want the value from
- Output - If the identifier was found, the resulting value is
- the output, otherwise the output is NIL
- }
- function get_value(id: pchar): pchar;
- { FUNCTION
- This function extracts array of values for the
- same variable (used in some checkbox forms)
- Use like in this example:
- v:=get_value('some_id');
- while v<>'' do begin
- Do_something_with(v);
- v:=get_next_value;
- end;
- }
- function get_next_value:PChar;
- { PROCEDURE
- This procedure writes the content-type to the screen
- Input - The content type in MIME format
- Output - Nothing
- Example - set_content('text/plain');
- set_content('text/html');
- }
- procedure set_content(const ctype: string);
- { Function to get the requested URL }
- function http_url: pchar;
- procedure cgi_init;
- procedure cgi_deinit;
- implementation
- {$IFDEF OS2}
- function GetEnv (EnvVar: string): PChar;
- var P: PChar;
- begin
- EnvVar := EnvVar + #0;
- if DosScanEnv (@EnvVar [1], P) = 0 then GetEnv := P else GetEnv := nil;
- end;
- {$ENDIF OS2}
- {$ifdef win32}
- Var EnvP : PChar;
- EnvLen : Longint;
- OldExitProc : Pointer;
- function GetEnvironmentStrings : pchar; external 'kernel32' name 'GetEnvironmentStringsA';
- function FreeEnvironmentStrings(p : pchar) : longbool; external 'kernel32' name 'FreeEnvironmentStringsA';
- Procedure FInitWin32CGI;
- begin
- { Free memory }
- FreeMem (EnvP,EnvLen);
- ExitProc:=OldExitProc;
- end;
- Procedure InitWin32CGI;
- var s : String;
- i,len : longint;
- hp,p : pchar;
- begin
- { Make a local copy of environment}
- p:=GetEnvironmentStrings;
- hp:=p;
- envp:=Nil;
- envlen:=0;
- while hp[0]<>#0 do
- begin
- len:=strlen(hp);
- hp:=hp+len+1;
- EnvLen:=Envlen+len+1;
- end;
- GetMem(EnvP,Envlen);
- Move(P^,EnvP^,EnvLen);
- FreeEnvironmentStrings(p);
- OldExitProc:=ExitProc;
- ExitProc:=@FinitWin32CGI;
- end;
- Function GetEnv(envvar: string): pchar;
- { Getenv that can return environment vars of length>255 }
- var s : String;
- i,len : longint;
- hp : pchar;
- begin
- s:=Envvar+#0;
- getenv:=Nil;
- hp:=envp;
- while hp[0]<>#0 do
- begin
- len:=strlen(hp);
- i:=Longint(strscan(hp,'='))-longint(hp);
- if StrLIComp(@s[1],HP,i-1)=0 then
- begin
- Len:=Len-i;
- getmem (getenv,len);
- Move(HP[I+1],getenv^,len+1);
- break;
- end;
- { next string entry}
- hp:=hp+len+1;
- end;
- end;
- {$endif}
- {$ifdef GO32V2}
- Function GetEnv(envvar: string): pchar;
- var
- hp : ppchar;
- hs : string;
- eqpos : longint;
- begin
- envvar:=upcase(envvar);
- hp:=envp;
- getenv:=nil;
- while assigned(hp^) do
- begin
- hs:=strpas(hp^);
- eqpos:=pos('=',hs);
- if copy(hs,1,eqpos-1)=envvar then
- begin
- getenv:=hp^+eqpos;
- exit;
- end;
- inc(hp);
- end;
- end;
- {$endif}
- {$ifdef unix}
- Function GetEnv(P:string):Pchar;
- {
- Searches the environment for a string with name p and
- returns a pchar to it's value.
- A pchar is used to accomodate for strings of length > 255
- }
- var
- ep : ppchar;
- found : boolean;
- Begin
- p:=p+'='; {Else HOST will also find HOSTNAME, etc}
- ep:=envp;
- found:=false;
- if ep<>nil then
- begin
- while (not found) and (ep^<>nil) do
- begin
- if strlcomp(@p[1],(ep^),length(p))=0 then
- found:=true
- else
- inc(ep);
- end;
- end;
- if found then
- getenv:=ep^+length(p)
- else
- getenv:=nil;
- end;
- {$endif unix}
- var
- done_init : boolean;
- procedure set_content(const ctype: string);
- begin
- writeln('Content-Type: ',ctype);
- writeln;
- end;
- function http_request_method: pchar;
- begin
- http_request_method :=getenv('REQUEST_METHOD');
- end;
- function http_referer: pchar;
- begin
- http_referer :=getenv('HTTP_REFERER');
- end;
- function http_useragent: pchar;
- begin
- http_useragent :=getenv('HTTP_USER_AGENT');
- end;
- function hexconv(h1,h2: char): char;
- function h2c(c:char):byte;
- begin
- case c of
- '0'..'9':h2c := ord(c) - ord('0');
- 'A'..'F':h2c := 10 + (ord(UpCase(c)) - ord('A'));
- end;
- end;
- begin
- HexConv:=Chr(h2c(h1)*16+h2c(h2));
- end;
- procedure def_uncgi_error(const pname,perr: string);
- begin
- set_content('text/html');
- writeln('<html><head><title>UNCGI ERROR</title></head>');
- writeln('<body>');
- writeln('<center><hr><h1>UNCGI ERROR</h1><hr></center><br><br>');
- writeln('UnCgi encountered the following error: <br>');
- writeln('<ul><br>');
- writeln('<li> procedure: ',pname,'<br>');
- writeln('<li> error: ',perr,'<br><hr>');
- writeln(
- '<h5><p><i>uncgi (c) ',uncgi_year,' ',maintainer_name,
- { skelet fix }
- '<a href="mailto:',maintainer_email,'">',
- maintainer_email,'</a></i></p></h5>');
- writeln('</body></html>');
- halt;
- end;
- var
- gv_cnt,gv_cnt_n:LongInt;
- function get_next_value:PChar;
- begin
- Assert(done_init,'Please call cgi_init() first');
- if gv_cnt>=cgiEnvC
- then
- Exit(Nil);
- with cgiEnvP[gv_cnt] do
- begin
- if gv_cnt_n>=NbrValues
- then
- Exit(Nil);
- get_next_value:=Value[gv_cnt_n];
- end;
- Inc(gv_cnt_n);
- end;
- function get_value(id: pchar): pchar;
- begin
- Assert(done_init,'Please call cgi_init() first');
- gv_cnt:=0;
- gv_cnt_n:=0;
- while(gv_cnt<cgiEnvC)and(StrComp(id,cgiEnvP[gv_cnt].Name)<>0)do
- Inc(gv_cnt);
- get_value:=get_next_value;
- end;
- Function UnEscape(QueryString: PChar): PChar;
- var
- qunescaped : pchar;
- sptr : longint;
- cnt : word;
- qslen : longint;
- begin
- qslen:=strlen(QueryString);
- if qslen=0 then
- begin
- Unescape:=Nil;
- get_nodata:=true;
- exit;
- end
- else
- get_nodata :=false;
- { skelet fix }
- {Escaped chain is usually longer than the unescaped chain}
- GetMem(qunescaped,qslen+1);
- if qunescaped=nil
- then
- uncgi_error('UnEscape()','Could not allocate memory');
- sptr :=0;
- { for cnt := 0 to qslen do +++++ use while instead of for }
- cnt:=0;
- while cnt<qslen do
- begin
- case querystring[cnt] of
- '+': qunescaped[sptr]:=' ';
- '%': begin
- qunescaped[sptr]:=hexconv(querystring[cnt+1], querystring[cnt+2]);
- inc(cnt,2); { <--- not allowed in for loops in pascal }
- end;
- else
- qunescaped[sptr] := querystring[cnt];
- end;
- inc(sptr);
- { skelet fix }
- qunescaped[sptr]:=#0;
- inc(cnt); { <-- don't forget to increment }
- end;
- UnEscape:=StrNew(qunescaped);
- FreeMem(qunescaped,qsLen+1);
- end;
- Function Chop(QueryString:PChar):Cardinal;
- var
- VarName,VarValue,name_pos,value_pos:PChar;
- sz,EnvCC:LongInt;
- p:Pointer;
- begin
- GetMem(cgiEnvP,MaxQuery*SizeOf(TCgiVar));
- name_pos:=QueryString;
- value_pos:=QueryString;
- repeat
- value_pos:=StrScan(name_pos,'=');
- if value_pos=Nil
- then
- value_pos:=StrEnd(name_pos)
- else
- Inc(value_pos);
- sz:=value_pos-name_pos-1;
- VarName:=StrAlloc(sz+1);
- StrLCopy(VarName,name_pos,sz);
- name_pos:=StrScan(name_pos,'&');
- if name_pos=Nil
- then
- sz:=StrLen(value_pos)
- else
- begin
- Inc(name_pos);
- sz:=name_pos-value_pos-1;
- end;
- VarValue:=StrAlloc(sz+1);
- StrLCopy(VarValue,value_pos,sz);
- EnvCC:=0;
- repeat
- with cgiEnvP[EnvCC] do
- begin
- if EnvCC=cgiEnvC
- then
- begin
- if cgiEnvC>=MaxQuery
- then
- uncgi_error('cgi_read_get_query()','Your are trying to use more than max varaibles allowed! Please change value of "MaxQuery" and recompile your program')
- else
- begin
- Name:=UnEscape(VarName);
- GetMem(Value,MaxQuery*SizeOf(PChar));
- NbrValues:=0;
- Inc(cgiEnvC);
- end;
- end;
- if StrComp(VarName,Name)=0
- then
- begin
- if NbrValues>=MaxQuery
- then
- uncgi_error('cgi_read_get_query()','Your are trying to use more than max values allowed for a given variable! Please change value of "MaxQuery" and recompile your program')
- else
- begin
- Value[NbrValues]:=UnEscape(VarValue);
- Inc(NbrValues);
- end;
- StrDispose(VarName);
- StrDispose(VarValue);
- break;
- end;
- end;
- Inc(EnvCC);
- until false;
- until name_pos=Nil;
- for EnvCC:=0 to cgiEnvC-1 do
- with cgiEnvP[EnvCC] do
- begin
- p:=Value;
- sz:=NbrValues*SizeOf(PChar);
- GetMem(Value,sz);
- Move(p^,Value^,sz);
- FreeMem(p,MaxQuery*SizeOf(PChar));
- end;
- p:=cgiEnvP;
- sz:=cgiEnvC*SizeOf(TCgiVar);
- GetMem(cgiEnvP,sz);
- Move(p^,cgiEnvP^,sz);
- FreeMem(p,MaxQuery*SizeOf(TCgiVar));
- Chop:=Abs(cgiEnvC);
- end;
- procedure cgi_read_get_query;
- var
- querystring : pchar;
- qslen : longint;
- begin
- querystring :=strnew(getenv('QUERY_STRING'));
- if querystring<>NIL
- then
- begin
- qslen :=strlen(querystring);
- if qslen=0
- then
- begin
- get_nodata :=true;
- exit;
- end
- else
- get_nodata :=false;
- query_read:=Chop(QueryString);
- end;
- StrDispose(QueryString);
- end;
- procedure cgi_read_post_query;
- var
- querystring : pchar;
- qslen : longint;
- sptr : longint;
- clen : string;
- ch : char;
- begin
- if getenv('CONTENT_LENGTH')<>Nil then
- begin
- clen:=strpas (getenv('CONTENT_LENGTH'));
- val(clen,qslen);
- if (upcase(strpas(getenv('CONTENT_TYPE')))='APPLICATION/X-WWW-FORM-URLENCODED')
- or (upcase(strpas(getenv('CONTENT_TYPE')))='TEXT/PLAIN')
- then
- begin
- getmem(querystring,qslen+1);
- sptr :=0;
- while sptr<>qslen do
- begin
- read(ch);
- QueryString[sptr]:=ch;
- inc(sptr);
- end;
- { !!! force null-termination }
- QueryString[sptr]:=#0;
- query_read:=Chop(QueryString);
- end;
- end;
- end;
- procedure cgi_init;
- var
- rmeth : pchar;
- begin
- Assert(NOT done_init,'cgi_init() was already called');
- query_read:=0;
- rmeth :=http_request_method;
- if rmeth=nil then
- begin
- uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
- exit;
- end;
- if strcomp('POST',rmeth)=0 then cgi_read_post_query else
- if strcomp('GET',rmeth)=0 then cgi_read_get_query else
- uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
- done_init :=true;
- end;
- procedure cgi_deinit;
- var
- i,j:LongInt;
- begin
- Assert(done_init,'Please call cgi_init() first');
- if cgiEnvC=0
- then
- Exit;
- for i:=0 to cgiEnvC-1 do
- with cgiEnvP[i] do
- begin
- StrDispose(Name);
- for j:=0 to NbrValues-1 do
- StrDispose(Value[j]);
- FreeMem(Value,NbrValues*SizeOf(PChar));
- end;
- FreeMem(cgiEnvP,cgiEnvC*SizeOf(TCgiVar));
- cgiEnvC:=0;
- end;
- Function http_url: pchar;
- begin
- http_url:=getenv('REQUEST_URI');
- end;
- function http_remote: pchar;
- begin
- http_remote :=getenv('REMOTE_ADDR');
- end;
- begin
- {$ifdef win32}
- InitWin32CGI;
- {$endif}
- uncgi_error:=@def_uncgi_error;
- done_init :=false;
- end.
- {
- HISTORY
- $Log$
- Revision 1.13 2003-09-27 12:07:31 peter
- * unix getenv added
- Revision 1.12 2003/07/16 12:56:03 mazen
- + using Assert to monitor done_init and get state of
- un_cgi initailization
- * renaming EnvP and EnvC to cgiEnvP and cgiEnvP
- to avoid confusion with regular EnvP and EnvC
- varaibles especially under win32 target
- * set_contents get parameter by address (const)
- Revision 1.11 2003/05/29 08:58:45 michael
- + Fixed inline error when building
- Revision 1.10 2003/05/27 20:50:18 mazen
- * New implemtation of HexConv
- * New implementation of Chop to fix an incompatibilty
- bug with SysUtils.
- * Replacing quary_array (static) by EnvP(dynamic)
- Revision 1.9 2002/10/24 17:25:36 sg
- * Fixed parsing of empty URL arguments (with missing "=")
- Revision 1.8 2002/10/18 05:43:53 michael
- + Fix of invalid pointer bug in unescape, from U. Maeder
- Revision 1.7 2002/10/10 05:48:20 michael
- Added http_remote and fixed determining of input method. Fix courtesy of Antal <[email protected]>
- Revision 1.6 2002/09/12 16:24:59 michael
- + Added http_url function from Michael Weinert
- Revision 1.5 2002/09/07 15:43:06 peter
- * old logs removed and tabs fixed
- Revision 1.4 2002/05/31 11:54:33 marco
- * Renamefest for 1.0, many 1.1.x spots patched also.
- Revision 1.3 2002/03/04 17:57:17 peter
- * updated example in comment
- Revision 1.2 2002/03/01 10:57:03 peter
- * get_next_value patch from Skelet
- Revision 1.1 2002/01/29 17:55:23 peter
- * splitted to base and extra
- }
|