uncgi.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. unit uncgi;
  2. {
  3. $Id$
  4. UNCGI UNIT 2.0.11
  5. ----------------
  6. }
  7. interface
  8. uses
  9. strings
  10. {$ifdef Unix}
  11. {$ifdef ver1_0}
  12. ,Linux
  13. {$else}
  14. ,Unix
  15. {$endif}
  16. {$endif}
  17. {$IFDEF OS2}
  18. ,DosCalls
  19. {$ENDIF OS2}
  20. ;
  21. {***********************************************************************}
  22. const
  23. maxquery = 100;
  24. hextable : array[0..15] of char=('0','1','2','3','4','5','6','7',
  25. '8','9','A','B','C','D','E','F');
  26. uncgi_version = 'UNCGI 2.0.11';
  27. uncgi_year = '1999';
  28. maintainer_name = 'Your Name Here';
  29. maintainer_email= '[email protected]';
  30. Type cgi_error_proc = procedure (Const Proc,Err : String);
  31. var
  32. get_nodata : boolean;
  33. query_read : word;
  34. query_array : array[1..2,1..maxquery] of pchar;
  35. uncgi_error : cgi_error_proc;
  36. {***********************************************************************}
  37. { FUNCTION
  38. This function returns the REQUEST METHOD of the CGI-BIN script
  39. Input - Nothing
  40. Output - [GET|POST]
  41. }
  42. function http_request_method: pchar;
  43. { FUNCTION
  44. This function returns the "referring" page. i.e. the page you followed
  45. the link to this CGI-BIN from
  46. Input - Nothing
  47. Output - [http://somewhere.a.tld]
  48. }
  49. function http_referer: pchar;
  50. { FUNCTION
  51. This function returns the IP address of the client.
  52. Input - Nothing
  53. Output - an internet IP address.
  54. }
  55. function http_remote: pchar;
  56. { FUNCTION
  57. This function returns the users's USER AGENT, the browser name etc.
  58. Input - Nothing
  59. Output - user agent string
  60. }
  61. function http_useragent: pchar;
  62. { FUNCTION
  63. This function returns a value from an id=value pair
  64. Input - The identifier you want the value from
  65. Output - If the identifier was found, the resulting value is
  66. the output, otherwise the output is NIL
  67. }
  68. function get_value(id: pchar): pchar;
  69. { FUNCTION
  70. This function extracts array of values for the
  71. same variable (used in some checkbox forms)
  72. Use like in this example:
  73. v:=get_value('some_id');
  74. while v<>'' do begin
  75. Do_something_with(v);
  76. v:=get_next_value('some_id');
  77. end;
  78. }
  79. function get_next_value(id: pchar): pchar;
  80. { PROCEDURE
  81. This procedure writes the content-type to the screen
  82. Input - The content type in MIME format
  83. Output - Nothing
  84. Example - set_content('text/plain');
  85. set_content('text/html');
  86. }
  87. procedure set_content(ctype: string);
  88. { Function to get the requested URL }
  89. function http_url: pchar;
  90. procedure cgi_init;
  91. procedure cgi_deinit;
  92. implementation
  93. {$IFDEF OS2}
  94. function GetEnv (EnvVar: string): PChar;
  95. var P: PChar;
  96. begin
  97. EnvVar := EnvVar + #0;
  98. if DosScanEnv (@EnvVar [1], P) = 0 then GetEnv := P else GetEnv := nil;
  99. end;
  100. {$ENDIF OS2}
  101. {$ifdef win32}
  102. Var EnvP : PChar;
  103. EnvLen : Longint;
  104. OldExitProc : Pointer;
  105. function GetEnvironmentStrings : pchar; external 'kernel32' name 'GetEnvironmentStringsA';
  106. function FreeEnvironmentStrings(p : pchar) : longbool; external 'kernel32' name 'FreeEnvironmentStringsA';
  107. Procedure FInitWin32CGI;
  108. begin
  109. { Free memory }
  110. FreeMem (EnvP,EnvLen);
  111. ExitProc:=OldExitProc;
  112. end;
  113. Procedure InitWin32CGI;
  114. var s : String;
  115. i,len : longint;
  116. hp,p : pchar;
  117. begin
  118. { Make a local copy of environment}
  119. p:=GetEnvironmentStrings;
  120. hp:=p;
  121. envp:=Nil;
  122. envlen:=0;
  123. while hp[0]<>#0 do
  124. begin
  125. len:=strlen(hp);
  126. hp:=hp+len+1;
  127. EnvLen:=Envlen+len+1;
  128. end;
  129. GetMem(EnvP,Envlen);
  130. Move(P^,EnvP^,EnvLen);
  131. FreeEnvironmentStrings(p);
  132. OldExitProc:=ExitProc;
  133. ExitProc:=@FinitWin32CGI;
  134. end;
  135. Function GetEnv(envvar: string): pchar;
  136. { Getenv that can return environment vars of length>255 }
  137. var s : String;
  138. i,len : longint;
  139. hp : pchar;
  140. begin
  141. s:=Envvar+#0;
  142. getenv:=Nil;
  143. hp:=envp;
  144. while hp[0]<>#0 do
  145. begin
  146. len:=strlen(hp);
  147. i:=Longint(strscan(hp,'='))-longint(hp);
  148. if StrLIComp(@s[1],HP,i-1)=0 then
  149. begin
  150. Len:=Len-i;
  151. getmem (getenv,len);
  152. Move(HP[I+1],getenv^,len+1);
  153. break;
  154. end;
  155. { next string entry}
  156. hp:=hp+len+1;
  157. end;
  158. end;
  159. {$endif}
  160. {$ifdef GO32V2}
  161. Function GetEnv(envvar: string): pchar;
  162. var
  163. hp : ppchar;
  164. hs : string;
  165. eqpos : longint;
  166. begin
  167. envvar:=upcase(envvar);
  168. hp:=envp;
  169. getenv:=nil;
  170. while assigned(hp^) do
  171. begin
  172. hs:=strpas(hp^);
  173. eqpos:=pos('=',hs);
  174. if copy(hs,1,eqpos-1)=envvar then
  175. begin
  176. getenv:=hp^+eqpos;
  177. exit;
  178. end;
  179. inc(hp);
  180. end;
  181. end;
  182. {$endif}
  183. var
  184. done_init : boolean;
  185. procedure set_content(ctype: string);
  186. begin
  187. writeln('Content-Type: ',ctype);
  188. writeln;
  189. end;
  190. function http_request_method: pchar;
  191. begin
  192. http_request_method :=getenv('REQUEST_METHOD');
  193. end;
  194. function http_referer: pchar;
  195. begin
  196. http_referer :=getenv('HTTP_REFERER');
  197. end;
  198. function http_useragent: pchar;
  199. begin
  200. http_useragent :=getenv('HTTP_USER_AGENT');
  201. end;
  202. function hexconv(h1,h2: char): char;
  203. var
  204. cnt : byte;
  205. thex : byte;
  206. begin
  207. for cnt :=0 to 15 do if upcase(h1)=hextable[cnt] then thex := cnt * 16;
  208. for cnt :=0 to 15 do if upcase(h2)=hextable[cnt] then thex := thex + cnt;
  209. hexconv := chr(thex);
  210. end;
  211. procedure def_uncgi_error(const pname,perr: string);
  212. begin
  213. set_content('text/html');
  214. writeln('<html><head><title>UNCGI ERROR</title></head>');
  215. writeln('<body>');
  216. writeln('<center><hr><h1>UNCGI ERROR</h1><hr></center><br><br>');
  217. writeln('UnCgi encountered the following error: <br>');
  218. writeln('<ul><br>');
  219. writeln('<li> procedure: ',pname,'<br>');
  220. writeln('<li> error: ',perr,'<br><hr>');
  221. writeln(
  222. '<h5><p><i>uncgi (c) ',uncgi_year,' ',maintainer_name,
  223. { skelet fix }
  224. '<a href="mailto:',maintainer_email,'">',
  225. maintainer_email,'</a></i></p></h5>');
  226. writeln('</body></html>');
  227. halt;
  228. end;
  229. var gv_cnt:word;
  230. function get_next_value(id: pchar): pchar;
  231. var
  232. cnt : word;
  233. begin
  234. if gv_cnt<=query_read then inc(gv_cnt);
  235. get_next_value:=Nil;
  236. if done_init then
  237. for cnt :=gv_cnt to query_read do
  238. if strcomp(strupper(id),strupper(query_array[1,cnt]))=0 then begin
  239. get_next_value := query_array[2,cnt];
  240. gv_cnt:=cnt;
  241. exit;
  242. end;
  243. end;
  244. function get_value(id: pchar): pchar;
  245. begin
  246. gv_cnt:=0;
  247. get_value:=get_next_value(id)
  248. end;
  249. Function UnEscape(QueryString: PChar): PChar;
  250. var
  251. qunescaped : pchar;
  252. sptr : longint;
  253. cnt : word;
  254. qslen : longint;
  255. begin
  256. qslen:=strlen(QueryString);
  257. if qslen=0 then
  258. begin
  259. Unescape:=#0;
  260. get_nodata:=true;
  261. exit;
  262. end
  263. else
  264. get_nodata :=false;
  265. { skelet fix }
  266. getmem(qunescaped,qslen+1);
  267. if qunescaped=nil then
  268. begin
  269. writeln ('Oh-oh');
  270. halt;
  271. end;
  272. sptr :=0;
  273. { for cnt := 0 to qslen do +++++ use while instead of for }
  274. cnt:=0;
  275. while cnt<=qslen do
  276. begin
  277. case querystring[cnt] of
  278. '+': qunescaped[sptr] := ' ';
  279. '%': begin
  280. qunescaped[sptr] :=
  281. hexconv(querystring[cnt+1], querystring[cnt+2]);
  282. inc(cnt,2); { <--- not allowed in for loops in pascal }
  283. end;
  284. else
  285. qunescaped[sptr] := querystring[cnt];
  286. end;
  287. inc(sptr);
  288. { skelet fix }
  289. qunescaped[sptr]:=#0;
  290. inc(cnt); { <-- don't forget to increment }
  291. end;
  292. UnEscape:=qunescaped;
  293. end;
  294. Function Chop(QunEscaped : PChar) : Longint;
  295. var
  296. qptr : word;
  297. cnt : word;
  298. qslen : longint;
  299. begin
  300. qptr := 1;
  301. qslen:=strlen(QUnescaped);
  302. query_array[1,qptr] := qunescaped;
  303. for cnt := 0 to qslen-1 do
  304. case qunescaped[cnt] of
  305. '=': begin
  306. qunescaped[cnt] := #0;
  307. { save address }
  308. query_array[2,qptr] := @qunescaped[cnt+1];
  309. end;
  310. '&': begin
  311. qunescaped[cnt] := #0;
  312. { Unescape previous one. }
  313. query_array[2,qptr]:=unescape(query_array[2,qptr]);
  314. inc(qptr);
  315. query_array[1,qptr] := @qunescaped[cnt+1];
  316. end;
  317. end; { Case }
  318. { Unescape last one. }
  319. if query_array[2,qptr] <> nil then
  320. query_array[2,qptr]:=unescape(query_array[2,qptr]);
  321. Chop :=qptr;
  322. end;
  323. procedure cgi_read_get_query;
  324. var
  325. querystring : pchar;
  326. qslen : longint;
  327. begin
  328. querystring :=strnew(getenv('QUERY_STRING'));
  329. if querystring<>NIL then
  330. begin
  331. qslen :=strlen(querystring);
  332. if qslen=0 then
  333. begin
  334. get_nodata :=true;
  335. exit;
  336. end
  337. else
  338. get_nodata :=false;
  339. query_read:=Chop(QueryString);
  340. end;
  341. done_init :=true;
  342. end;
  343. procedure cgi_read_post_query;
  344. var
  345. querystring : pchar;
  346. qslen : longint;
  347. sptr : longint;
  348. clen : string;
  349. ch : char;
  350. begin
  351. if getenv('CONTENT_LENGTH')<>Nil then
  352. begin
  353. clen:=strpas (getenv('CONTENT_LENGTH'));
  354. val(clen,qslen);
  355. if (upcase(strpas(getenv('CONTENT_TYPE')))='APPLICATION/X-WWW-FORM-URLENCODED')
  356. or (upcase(strpas(getenv('CONTENT_TYPE')))='TEXT/PLAIN')
  357. then
  358. begin
  359. getmem(querystring,qslen+1);
  360. sptr :=0;
  361. while sptr<>qslen do
  362. begin
  363. read(ch);
  364. pchar(longint(querystring)+sptr)^ :=ch;
  365. inc(sptr);
  366. end;
  367. { !!! force null-termination }
  368. pchar(longint(querystring)+sptr)^ :=#0;
  369. query_read:=Chop(QueryString);
  370. end;
  371. end;
  372. done_init :=true;
  373. end;
  374. procedure cgi_init;
  375. var
  376. rmeth : pchar;
  377. begin
  378. query_read:=0;
  379. rmeth :=http_request_method;
  380. if rmeth=nil then
  381. begin
  382. uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
  383. exit;
  384. end;
  385. if strcomp('POST',rmeth)=0 then cgi_read_post_query else
  386. if strcomp('GET',rmeth)=0 then cgi_read_get_query else
  387. uncgi_error('cgi_init()','No REQUEST_METHOD passed from server!');
  388. end;
  389. procedure cgi_deinit;
  390. begin
  391. done_init :=false;
  392. query_read :=0;
  393. fillchar(query_array,sizeof(query_array),0);
  394. end;
  395. Function http_url: pchar;
  396. begin
  397. http_url:=getenv('REQUEST_URI');
  398. end;
  399. function http_remote: pchar;
  400. begin
  401. http_remote :=getenv('REMOTE_ADDR');
  402. end;
  403. begin
  404. {$ifdef win32}
  405. InitWin32CGI;
  406. {$endif}
  407. uncgi_error:=@def_uncgi_error;
  408. done_init :=false;
  409. fillchar(query_array,sizeof(query_array),0);
  410. end.
  411. {
  412. HISTORY
  413. $Log$
  414. Revision 1.9 2002-10-24 17:25:36 sg
  415. * Fixed parsing of empty URL arguments (with missing "=")
  416. Revision 1.8 2002/10/18 05:43:53 michael
  417. + Fix of invalid pointer bug in unescape, from U. Maeder
  418. Revision 1.7 2002/10/10 05:48:20 michael
  419. Added http_remote and fixed determining of input method. Fix courtesy of Antal <[email protected]>
  420. Revision 1.6 2002/09/12 16:24:59 michael
  421. + Added http_url function from Michael Weinert
  422. Revision 1.5 2002/09/07 15:43:06 peter
  423. * old logs removed and tabs fixed
  424. Revision 1.4 2002/05/31 11:54:33 marco
  425. * Renamefest for 1.0, many 1.1.x spots patched also.
  426. Revision 1.3 2002/03/04 17:57:17 peter
  427. * updated example in comment
  428. Revision 1.2 2002/03/01 10:57:03 peter
  429. * get_next_value patch from Skelet
  430. Revision 1.1 2002/01/29 17:55:23 peter
  431. * splitted to base and extra
  432. }