HTTP server and client fixes

db4
Slava Pestov 2008-03-07 17:21:20 -06:00
parent 71a1edf426
commit 68f276b444
6 changed files with 68 additions and 36 deletions

View File

@ -23,6 +23,5 @@ tuple-syntax namespaces ;
[ [
"http://www.apple.com/index.html" "http://www.apple.com/index.html"
<get-request> <get-request>
request-with-url
] with-scope ] with-scope
] unit-test ] unit-test

View File

@ -6,72 +6,76 @@ splitting calendar continuations accessors vectors io.encodings.latin1
io.encodings.binary ; io.encodings.binary ;
IN: http.client IN: http.client
DEFER: http-request
<PRIVATE
: parse-url ( url -- resource host port ) : parse-url ( url -- resource host port )
"http://" ?head [ "Only http:// supported" throw ] unless "http://" ?head [ "Only http:// supported" throw ] unless
"/" split1 [ "/" swap append ] [ "/" ] if* "/" split1 [ "/" swap append ] [ "/" ] if*
swap parse-host ; swap parse-host ;
<PRIVATE
: store-path ( request path -- request ) : store-path ( request path -- request )
"?" split1 >r >>path r> dup [ query>assoc ] when >>query ; "?" split1 >r >>path r> dup [ query>assoc ] when >>query ;
! This is all pretty complex because it needs to handle
! HTTP redirects, which might be absolute or relative
: request-with-url ( url request -- request ) : request-with-url ( url request -- request )
clone dup "request" set
swap parse-url >r >r store-path r> >>host r> >>port ; swap parse-url >r >r store-path r> >>host r> >>port ;
DEFER: (http-request) ! This is all pretty complex because it needs to handle
! HTTP redirects, which might be absolute or relative
: absolute-redirect ( url -- request ) : absolute-redirect ( url -- request )
"request" get request-with-url ; request get request-with-url ;
: relative-redirect ( path -- request ) : relative-redirect ( path -- request )
"request" get swap store-path ; request get swap store-path ;
: do-redirect ( response -- response stream ) : do-redirect ( response -- response stream )
dup response-code 300 399 between? [ dup response-code 300 399 between? [
stdio get dispose
header>> "location" swap at header>> "location" swap at
dup "http://" head? [ dup "http://" head? [
absolute-redirect absolute-redirect
] [ ] [
relative-redirect relative-redirect
] if "GET" >>method (http-request) ] if "GET" >>method http-request
] [ ] [
stdio get stdio get
] if ; ] if ;
: (http-request) ( request -- response stream ) : request-addr ( request -- addr )
dup host>> over port>> <inet> latin1 <client> stdio set dup host>> swap port>> <inet> ;
dup "r" set-global write-request flush read-response
do-redirect ; : close-on-error ( stream quot -- )
[ with-stream* ] curry [ ] pick [ dispose ] curry cleanup ;
inline
PRIVATE> PRIVATE>
: http-request ( url request -- response stream ) : http-request ( request -- response stream )
[ dup request [
request-with-url dup request-addr latin1 <client>
[
(http-request)
1 minutes over set-timeout 1 minutes over set-timeout
] [ ] [ stdio get dispose ] cleanup [
] with-scope ; write-request flush
read-response
do-redirect
] close-on-error
] with-variable ;
: <get-request> ( -- request ) : <get-request> ( url -- request )
<request> "GET" >>method ; <request> request-with-url "GET" >>method ;
: http-get-stream ( url -- response stream ) : http-get-stream ( url -- response stream )
<get-request> http-request ; <get-request> http-request ;
: success? ( code -- ? ) 200 = ; : success? ( code -- ? ) 200 = ;
: check-response ( response stream -- stream ) : check-response ( response -- )
swap code>> success? code>> success?
[ dispose "HTTP download failed" throw ] unless ; [ "HTTP download failed" throw ] unless ;
: http-get ( url -- string ) : http-get ( url -- string )
http-get-stream check-response contents ; http-get-stream contents swap check-response ;
: download-name ( url -- name ) : download-name ( url -- name )
file-name "?" split1 drop "/" ?tail drop ; file-name "?" split1 drop "/" ?tail drop ;
@ -84,12 +88,13 @@ PRIVATE>
: download ( url -- ) : download ( url -- )
dup download-name download-to ; dup download-name download-to ;
: <post-request> ( content-type content -- request ) : <post-request> ( content-type content url -- request )
<request> <request>
request-with-url
"POST" >>method "POST" >>method
swap >>post-data swap >>post-data
swap >>post-data-type ; swap >>post-data-type ;
: http-post ( content-type content url -- response string ) : http-post ( content-type content url -- response string )
#! The content is URL encoded for you. #! The content is URL encoded for you.
-rot url-encode <post-request> http-request contents ; >r url-encode r> <post-request> http-request contents ;

