uncgi.pp 13 KB

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