170 lines
4.6 KiB
Forth
Executable File
170 lines
4.6 KiB
Forth
Executable File
\ cgi.fs - Common Gateway Interface for Forth
|
|
\ +JMJ 2013 David Meyer <papa@sdf.org>
|
|
|
|
\ URI length limits:
|
|
\ Standards impose no maximum URI length, but MSIE
|
|
\ through version 10 can only handle URIs of 2083
|
|
\ characters or less (2048 characters is maximum
|
|
\ path length).
|
|
\ URI RFC recommends hostname part of URI not
|
|
\ exceed 255 characters.
|
|
|
|
\ Maximum number of key/value pairs in URI query string
|
|
\ Max. characters: 2083
|
|
\ Query string length: SUM( key-length-n + value-length-n + 2 ) - 1
|
|
\ = n * ( key-length-avg + value-length-avg + 2 ) - 1
|
|
\ Maximum number of keys achieved when key and values are minimum
|
|
\ length - 1 character.
|
|
\ 2083 = n * ( 1 + 1 + 2 ) - 1
|
|
\ = n * 4 - 1
|
|
\ 2084 = n * 4
|
|
\ n = 521 <-- Maximum possible number of key/value pairs in query string
|
|
|
|
require array.fs
|
|
|
|
variable CGIQUERYSTR \ QUERY_STRING address
|
|
variable CGIQUERYLEN \ QUERY_STRING length
|
|
|
|
521 4 table CGIFIELD
|
|
|
|
variable decode-ptr
|
|
variable code-len
|
|
variable keystr-ptr
|
|
variable keystr-len
|
|
variable valstr-ptr
|
|
variable valstr-len
|
|
|
|
\ Is character c a '%'?
|
|
: c%? ( c -- f ) [char] % = ;
|
|
|
|
\ Return hexadecimal value (0-15) of character [0-9A-Fa-f]
|
|
\ Returns -1 for invalid character
|
|
: chex ( c -- n )
|
|
dup [char] 0 [char] 9 1+ within if
|
|
[char] 0 - exit
|
|
then
|
|
dup [char] A [char] F 1+ within if
|
|
[char] A - 10 + exit
|
|
then
|
|
dup [char] a [char] f 1+ within if
|
|
[char] a - 10 + exit
|
|
then
|
|
drop -1 ( Invalid character error )
|
|
;
|
|
|
|
\ Compute value (0-255) of 2-character hexadecimal number
|
|
: hexval ( chigh clow -- 16*chigh+clow ) swap 16 * + ;
|
|
|
|
\ Search string at c-addr1 for character c. If found, set f true and u2 to offset of 1st c in string.
|
|
: csearch ( c-addr1 u1 c -- u2 f )
|
|
0 2over ( c-addr1 u1 c ui c-addr1 u1 )
|
|
+do ( c-addr1 u1 c ui c-addr1 )
|
|
swap chars + c@ ( c-addr1 u1 c ci )
|
|
i rot rot ( c-addr1 u1 ui+1 c ci )
|
|
over = ( c-addr1 u1 ui+1 c fi )
|
|
>r swap 2over drop r> ( c-addr1 u1 c ui+1 c-addr1 fi )
|
|
\ Exit loop if current char. matches
|
|
if leave then ( c-addr1 u1 c ui+1 c-addr1 )
|
|
loop
|
|
drop 1- rot over ( c-addr1 c u2 u1 u2 )
|
|
- 1 > if ( c-addr1 c u2 )
|
|
\ Found char. before end of string
|
|
true 2swap 2drop ( u2 true )
|
|
else
|
|
\ Got to end of string
|
|
dup chars 2swap rot rot + c@ ( u2 c c2 )
|
|
= if
|
|
\ End of string matches char.
|
|
true ( u2 true )
|
|
else
|
|
\ No match
|
|
false ( u2 false )
|
|
then
|
|
then
|
|
;
|
|
|
|
|
|
\ Decode percent-encoded string
|
|
: %decode ( c-code u-code -- c-decode u-decode )
|
|
here decode-ptr !
|
|
dup chars allot
|
|
code-len ! ( c-code )
|
|
|
|
0 swap 0 ( decode-ofst c-code code-ofst )
|
|
begin
|
|
dup 1+ code-len @ <=
|
|
while
|
|
rot >r ( c-code code-ofst )
|
|
2dup + c@ c%? if
|
|
2dup 2dup + 1 chars + c@ chex
|
|
rot rot + 2 chars + c@ chex
|
|
2dup 0>= swap 0>= and if
|
|
hexval decode-ptr @ r@ + c!
|
|
r> 1 chars + rot rot
|
|
else
|
|
2drop
|
|
2dup + decode-ptr @ r@ + 3 cmove
|
|
r> 3 chars + rot rot
|
|
then
|
|
2 chars +
|
|
else
|
|
2dup + c@ decode-ptr @ r@ + c!
|
|
r> 1 chars + rot rot
|
|
\ cr ." debug:" decode-ptr @ code-len @ dump
|
|
then
|
|
1 chars +
|
|
repeat
|
|
2drop decode-ptr @ swap
|
|
;
|
|
|
|
\ Return value for CGI query string key.
|
|
\ Return 0 0 if key not found.
|
|
: qskeyval ( c-key u-key-len -- c-value u-value-len )
|
|
dup
|
|
s" QUERY_STRING" getenv
|
|
dup if
|
|
rot over swap - 2 < if
|
|
\ Query string not long enough for key=value
|
|
2drop 2drop 0 0
|
|
else
|
|
\ search for key string in query
|
|
2swap
|
|
( c-querystr u-querystr-len c-key u-key-len )
|
|
\ Set key search string
|
|
here keystr-ptr !
|
|
dup 2 + dup keystr-len !
|
|
chars dup allot
|
|
[char] = swap keystr-ptr @ + !
|
|
[char] & keystr-ptr !
|
|
keystr-ptr @ 1 chars + swap cmove
|
|
( c-querystr u-querystr-len )
|
|
\ Check for key at beginning of query string
|
|
2dup keystr-ptr @ 1 chars + keystr-len @ 1-
|
|
string-prefix? if
|
|
\ Extract 1st value string
|
|
here valstr-ptr !
|
|
|
|
else
|
|
\ Search query string for full key
|
|
then
|
|
then
|
|
else
|
|
\ QUERY_STRING not defined
|
|
2swap 2drop rot drop
|
|
then
|
|
;
|
|
|
|
\ 2013/10/21 New start: Following may be useful even if above
|
|
\ is discarded ...
|
|
|
|
create cgiKey 521 allot
|
|
create cgiKeyLen 521 allot
|
|
create cgiValue 521 allot
|
|
create cgiValueLen 521 allot
|
|
-1 variable cgiLastField
|
|
|
|
: cgiParseQuery { a-query u -- }
|
|
2dup [char] & scan
|
|
|
|
;
|