View File

@ -127,3 +127,30 @@ read-response-test-1' 1array [
"rmid=732423sdfs73242; path=/; domain=.example.net; expires=Fri, 31-Dec-2010 23:59:59 GMT" "rmid=732423sdfs73242; path=/; domain=.example.net; expires=Fri, 31-Dec-2010 23:59:59 GMT"
dup parse-cookies unparse-cookies = dup parse-cookies unparse-cookies =
] unit-test ] unit-test
! Live-fire exercise
USING: http.server http.server.static http.server.actions
http.client io.server io.files io accessors namespaces threads
io.encodings.ascii ;
[ ] [
[
<dispatcher>
<action>
[ stop-server "text/html" <content> [ "Goodbye" write ] >>body ] >>get
"quit" add-responder
"extra/http/test" resource-path <static> >>default
default-host set
[ 1237 httpd ] "HTTPD test" spawn drop
] with-scope
] unit-test
[ t ] [
"extra/http/test/foo.html" resource-path ascii file-contents
"http://localhost:1237/foo.html" http-get =
] unit-test
[ "Goodbye" ] [
"http://localhost:1237/quit" http-get
] unit-test

View File

@ -3,7 +3,7 @@
USING: calendar html io io.files kernel math math.parser http USING: calendar html io io.files kernel math math.parser http
http.server namespaces parser sequences strings assocs http.server namespaces parser sequences strings assocs
hashtables debugger http.mime sorting html.elements logging hashtables debugger http.mime sorting html.elements logging
calendar.format new-slots accessors ; calendar.format new-slots accessors io.encodings.binary ;
IN: http.server.static IN: http.server.static
SYMBOL: responder SYMBOL: responder
@ -33,7 +33,7 @@ TUPLE: file-responder root hook special ;
<content> <content>
over file-length "content-length" set-header over file-length "content-length" set-header
over file-http-date "last-modified" set-header over file-http-date "last-modified" set-header
swap [ <file-reader> stdio get stream-copy ] curry >>body swap [ binary <file-reader> stdio get stream-copy ] curry >>body
] <file-responder> ; ] <file-responder> ;
: serve-static ( filename mime-type -- response ) : serve-static ( filename mime-type -- response )

1
extra/http/test/foo.html Normal file
View File

@ -0,0 +1 @@
<html><head><title>Hello</title></head><body>HTTPd test</body></html>

View File

@ -40,11 +40,11 @@ PRIVATE>
f swap t resolve-host ; f swap t resolve-host ;
: with-server ( seq service encoding quot -- ) : with-server ( seq service encoding quot -- )
V{ } clone [ V{ } clone servers [
swap servers [ [
[ server-loop ] 2curry with-logging [ server-loop ] 2curry with-logging
] with-variable ] 3curry parallel-each
] 3curry curry parallel-each ; inline ] with-variable ; inline
: stop-server ( -- ) : stop-server ( -- )
servers get [ dispose ] each ; servers get [ dispose ] each ;