blob: 5eecbdb0d5aeac9a589da5355f3d2e7cbe7b0f2a [file] [log] [blame]
\ See license at end of file
purpose: HTTPD Server package
\ To use this code, be certain that you have an "index.htm"
\ in the ROM as a dropin along with a "homelogo.gif".
hex
headers
\needs httpd-port d# 80 constant httpd-port
false value httpd-debug?
: ?httpd-show ( adr len mask -- )
httpd-debug? and if type space else 2drop then
;
[ifndef] show"
: ?show ( adr len -- ) 1 ?httpd-show ;
: show" ( "str" -- ) postpone " postpone ?show ; immediate
[then]
[ifndef] state"
: ?state ( adr len -- ) 2 ?httpd-show ;
: state" ( "str" -- ) postpone " postpone ?state ; immediate
[then]
[ifndef] url"
: ?url ( adr len -- ) 4 ?httpd-show ;
: url" ( "str" -- ) postpone " postpone ?url ; immediate
[then]
\needs init-display : init-display ( adr len -- ) 2drop ;
true value key-interrupt?
" " 2value pending-cmd
0 value hbuf \ Accumulator for incoming data
h# 800 constant /hbuf
0 value hbuf-ptr
0 value sbuf \ A temporary string buffer
h# 40 constant /sbuf
0 value obuf \ A buffer for constructing headers
h# 800 constant /obuf
0 value obuf-ptr
\ The TCP stack on NT appears to do a better job of collecting data and
\ sending it all at once. If our receive buffer is too short, then
\ Netscape on NT will choke. A value of h# 100 will not work here.
0 value thbuf \ Intermediate buffer to hold data
h# 200 constant /thbuf \ from TCP stack
: +hptr ( -- ) hbuf-ptr 1+ to hbuf-ptr ;
: reset-hbuf-ptr ( -- ) 0 to hbuf-ptr ;
: hbuf@ ( index -- b )
hbuf + c@
;
: hbuf-adr ( -- adr ) hbuf hbuf-ptr + ;
0 instance value verbose?
0 instance value preprocess?
0 instance value authenticate?
: parse-args ( -- )
my-args
begin dup while ( rem$ )
ascii , left-parse-string ( rem$' head$ )
2dup " debug" $= if true to httpd-debug? else ( rem$' head$ )
2dup " verbose" $= if true to verbose? else ( rem$' head$ )
2dup " preprocess" $= if true to preprocess? else ( rem$' head$ )
2dup " authenticate" $= if true to authenticate? else ( rem$' head$ )
2dup " nokey" $= if false to key-interrupt? else ( rem$' head$ )
then then then then then ( rem$' head$ )
2drop
repeat
2drop
;
: .ipb ( adr -- adr' ) dup 1+ swap c@ (.) type ;
: .ipaddr ( addr-buff -- )
push-decimal
3 0 do .ipb ." ." loop .ipb drop
pop-base
;
false instance value connected?
: ?bailout ( -- )
key-interrupt? if
key? if key drop abort then
then
pending-cmd dup if
" " to pending-cmd include-buffer
else
2drop
then
;
: connect ( -- )
httpd-debug? if ." Waiting for new connection" cr then
state" W"
begin
?bailout
httpd-port " accept" $call-parent
until
true to connected?
reset-hbuf-ptr \ Clear the buffer for a new connection
httpd-debug? if ." Connected" cr then
state" C"
;
: open ( -- flag )
parse-args
" my-ip-addr" $call-parent collect( .ipaddr )collect
2dup init-display
verbose? if
." http://"
2dup type
cr
key-interrupt? if
." Type any key to stop." cr
then
then
2drop
/hbuf alloc-mem to hbuf
/sbuf alloc-mem to sbuf
/thbuf alloc-mem to thbuf
/obuf alloc-mem to obuf
true
;
\ in-progress? is true while we are collecting and processing a request.
\ It is false while we are polling for a new request on a persistent
\ connection or while there is no open connection.
false value in-progress?
\ This is a special hack that is used by the Swing Solutions application,
\ which has some HTTP requests that do not complete until an exernal event
\ occurs. The requester can abort the request by dropping the TCP
\ connection, but there are some cases where the TCP drop does not
\ appear to be propagated to the responder. Executing abort-on-reconnect
\ marks the current TCP connection so that the receipt of a new connection
\ request will abort the current one.
: abort-on-reconnect ( -- ) " abort-on-reconnect" $call-parent ;
: reset-connection ( -- )
" disconnect" $call-parent
false to connected?
false to in-progress?
;
: close ( -- )
hbuf /hbuf free-mem
sbuf /sbuf free-mem
thbuf /thbuf free-mem
obuf /obuf free-mem
;
: read ( adr len -- actual )
" read" $call-parent dup -1 = if
connected? if show" HDROP" then
false to connected?
then
;
: write ( adr len -- actual ) " write" $call-parent ;
: match? ( match$ -- match? ) hbuf over $= ;
: (send-all) ( adr len -- )
dup 0= if 2drop exit then
tuck write 2dup <> if ( len actual )
dup -1 = if
." Connection closed prematurely" cr
show" HSDROP"
else
." Write failure" cr
show" HWERR"
then
then
2drop
;
defer send-all ' (send-all) to send-all
: >obuf ( adr len -- )
tuck obuf-ptr swap move obuf-ptr + to obuf-ptr
;
: init-obuf ( -- )
['] >obuf to send-all
obuf to obuf-ptr
;
: send-obuf ( -- )
['] (send-all) to send-all
obuf obuf-ptr over - send-all
;
: send-crlf ( -- ) " "r"n" send-all ;
: num>ascii ( n -- $ ) (u.) ;
\ A vrsion of cat that re-uses the same buffer, rather that continually
\ using alloc-mem to create a new string.
: $cat2 ( $1 $2 -- $3 )
\ First figure final length
2 pick over + >r ( $1 $2 ) ( r: 3len )
\ Move the first string to buffer, saving length
2swap dup >r sbuf swap move r> ( $2 len ) ( r: 3len )
\ Now move second string
sbuf + swap move ( ) ( r: len )
\ Now go..
sbuf r> ( $3 )
;
: create-num$ ( len -- num$ ) push-decimal num>ascii pop-base ;
: get-type ( adr len -- c )
0 -rot
bounds do
i c@ [char] . = if drop i then ( adr )
loop
1+ c@
;
: send-content-type ( type$ -- )
" Content-Type: " 2swap $cat2 ( adr len )
" "r"n" $cat2 ( adr len' )
httpd-debug? if 2dup type then ( adr len' )
send-all
;
: presume-content-type ( url$ -- type$ )
get-type upc ( type-char )
case
ascii H of " text/html" endof
ascii B of " image/bmp" endof
ascii G of " image/gif" endof
ascii J of " image/jpeg" endof
( default ) >r " text/html" r>
endcase
;
: send-agent ( -- ) " User-Agent: FirmWorks/1.0"r"n" send-all ;
: 200-header ( -- ) " HTTP/1.0 200 OK"r"n" send-all ;
: 202-header ( -- ) " HTTP/1.0 202 Accepted"r"n" send-all ;
: 204-header ( -- ) " HTTP/1.0 204 No Content"r"n" send-all ;
: 401-header ( -- ) " HTTP/1.0 401 Not Authorized"r"n" send-all ;
: 404-header ( -- ) " HTTP/1.0 404 Not Found"r"n" send-all ;
defer send-header
['] 200-header to send-header
false value persistent? \ False means to disconnect after xfers
: send-connection ( -- )
persistent? if \ HTTP 1.1 needs to be persistent
" Connection: Keep-Alive"r"n" ( adr len )
httpd-debug? if 2dup type then ( adr len )
send-all ( )
then
;
: count-content ( data$ .. n -- data$ .. n len )
0 over 0 ?do ( data$ .. n len )
i 2* 2+ pick + ( data$ .. n len' )
loop
;
: send-content-length ( data$ .. n -- data$ .. n )
count-content ( data$ .. n len )
" Content-Length: " ( data$ .. n len adr len )
rot create-num$ $cat2 ( data$ .. n adr len' )
" "r"n" $cat2 ( data$ .. n adr len'' )
httpd-debug? if 2dup type then ( data$ .. n adr len'' )
send-all ( data$ .. n )
;
: send-pieces ( data$ .. n -- )
0 ?do send-all loop
;
: type-cr ( adr len -- ) type cr ;
\ full-response is what is used to respond to HTTP 1.0 or higher requests.
: full-response ( data$ .. n type$ -- )
httpd-debug? if ." Sending: " 2dup type-cr then
init-obuf
send-header ( data$ .. n type$ )
send-agent ( data$ .. n type$ )
send-connection ( data$ .. n type$ )
send-content-type ( data$ .. n )
send-content-length ( data$ .. n )
send-crlf ( data$ .. n ) \ Data separator
send-obuf
send-pieces ( ) \ Send all segments of the data
;
\ simple-response is used to respond to HTTP 0.9 requests
: simple-response ( data$ .. n type$ -- ) 2drop send-pieces ;
: send-response-header ( data$ .. n header$ -- )
httpd-debug? if ." Sending: " 2dup type-cr then
init-obuf
send-header ( data$ .. n header$ )
send-all ( data$ .. n )
send-crlf ( data$ .. n ) \ Data separator
send-obuf
send-pieces ( ) \ Send all segments of the data
;
defer (send)
['] full-response to (send) \ Default to HTTP 1.0 full-responses for now
: respond ( data$ .. n type$ -- )
state" R"
connected? 0= if ( data$ .. n type$ )
httpd-debug? if ." Discarding response to aborted connection" cr then
2drop 0 ?do 2drop loop
exit
then
(send)
state" S"
;
\ Send a block of preformatted data
: send-html ( adr len -- ) 1 " text/html" respond ;
: hbuf@++ ( -- char ) hbuf-ptr hbuf@ +hptr ;
: skip-til-white ( -- ) begin hbuf@++ bl = until ;
: skip-til ( char -- ) begin dup hbuf@++ = until drop ;
: skip-til-crlf ( -- ) carret skip-til +hptr ;
: skip-til-white-or-? ( -- )
begin hbuf@++ dup bl = swap [char] ? = or until
;
: extract-url ( -- option$ url$ ) \ Pull URL $ from incomming request
reset-hbuf-ptr ( )
skip-til-white ( )
hbuf-adr ( start-adr )
skip-til-white-or-? ( start-adr )
hbuf-adr over - 1- ( start-adr len )
\ Kill off leading "/" from return
dup 1 >= if over c@ [char] / = if 1 /string then then
dup 0= if ( url$ ) \ But is it real?
2drop 0 0 ( 0 0 )
" index.htm" ( 0 0 url$ ) \ Our default
exit ( 0 0 url$ ) \ Get out of dodge...
then
hbuf-ptr 1- hbuf@ ascii ? = if \ We have options...
hbuf-adr ( url$ opt-adr )
skip-til-white ( url$ opt-adr )
hbuf-adr over - 1- ( url$ opt-adr opt-len )
2swap ( opt$ url$ )
else
0 0 2swap ( 0 0 url$ ) \ No options
then
;
\ Dump preformatted tag into output stream
: create-pre ( -- ) " <PRE>" type-cr ;
\ Dump end-preformatted tag into output stream
: create-endpre ( -- ) " </PRE>" type-cr ;
\ Dump a basic HTML header into output stream
: create-header ( -- )
no-page
" <HTML>" type-cr
" <HEAD>" type-cr
" <TITLE>Internet ROM</TITLE>" type-cr
" </HEAD>" type-cr
" <BODY TEXT=""#000000"" BGCOLOR=""#FFFFFF"" LINK=""#0000FF"" " type-cr
" VLINK=""#FF4400"">" type-cr
" <hr>" type-cr
;
\ Dump a link to home into output stream
: et-go-home ( -- )
" <CENTER><A href=""index.htm"" target=""_top"">Back to Main Page</A></CENTER>" type-cr
;
\ Dump a footer into the output stream
: create-footer ( -- )
" <br>" type-cr
et-go-home
" <hr>" type-cr
" <CENTER><IMG SRC=""homelogo.gif""></CENTER>" type-cr
" </BODY>" type-cr
" </HTML>" type-cr
page-mode
;
\ Collect output from execute ROM command
: collect-data ( xt -- adr len )
collect( ( xt )
create-header ( xt )
create-pre ( xt )
guarded ( )
create-endpre ( )
create-footer ( )
)collect ( adr len )
;
\needs auth-header : auth-header ( -- $ ) " WWW-Authenticate: Basic realm=""OFW"""n"r" ;
: send-204 ( -- )
httpd-debug? if ." Sending 204" cr then
['] 200-header to send-header
['] banner collect-data send-html
['] 200-header to send-header
;
: send-401 ( -- )
httpd-debug? if ." Sending 401" cr then
['] 401-header to send-header
['] send-response-header to (send)
0 auth-header respond
['] 200-header to send-header
;
: send-404 ( -- )
httpd-debug? if ." Sending 404" cr then
['] 404-header to send-header
" The ROM cannot supply this information." send-html
['] 200-header to send-header
;
\ HTML preprocessing before sending to browser.
0 0 instance 2value rem$
0 instance value #data$
: #data$+ ( -- ) #data$ 1+ to #data$ ;
: find$ ( s$ t$ -- offset find? )
2>r ( s$ ) ( R: t$ )
0 -rot begin ( offset s$ ) ( R: t$ )
over 2r@ comp 0= if 2r> 2drop 2drop true exit then
1 /string ( offset s$' ) ( R: t$ )
rot 1+ -rot ( offset' s$ ) ( R: t$ )
dup 0= until 2r> 2drop 2drop false ( offset )
;
: eval-forth ( -- data$ ... )
rem$ 7 /string 2dup to rem$ ( adr len )
" </FORTH>" find$ 0= if ." Missing </FORTH>" abort then ( offset )
rem$ drop swap ( forth$ )
rem$ 2 pick 8 + /string to rem$ ( forth$ )
evaluate ( data$ ... n )
#data$ + to #data$ ( data$ ... )
;
: swap-data$ ( data$ ... -- data$' ... n )
#data$ if
#data$ begin
dup 2* pick over 2* pick 2>r
1- ?dup 0=
until
#data$ 0 do 2drop loop
#data$ begin
2r> rot 1- ?dup 0=
until
then #data$
;
: (preprocess-html) ( data$ -- data$' ... n )
to rem$
begin
rem$ " <FORTH>" find$ over ( offset found? offset )
#data$+
rem$ drop swap 2>r ( offset found? ) ( R: data$ )
swap rem$ rot /string to rem$ 2r> ( found? data$ )
rot if eval-forth then ( data$ ... )
rem$ nip 0=
until
swap-data$ ( data$ ... n )
;
: preprocess-html ( url$ data$ -- data$' ... n' )
preprocess? if ( url$ data$ )
0 to #data$ ( url$ data$ )
2swap get-type upc ascii H = if ( data$ )
(preprocess-html) ( data$' ... n )
else ( data$ )
1 ( data$ n )
then
else ( url$ data$ )
2swap 2drop 1 ( data$ n )
then
;
: transaction-done ( -- )
state" T"
persistent? if
url" tdonefw"
" flush-writes" $call-parent
reset-hbuf-ptr
false to in-progress?
else
\ url" tdonerc"
reset-connection
then
state" D"
;
[ifndef] urls
also forth definitions
vocabulary urls
previous definitions
[then]
: handle-url ( opt$ url$ -- )
2dup ['] urls search-wordlist if ( opt$ url$ xt )
execute ( data$ .. n type$ )
respond ( )
state" H"
exit ( )
then ( opt$ url$ )
2dup find-drop-in if ( opt$ url$ data$ )
2over 2>r ( opt$ url$ data$ ) ( R: url$ )
2>r 2>r 2drop 2r> 2r> ( url$ data$ ) ( R: url$ )
preprocess-html ( data$' n ) ( R: url$ )
2r> presume-content-type ( data$ n type$ )
respond ( )
exit ( )
then ( opt$ url$ )
4drop send-404 ( )
;
\ Basic HTTP strings all end with "crlf"
: dual-crlf? ( adr -- flag ) 4 - hbuf + " "(0d0a0d0a)" comp 0= ;
: request-complete? ( -- complete? ) \ Tells us if we have all were going
\ to get.
\ HTTP 0.9 looks like:
\ GET <url> crlf
\ HTTP 1.0/1.1 looks like:
\ GET <url> HTTP/1.0 crlf ...<a bunch of crlf terminated crud>... crlf
\ The major difference being that 0.9 is a single line with a single
\ crlf at the end, 1.0 (and higher ) is multi-line (each line terminated
\ by crlf) with an additional crlf at the end of the request.
\ We need to determine which one we have in the buffer, and if complete,
\ return true so that the request can be processed. We also want to set
\ the response type up here to simple or full depending on 0.9 or 1.x
hbuf-ptr ( ptr ) \ Save for later
\ Reset the pointer, then advance it to where HTTP would be if we
\ have HTTP 1.0 request.
reset-hbuf-ptr ( ptr )
skip-til-white ( ptr )
skip-til-white ( ptr )
\ Now test the buffer and take action accordingly
" HTTP" hbuf hbuf-ptr + 4 ( ptr test$ buf$ )
$= if ( ptr ) \ HTTP 1.x
['] full-response to (send)
\ Now we have to see if we have all of this request or not
dup dual-crlf? ( ptr flag )
\ Now we have to setup to deal with persistent connections.
\ This is a bit of a cheat. We should be looking at the
\ "connection:" field (if it exists) in the incoming URL
\ requset. If it set to "Keep-Alive" then we would set
\ the persistent flag. But so far, *everyone* always sets
\ the Keep-Alive flag. But 1.0 implementations don't work,
\ and 1.1 implementations really want it to. So we just
\ set the persistance based on 1.1ness.
\ " 1.0" hbuf hbuf-ptr + 5 + 3 $= 0= to persistent?
else \ HTTP 0.9
\ We have all we are going to get.
['] simple-response to (send)
true ( ptr true )
then
swap to hbuf-ptr ( flag ) \ Restore buffer pointer in case
\ there is more to come.
;
: b64>6bit ( byte -- 6bit )
dup ascii A ascii Z between if ascii A - exit then
dup ascii a ascii z between if ascii a - d# 26 + exit then
dup ascii 0 ascii 9 between if ascii 0 - d# 52 + exit then
case
ascii + of 3e endof
ascii / of 3f endof
( default ) 0 swap
endcase
;
: b64>ascii ( b64$ -- adr len )
over dup >r 0 2swap ( adr len b64$ ) ( R: adr )
bounds ?do ( adr len ) ( R: adr )
i l@ lbsplit ( adr len b3 b2 b1 b0 ) ( R: adr )
b64>6bit d# 18 << ( adr len b3 b2 b1 val ) ( R: adr )
swap b64>6bit d# 12 << or ( adr len b3 b2 val' ) ( R: adr )
swap b64>6bit d# 6 << or ( adr len b3 val' ) ( R: adr )
swap b64>6bit or ( adr len val' ) ( R: adr )
lbsplit drop ( adr len b3 b2 b1 ) ( R: adr )
4 pick c! ( adr len b3 b2 ) ( R: adr )
3 pick 1+ c! ( adr len b3 ) ( R: adr )
2 pick 2 + c! ( adr len ) ( R: adr )
3 + swap 3 + swap ( adr' len' ) ( R: adr )
4 +loop
dup if \ strip trailing 0's
3 1 do
over i - c@ 0= if 1- then
loop
then nip ( len' )
r> swap ( adr len )
;
: (authorized?) ( realm$ pwd$ user$ -- authorized? )
" admin" $= >r " ofw" $= r> and
-rot 2drop
;
defer authorized?
[ifdef] oem-authorized?
['] oem-authorized? to authorized?
[else]
['] (authorized?) to authorized?
[then]
: extract-auth ( -- realm$ pwd$ user$ )
begin skip-til-crlf hbuf-adr " "(0d0a)" comp while
hbuf-adr ( adr )
[char] : skip-til ( adr )
hbuf-adr over - 1- ( token$ )
" Authorization" $= if ( )
skip-til-white ( )
hbuf-adr ( adr )
skip-til-white
hbuf-adr over - 1- ( realm$ )
hbuf-adr ( realm$ adr )
skip-til-crlf
hbuf-adr over - 2 - ( realm$ base64$ )
b64>ascii ( realm$ user:pwd$ )
[char] : left-parse-string ( realm$ pwd$ user$ )
exit
then
repeat
null$ null$ null$
;
: authenticate-request? ( -- authorized? )
extract-auth ( realm$ pwd$ user$ )
authorized?
;
\ Since we serve up the HTML code, we can decide what to support. You
\ can do everything with "GET"s, and do not really need to support
\ POSTs. POSTs are better for security issues, but since this code
\ would not really be executed in the normal case, this should be a
\ minor issue.
: do-get ( -- )
request-complete? if
httpd-debug? if cr hbuf hbuf-ptr type then
extract-url ( opt$ url$ )
httpd-debug? if ( opt$ url$ )
." URL: " 2dup type-cr ( opt$ url$ )
2over ( opt$ url$ opt$ )
?dup if ( opt$ url$ opt$ )
." OPT: " type-cr ( opt$ url$ )
else drop then ( opt$ url$ )
then ( opt$ url$ )
authenticate? if ( opt$ url$ )
authenticate-request? 0= if ( )
4drop ( )
send-401
transaction-done
exit
then
then
handle-url ( )
transaction-done
then
;
: do-post ( -- )
request-complete? if
httpd-debug? if cr hbuf hbuf-ptr type then
send-204
transaction-done
then
;
: handle-buf ( -- )
" GET" match? if do-get then
" POST" match? if do-post then
;
false instance value crlf-seen?
: >hbuf ( b -- ) \ Accumulate data, when we get a CRLF pair, go check it
hbuf hbuf-ptr + c!
+hptr
hbuf-ptr 2 >= if
hbuf-ptr hbuf + 2- " "(0d0a)" comp 0= if handle-buf then
then
;
0 value end-time
d# 5000 constant short-time
d# 30000 constant long-time
: reset-timer ( -- )
true to in-progress?
persistent? if long-time else short-time then ( timeout-msecs )
get-msecs + to end-time
;
: do-disconnect ( -- )
httpd-debug? if ." Disconnect reset" cr then
url" discrc"
reset-connection
;
: do-idle ( -- )
in-progress? if
key-interrupt? if
key? if
key drop
." HTTPD transaction in progress; interacting " cr
interact
then
then
else
?bailout
then
persistent? if exit then
get-msecs end-time - 0> if
httpd-debug? if ." Timeout reset" cr then
url" idlerc"
reset-connection
then
;
\ Call into the TCP stack, just shovel the data to our collection
\ buffer. The shoveler (>hbuf) will decide when there is enough
\ data to work on.
: httpd-loop ( -- )
false to in-progress?
begin
connected? 0= if connect reset-timer then
thbuf /thbuf read case ( -1|-2|actual )
-1 of do-disconnect endof
-2 of do-idle endof
( actual )
reset-timer ( actual )
thbuf over bounds do i c@ >hbuf loop ( actual )
endcase
key-interrupt? if key? if key emit exit then then
again
;
\ builtin URLs
\ this is essentially demo code
hex
headers
\ support for the built-in URLs
\ Creates return message for setenv
: nice-message ( val$ var$ -- adr len )
collect( ( val$ var$ )
create-header ( val$ var$ )
" ROM Configuration Variable " type ( val$ var$ )
" <b>" type ( val$ var$ )
type ( val$ )
" </b>" type ( val$ )
" set to " type ( val$ )
" <b>" type ( val$ )
type-cr ( )
" </b>" type ( )
" <br> <br>" type-cr
create-footer
)collect
;
\ \ Creates return message for setenv
\ : nice-message1 ( var$ -- adr len )
\ collect( ( var$ )
\ create-header ( var$ )
\ " ROM Configuration Variable " type ( var$ )
\ " <b>" type ( var$ )
\ type ( )
\ " </b>" type ( )
\ " set to default value" type ( )
\ " </b>" type ( )
\ " <br> <br>" type-cr
\ create-footer
\ )collect
\ ;
\ HTTP strings have a "+" where blanks are suppsed to be. Just whack them.
: fix-blanks ( adr len -- )
bounds ?do
i c@ [char] + = if bl i c! then
loop
;
\ HTTP strings mungle up the special characters. Instead of a "/" for
\ example, you get "%2F". This routine looks for the "%" characters,
\ extracts the ascii string after that, converts it to the real hex
\ value and punches it back where the "%" was, then moves everything
\ else to the left by two.
: fixup-string ( adr len -- adr len' )
2dup fix-blanks \ First whack the blanks into shape.
dup 3 < if exit then \ Cannot possibly have %xx.
2dup 2- bounds ?do
i c@ [char] % = if
i 1+ 2 $number 0<> if ." Parsing error" unloop exit then
( adr len b ) i c!
i 3 + ( adr len src )
i 1 + ( adr len src dst )
over 4 pick - ( adr len src dst #ok )
3 pick swap - ( adr len src dst len )
move ( adr len )
2- ( adr len' )
then
loop
;
also urls definitions
: stop ( opt$ url$ -- httpd-stuff )
" abort" to pending-cmd
" Closing remote HTTP server" 1 " text/plain"
;
: reboot ( opt$ url$ -- httpd-stuff )
" bye" to pending-cmd
" Rebooting remote system" 1 " text/plain"
;
\ This is really demo code, not ready for primetime. We deal with some
\ special cases with this code example. If a URL comes in as
\ "rom-setconfig-tf", then we go look for some other stuff in the
\ incomming request packet, reformat the whole wad into a "setenv"
\ command and execute it. This "-tf" method looks at the first
\ character of the incoming set string for "t" or "f" and then creates
\ its own "true" or "false" to pass to the setenv command. Helps with
\ people that can't spell. The second special is really a more general
\ case inplementaion. rom-setconfig-string parses out the string that
\ is passed in and sets the environment variable accordingly. Just
\ another way to do it. Demo code after all. If the request URL has
\ "rom-ok" in it, we treat the passed in data as a string that we just
\ pass to the "ok" prompt, returning whatever we get back. Any other
\ request that is prefeaced by "rom-" is assumed to be a method call, so
\ we go look for an XT, then execute it, returning the data. Thus
\ showing four possibilities of how one might interface to the ROM via
\ HTTP.
: rom-setconfig-tf ( opt$ url$ -- httpd-stuff )
\ OK, the option string will have what we need in it. We need to
\ extract what we need from it, run the setenv command and return
\ something nice to the user...
2drop
hbuf swap move ( ) \ Re-use the hbuf XXX this is bad.
reset-hbuf-ptr
[char] = skip-til hbuf-adr ( adr )
[char] & skip-til hbuf-adr over - 1- ( var$ )
fixup-string ( var$' )
[char] = skip-til ( var$' adr )
hbuf-adr c@ ascii t = if
" true" else " false" ( var$' val$ )
then
2swap 4dup ( val$ var$' val$ var$' )
collect( $setenv )collect ( val$ var$' adr len )
2drop ( val$ var$' )
nice-message 1 " text/html"
;
: rom-setconfig-string ( opt$ url$ -- httpd-stuff )
\ OK, the option string will have what we need in it. We need to
\ extract what we need from it, run the setenv command and return
\ something nice to the user...
2drop
hbuf swap dup >r move ( ) \ Re-use the hbuf
reset-hbuf-ptr
[char] = skip-til hbuf-adr ( adr )
[char] & skip-til hbuf-adr over - 1- ( var$ )
fixup-string ( var$' )
[char] = skip-til ( var$' )
hbuf-adr ( var$ val-adr )
hbuf - ( var$ count )
hbuf r> ( var$ count adr len )
rot /string ( var$ val$ )
fixup-string ( var$ val$ )
2swap 4dup ( val$ var$' val$ var$' )
collect( $setenv )collect ( val$ var$' adr len )
2drop ( val$ var$' )
nice-message 1 " text/html"
;
: rom-setdefault ( opt$ url$ -- httpd-stuff )
\ OK, the option string will have what we need in it. We need to
\ extract what we need from it, run the set-default command and return
\ something nice to the user...
2drop
hbuf swap dup >r move ( ) \ Re-use the hbuf
reset-hbuf-ptr
[char] = skip-til hbuf-adr ( adr )
hbuf - hbuf r> rot /string ( var$ )
fixup-string 2dup ( var$' var$' )
collect(
create-header
create-pre
find-option if do-set-default then
(printenv)
create-endpre
create-footer
)collect ( adr len )
1 " text/html"
;
: rom-restart ( opt$ url$ -- )
\ rom-restart?option_file=url&var=value
2drop
hbuf swap dup >r move ( ) \ Re-use the hbuf
reset-hbuf-ptr
[char] = skip-til hbuf-adr ( adr )
[char] & skip-til hbuf-adr over - 1- ( url$ )
fixup-string ( url$' )
2dup find-drop-in if ( url$ data$ )
2over 2>r ( url$ data$ ) ( R: url$ )
preprocess-html ( data$' n )
2r> presume-content-type ( data$ n type$ )
respond ( )
transaction-done ( )
else ( url$ )
2drop
then
hbuf-adr [char] = skip-til ( var )
hbuf-adr over - 1- ( var$ )
hbuf-adr ( var$ val-adr )
hbuf - ( var$ count )
hbuf r> ( var$ count adr len )
rot /string ( var$ val$ )
fixup-string 2swap ( val$' var$ )
collect( $setenv )collect 2drop ( )
reset-all
;
\ command?here+.+cr plusses become blanks
\ command?4+5+%2b+.+cr use %2b to get a plus
\ note: the web page encodes the command string before sending it
\ and sends command?command=here+.+cr
: cmdeq ( -- $ ) " command=" ;
: command ( opt$ url$ -- httpd-stuff )
2drop
cmdeq 2over sindex 0= if
cmdeq nip /string
then
fixup-string ['] eval collect-data 1 " text/html"
;
previous definitions
\ LICENSE_BEGIN
\ Copyright (c) 2006 FirmWorks
\
\ Permission is hereby granted, free of charge, to any person obtaining
\ a copy of this software and associated documentation files (the
\ "Software"), to deal in the Software without restriction, including
\ without limitation the rights to use, copy, modify, merge, publish,
\ distribute, sublicense, and/or sell copies of the Software, and to
\ permit persons to whom the Software is furnished to do so, subject to
\ the following conditions:
\
\ The above copyright notice and this permission notice shall be
\ included in all copies or substantial portions of the Software.
\
\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\
\ LICENSE_END