1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs kernel math math.parser namespaces make
4 sequences io io.sockets io.streams.string io.files io.timeouts
5 strings splitting calendar continuations accessors vectors
6 math.order hashtables byte-arrays destructors
14 fry ascii urls urls.encoding present
18 : write-request-line ( request -- request )
21 [ url>> relative-url present write bl ]
22 [ "HTTP/" write version>> write crlf ]
25 : url-host ( url -- string )
26 [ host>> ] [ port>> ] bi dup "http" protocol-port =
27 [ drop ] [ ":" swap number>string 3append ] if ;
29 : write-request-header ( request -- request )
30 dup header>> >hashtable
31 over url>> host>> [ over url>> url-host "host" pick set-at ] when
33 [ raw>> length "content-length" pick set-at ]
34 [ content-type>> "content-type" pick set-at ]
37 over cookies>> [ unparse-cookie "cookie" pick set-at ] unless-empty
40 GENERIC: >post-data ( object -- post-data )
42 M: post-data >post-data ;
44 M: string >post-data utf8 encode "application/octet-stream" <post-data> ;
46 M: byte-array >post-data "application/octet-stream" <post-data> ;
48 M: assoc >post-data assoc>query ascii encode "application/x-www-form-urlencoded" <post-data> ;
52 : unparse-post-data ( request -- request )
53 [ >post-data ] change-post-data ;
55 : write-post-data ( request -- request )
56 dup method>> [ "POST" = ] [ "PUT" = ] bi or [ dup post-data>> raw>> write ] when ;
58 : write-request ( request -- )
67 : read-response-line ( response -- response )
68 read-crlf parse-response-line first3
69 [ >>version ] [ >>code ] [ >>message ] tri* ;
71 : read-response-header ( response -- response )
73 dup "set-cookie" header parse-set-cookie >>cookies
74 dup "content-type" header [
77 [ >>content-charset ] bi*
80 : read-response ( -- response )
83 read-response-header ;
87 ERROR: too-many-redirects ;
91 DEFER: (with-http-request)
95 : redirect-url ( request url -- request )
96 '[ _ >url derive-url ensure-port ] change-url ;
98 : redirect? ( response -- ? )
99 code>> 300 399 between? ;
101 : do-redirect ( quot: ( chunk -- ) response -- response )
103 redirects get max-redirects < [
105 swap "location" header redirect-url
106 "GET" >>method swap (with-http-request)
107 ] [ too-many-redirects ] if ; inline recursive
109 : read-chunk-size ( -- n )
110 read-crlf ";" split1 drop [ blank? ] trim-right
111 hex> [ "Bad chunk size" throw ] unless* ;
113 : read-chunked ( quot: ( chunk -- ) -- )
114 read-chunk-size dup zero?
116 read [ swap call ] [ drop ] 2bi
117 read-crlf B{ } assert= read-chunked
118 ] if ; inline recursive
120 : read-unchunked ( quot: ( chunk -- ) -- )
121 8192 read-partial dup [
122 [ swap call ] [ drop read-unchunked ] 2bi
123 ] [ 2drop ] if ; inline recursive
125 : read-response-body ( quot response -- )
127 "transfer-encoding" header "chunked" =
128 [ read-chunked ] [ read-unchunked ] if ; inline
130 : <request-socket> ( -- stream )
131 request get url>> url-addr ascii <client> drop
132 1 minutes over set-timeout ;
134 : (with-http-request) ( request quot: ( chunk -- ) -- response )
140 [ request get write-request ]
144 read-response dup redirect? [ t ] [
146 [ read-response-body ]
153 [ do-redirect ] [ nip ] if
154 ] with-variable ; inline recursive
158 : success? ( code -- ? ) 200 299 between? ;
160 ERROR: download-failed response ;
162 : check-response ( response -- response )
163 dup code>> success? [ download-failed ] unless ;
165 : with-http-request ( request quot -- response )
166 (with-http-request) check-response ; inline
168 : http-request ( request -- response data )
169 [ [ % ] with-http-request ] B{ } make
170 over content-charset>> decode ;
172 : <get-request> ( url -- request )
175 swap >url ensure-port >>url ;
177 : http-get ( url -- response data )
178 <get-request> http-request ;
180 : with-http-get ( url quot -- response )
181 [ <get-request> ] dip with-http-request ; inline
183 : download-name ( url -- name )
184 present file-name "?" split1 drop "/" ?tail drop ;
186 : download-to ( url file -- )
187 binary [ [ write ] with-http-get drop ] with-file-writer ;
189 : download ( url -- )
190 dup download-name download-to ;
192 : <post-request> ( post-data url -- request )
195 swap >url ensure-port >>url
198 : http-post ( post-data url -- response data )
199 <post-request> http-request ;
201 USING: vocabs vocabs.loader ;
203 "debugger" vocab [ "http.client.debugger" require ] when