uncgi.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. unit uncgi;
  2. {
  3. UNCGI UNIT 2.0.9
  4. ----------------
  5. }
  6. interface
  7. uses
  8. strings
  9. {$ifdef linux}
  10. ,linux
  11. {$endif}
  12. ;
  13. {***********************************************************************}
  14. const
  15. maxquery = 100;
  16. hextable : array[0..15] of char=('0','1','2','3','4','5','6','7',
  17. '8','9','A','B','C','D','E','F');
  18. uncgi_version = 'UNCGI 2.0.9';
  19. uncgi_year = '1999';
  20. maintainer_name = 'Your Name Here';
  21. maintainer_email= '[email protected]';
  22. Type cgi_error_proc = procedure (Const Proc,Err : String);
  23. var
  24. get_nodata : boolean;
  25. query_read : word;
  26. query_array : array[1..2,1..maxquery] of pchar;
  27. uncgi_error : cgi_error_proc;
  28. {***********************************************************************}
  29. { FUNCTION
  30. This function returns the REQUEST METHOD of the CGI-BIN script
  31. Input - Nothing
  32. Output - [GET|POST]
  33. }
  34. function http_request_method: pchar;
  35. { FUNCTION
  36. This function returns the "referring" page. i.e. the page you followed
  37. the link to this CGI-BIN from
  38. Input - Nothing
  39. Output - [http://somewhere.a.tld]
  40. }
  41. function http_referer: pchar;
  42. { FUNCTION
  43. This function returns the users's USER AGENT, the browser name etc.
  44. Input - Nothing
  45. Output - user agent string
  46. }
  47. function http_useragent: pchar;
  48. { FUNCTION
  49. This function returns a value from an id=value pair
  50. Input - The identifier you want the value from
  51. Output - If the identifier was found, the resulting value is
  52. the output, otherwise the output is NIL
  53. }
  54. function get_value(id: pchar): pchar;
  55. { PROCEDURE
  56. This procedure writes the content-type to the screen
  57. Input - The content type in MIME format
  58. Output - Nothing
  59. Example - set_content('text/plain');
  60. set_content('text/html');
  61. }
  62. procedure set_content(ctype: string);
  63. procedure cgi_init;
  64. procedure cgi_deinit;
  65. implementation
  66. {$ifdef win32}
  67. Var EnvP : PChar;
  68. EnvLen : Longint;
  69. OldExitProc : Pointer;
  70. function GetEnvironmentStrings : pchar; external 'kernel32' name 'GetEnvironmentStringsA';
  71. function FreeEnvironmentStrings(p : pchar) : longbool; external 'kernel32' name 'FreeEnvironmentStringsA';
  72. Function GetEnv(envvar: string): pchar;
  73. { Getenv that can return environment vars of length>255 }
  74. var s : String;
  75. i,len : longint;
  76. hp : pchar;
  77. begin
  78. s:=Envvar+#0;
  79. getenv:=Nil;
  80. hp:=envp;
  81. while hp[0]<>#0 do
  82. begin
  83. len:=strlen(hp);
  84. i:=Longint(strscan(hp,'='))-longint(hp);
  85. if StrLIComp(@s[1],HP,i-1)=0 then
  86. begin
  87. Len:=Len-i;
  88. getmem (getenv,len);
  89. Move(HP[I+1],getenv^,len+1);
  90. break;
  91. end;
  92. { next string entry}
  93. hp:=hp+len+1;
  94. end;
  95. end;
  96. Procedure FInitWin32CGI;
  97. begin
  98. { Free memory }
  99. FreeMem (EnvP,EnvLen);
  100. ExitProc:=OldExitProc;
  101. end;
  102. Procedure InitWin32CGI;
  103. var s : String;
  104. i,len : longint;
  105. hp,p : pchar;
  106. begin
  107. { Make a local copy of environment}
  108. p:=GetEnvironmentStrings;
  109. hp:=p;
  110. envp:=Nil;
  111. envlen:=0;
  112. while hp[0]<>#0 do
  113. begin
  114. len:=strlen(hp);
  115. hp:=hp+len+1;
  116. EnvLen:=Envlen+len+1;
  117. end;
  118. GetMem(EnvP,Envlen);
  119. Move(P^,EnvP^,EnvLen);
  120. FreeEnvironmentStrings(p);
  121. OldExitProc:=ExitProc;
  122. ExitProc:=@FinitWin32CGI;
  123. end;
  124. {$endif}
  125. var
  126. done_init : boolean;
  127. procedure set_content(ctype: string);
  128. begin
  129. writeln('Content-Type: ',ctype);
  130. writeln;
  131. end;
  132. function http_request_method: pchar;
  133. begin
  134. http_request_method :=getenv('REQUEST_METHOD');
  135. end;
  136. function http_referer: pchar;
  137. begin
  138. http_referer :=getenv('HTTP_REFERER');
  139. end;
  140. function http_useragent: pchar;
  141. begin
  142. http_useragent :=getenv('HTTP_USER_AGENT');
  143. end;
  144. function hexconv(h1,h2: char): char;
  145. var
  146. cnt : byte;
  147. thex : byte;
  148. begin
  149. for cnt :=0 to 15 do if upcase(h1)=hextable[cnt] then thex := cnt * 16;
  150. for cnt :=0 to 15 do if upcase(h2)=hextable[cnt] then thex := thex + cnt;
  151. hexconv := chr(thex);
  152. end;
  153. procedure def_uncgi_error(pname,perr: string);
  154. begin
  155. set_content('text/html');
  156. writeln('<html><head><title>UNCGI ERROR</title></head>');
  157. writeln('<body>');
  158. writeln('<center><hr><h1>UNCGI ERROR</h1><hr></center><br><br>');
  159. writeln('UnCgi encountered the following error: <br>');
  160. writeln('<ul><br>');
  161. writeln('<li> procedure: ',pname,'<br>');
  162. writeln('<li> error: ',perr,'<br><hr>');
  163. writeln(
  164. '<h5><p><i>uncgi (c) ',uncgi_year,' ',maintainer_name,
  165. { skelet fix }
  166. '<a href="mailto:',maintainer_email,'">',
  167. maintainer_email,'</a></i></p></h5>');
  168. writeln('</body></html>');
  169. halt;
  170. end;
  171. function get_value(id: pchar): pchar;
  172. var
  173. cnt : word;
  174. begin
  175. if not done_init then
  176. begin
  177. get_value :=NIL;
  178. exit;
  179. end;
  180. for cnt :=1 to query_read do
  181. if strcomp(strupper(id),strupper(query_array[1,cnt]))=0 then
  182. begin
  183. get_value := query_array[2,cnt];
  184. exit;
  185. end;
  186. get_value:=NIL;
  187. end;
  188. Function UnEscape(QueryString: PChar): PChar;
  189. var
  190. qunescaped : pchar;
  191. sptr : longint;
  192. cnt : word;
  193. qslen : longint;
  194. begin
  195. qslen:=strlen(QueryString);
  196. if qslen=0 then
  197. begin
  198. get_nodata :=true;
  199. exit;
  200. end
  201. else
  202. get_nodata :=false;
  203. { skelet fix }
  204. getmem(qunescaped,qslen+1);
  205. if qunescaped=nil then
  206. begin
  207. writeln ('Oh-oh');
  208. halt;
  209. end;
  210. sptr :=0;
  211. for cnt := 0 to qslen do
  212. begin
  213. case querystring[cnt] of
  214. '+': qunescaped[sptr] := ' ';
  215. '%': begin
  216. qunescaped[sptr] :=
  217. hexconv(querystring[cnt+1], querystring[cnt+2]);
  218. inc(cnt,2);
  219. end;
  220. else
  221. qunescaped[sptr] := querystring[cnt];
  222. end;
  223. inc(sptr);
  224. { skelet fix }
  225. qunescaped[sptr]:=#0;
  226. end;
  227. UnEscape:=qunescaped;
  228. end;
  229. Function Chop(QunEscaped : PChar) : Longint;
  230. var
  231. qptr : word;
  232. cnt : word;
  233. qslen : longint;
  234. p : pchar;
  235. begin
  236. qptr := 1;
  237. qslen:=strlen(QUnescaped);
  238. query_array[1,qptr] := qunescaped;
  239. for cnt := 0 to qslen-1 do
  240. case qunescaped[cnt] of
  241. '=': begin
  242. qunescaped[cnt] := #0;
  243. { save address }
  244. query_array[2,qptr] := @qunescaped[cnt+1];
  245. end;
  246. '&': begin
  247. qunescaped[cnt] := #0;
  248. { Unescape previous one. }
  249. query_array[2,qptr]:=unescape(query_array[2,qptr]);
  250. inc(qptr);
  251. query_array[1,qptr] := @qunescaped[cnt+1];
  252. end;
  253. end; { Case }
  254. { Unescape last one. }
  255. query_array[2,qptr]:=unescape(query_array[2,qptr]);
  256. Chop :=qptr;
  257. end;
  258. procedure cgi_read_get_query;
  259. var
  260. querystring : pchar;
  261. qunescaped : pchar;
  262. qslen : longint;
  263. begin
  264. querystring :=strnew(getenv('QUERY_STRING'));
  265. if querystring=NIL then uncgi_error('cgi_read_get_query()',
  266. 'No QUERY_STRING passed from server!');
  267. qslen :=strlen(querystring);
  268. if qslen=0 then
  269. begin
  270. get_nodata :=true;
  271. exit;
  272. end
  273. else
  274. get_nodata :=false;
  275. query_read:=Chop(QueryString);
  276. done_init :=true;
  277. end;
  278. procedure cgi_read_post_query;
  279. var
  280. querystring : pchar;
  281. qunescaped : pchar;
  282. qslen : longint;
  283. sptr : longint;
  284. clen : string;
  285. ch : char;
  286. begin
  287. if getenv('CONTENT_LENGTH')=Nil then
  288. uncgi_error('cgi_read_post_query()',
  289. 'No content length passed from server!');
  290. clen:=strpas (getenv('CONTENT_LENGTH'));
  291. val(clen,qslen);
  292. if upcase(strpas(getenv('CONTENT_TYPE')))<>'APPLICATION/X-WWW-FORM-URLENCODED'
  293. then uncgi_error('cgi_read_post_query()',
  294. 'No content type passed from server!');
  295. getmem(querystring,qslen+1);
  296. sptr :=0;
  297. while sptr<>qslen do
  298. begin
  299. read(ch);
  300. pchar(longint(querystring)+sptr)^ :=ch;
  301. inc(sptr);
  302. end;
  303. { !!! force null-termination }
  304. pchar(longint(querystring)+sptr)^ :=#0;
  305. query_read:=Chop(QueryString);
  306. done_init :=true;
  307. end;
  308. procedure cgi_init;
  309. var
  310. rmeth : pchar;
  311. begin
  312. rmeth :=http_request_method;
  313. if rmeth=nil then
  314. begin
  315. uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
  316. exit;
  317. end;
  318. if strcomp('POST',rmeth)=0 then cgi_read_post_query else
  319. if strcomp('GET',rmeth)=0 then cgi_read_get_query else
  320. uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
  321. end;
  322. procedure cgi_deinit;
  323. var
  324. ctr : longint;
  325. begin
  326. done_init :=false;
  327. query_read :=0;
  328. fillchar(query_array,sizeof(query_array),0);
  329. end;
  330. begin
  331. {$ifdef win32}
  332. InitWin32CGI;
  333. {$endif}
  334. uncgi_error:=@def_uncgi_error;
  335. done_init :=false;
  336. fillchar(query_array,sizeof(query_array),0);
  337. end.
  338. {
  339. UNCGI UNIT 2.0.6
  340. -------------------------------------------
  341. HISTORY
  342. - 1.0.0 03/07/97
  343. ----------------
  344. Only GET method implemented
  345. - 1.0.1 05/07/97
  346. ----------------
  347. + Extra procedures for getting extra information:
  348. * referrer
  349. * user agent
  350. * request method
  351. + Crude POST reading
  352. - 1.1.0 14/07/97
  353. ----------------
  354. + Bugfix in POST reading, still doesn't work right.
  355. - 2.0.0 02/08/97
  356. ----------------
  357. Started from scratch, POST reading still limited to
  358. 255 characters max. for value
  359. - 2.0.1 04/08/97
  360. ---------------
  361. Conversion from strings to pchar done by
  362. Michael van Canneyt. (Routines "UnEscape" and "Chop")
  363. Small changes made to convert everything to pchar usage.
  364. - 2.0.2 22/04/98
  365. ---------------
  366. tested with Apache HTTP Server and bugfix in pchar conversion,
  367. PChar(Longint(PChar)+x)) syntax modified to PChar[x]
  368. by Laszlo Nemeth.
  369. - 2.0.3 05/06/98
  370. ---------------
  371. Added maintainer_name,maintainer_email,uncgi_year
  372. diff from Bernhard van Staveren.
  373. - 2.0.4 09/07/98
  374. ---------------
  375. Some more error checking.
  376. cgi_error is now a procedural variable with the old
  377. cgi_erro procedure as a default value, allowing recovery
  378. incase of an error, and not immediate shutdown.
  379. - 2.0.6 02/28/99
  380. --------------
  381. The unit can be used under Win32 also.
  382. - 2.0.7 04/04/99
  383. --------------
  384. Inversed order of Chop and unescape, thus fixing bug of possible
  385. '=' and '&' characters in values.
  386. - 2.0.8 04/08/99
  387. --------------
  388. Fixed bug in unescape, qslen wasn't initialized.
  389. - 2.0.9 05/16/99
  390. --------------
  391. Some fixes by Georgi Georgiev
  392. }