| 
									
										
										
										
											2010-03-13 01:06:41 -05:00
										 |  |  | ! Copyright (C) 2005, 2010 Slava Pestov. | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2014-03-12 22:29:35 -04:00
										 |  |  | USING: accessors ascii assocs calendar combinators.short-circuit | 
					
						
							|  |  |  | destructors fry hashtables http http.client.post-data | 
					
						
							|  |  |  | http.parsers io io.crlf io.encodings io.encodings.ascii | 
					
						
							|  |  |  | io.encodings.binary io.encodings.iana io.encodings.string | 
					
						
							|  |  |  | io.files io.pathnames io.sockets io.timeouts kernel locals math | 
					
						
							|  |  |  | math.order math.parser mime.types namespaces present sequences | 
					
						
							|  |  |  | splitting urls vocabs.loader ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | IN: http.client | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | ERROR: too-many-redirects ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  | : write-request-line ( request -- request )
 | 
					
						
							|  |  |  |     dup
 | 
					
						
							|  |  |  |     [ method>> write bl ] | 
					
						
							|  |  |  |     [ url>> relative-url present write bl ] | 
					
						
							|  |  |  |     [ "HTTP/" write version>> write crlf ] | 
					
						
							|  |  |  |     tri ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-20 21:28:50 -04:00
										 |  |  | : default-port? ( url -- ? )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         [ port>> not ] | 
					
						
							|  |  |  |         [ [ port>> ] [ protocol>> protocol-port ] bi = ] | 
					
						
							|  |  |  |     } 1|| ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : unparse-host ( url -- string )
 | 
					
						
							|  |  |  |     dup default-port? [ host>> ] [ | 
					
						
							|  |  |  |         [ host>> ] [ port>> number>string ] bi ":" glue
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | : set-host-header ( request header -- request header )
 | 
					
						
							| 
									
										
										
										
											2010-08-20 21:28:50 -04:00
										 |  |  |     over url>> unparse-host "host" pick set-at ;
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : set-cookie-header ( header cookies -- header )
 | 
					
						
							|  |  |  |     unparse-cookie "cookie" pick set-at ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  | : write-request-header ( request -- request )
 | 
					
						
							|  |  |  |     dup header>> >hashtable | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  |     over url>> host>> [ set-host-header ] when
 | 
					
						
							|  |  |  |     over post-data>> [ set-post-data-headers ] when*
 | 
					
						
							|  |  |  |     over cookies>> [ set-cookie-header ] unless-empty
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  |     write-header ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : write-request ( request -- )
 | 
					
						
							|  |  |  |     unparse-post-data | 
					
						
							|  |  |  |     write-request-line | 
					
						
							|  |  |  |     write-request-header | 
					
						
							| 
									
										
										
										
											2008-12-11 00:30:33 -05:00
										 |  |  |     binary encode-output | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  |     write-post-data | 
					
						
							|  |  |  |     flush
 | 
					
						
							|  |  |  |     drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-response-line ( response -- response )
 | 
					
						
							| 
									
										
										
										
											2011-10-12 15:51:49 -04:00
										 |  |  |     read-?crlf parse-response-line first3
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  |     [ >>version ] [ >>code ] [ >>message ] tri* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-13 04:09:56 -05:00
										 |  |  | : detect-encoding ( response -- encoding )
 | 
					
						
							|  |  |  |     [ content-charset>> name>encoding ] | 
					
						
							|  |  |  |     [ content-type>> mime-type-encoding ] bi
 | 
					
						
							|  |  |  |     or ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  | : read-response-header ( response -- response )
 | 
					
						
							|  |  |  |     read-header >>header | 
					
						
							|  |  |  |     dup "set-cookie" header parse-set-cookie >>cookies | 
					
						
							|  |  |  |     dup "content-type" header [ | 
					
						
							|  |  |  |         parse-content-type | 
					
						
							| 
									
										
										
										
											2010-03-13 01:06:41 -05:00
										 |  |  |         [ >>content-type ] [ >>content-charset ] bi*
 | 
					
						
							| 
									
										
										
										
											2010-03-13 04:09:56 -05:00
										 |  |  |         dup detect-encoding >>content-encoding | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  |     ] when* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-response ( -- response )
 | 
					
						
							|  |  |  |     <response> | 
					
						
							|  |  |  |     read-response-line | 
					
						
							|  |  |  |     read-response-header ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  | DEFER: (with-http-request) | 
					
						
							| 
									
										
										
										
											2008-11-01 05:39:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 16:37:49 -04:00
										 |  |  | SYMBOL: redirects | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-02 16:00:03 -04:00
										 |  |  | : redirect-url ( request url -- request )
 | 
					
						
							| 
									
										
										
										
											2008-09-10 23:11:40 -04:00
										 |  |  |     '[ _ >url derive-url ensure-port ] change-url ;
 | 
					
						
							| 
									
										
										
										
											2008-06-02 16:00:03 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  | : redirect? ( response -- ? )
 | 
					
						
							|  |  |  |     code>> 300 399 between? ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-07 05:19:21 -04:00
										 |  |  | :: do-redirect ( quot: ( chunk -- ) response -- response )
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |     redirects inc
 | 
					
						
							| 
									
										
										
										
											2009-06-18 14:47:08 -04:00
										 |  |  |     redirects get request get redirects>> < [ | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |         request get clone
 | 
					
						
							| 
									
										
										
										
											2009-04-07 05:19:21 -04:00
										 |  |  |         response "location" header redirect-url | 
					
						
							|  |  |  |         response code>> 307 = [ "GET" >>method ] unless
 | 
					
						
							|  |  |  |         quot (with-http-request) | 
					
						
							| 
									
										
										
										
											2015-08-13 19:13:05 -04:00
										 |  |  |     ] [ too-many-redirects ] if ; inline recursive
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  | : read-chunk-size ( -- n )
 | 
					
						
							| 
									
										
										
										
											2011-10-12 23:14:21 -04:00
										 |  |  |     read-crlf ";" split1 drop [ blank? ] trim-tail
 | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  |     hex> [ "Bad chunk size" throw ] unless* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  | : read-chunked ( quot: ( chunk -- ) -- )
 | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  |     read-chunk-size dup zero?
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |     [ 2drop ] [ | 
					
						
							|  |  |  |         read [ swap call ] [ drop ] 2bi
 | 
					
						
							| 
									
										
										
										
											2011-10-12 23:14:21 -04:00
										 |  |  |         read-crlf B{ } assert= read-chunked | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |     ] if ; inline recursive
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-17 20:54:29 -04:00
										 |  |  | : read-response-body ( quot: ( chunk -- ) response -- )
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |     binary decode-input | 
					
						
							|  |  |  |     "transfer-encoding" header "chunked" =
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  |     [ read-chunked ] [ each-block ] if ; inline
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : <request-socket> ( -- stream )
 | 
					
						
							|  |  |  |     request get url>> url-addr ascii <client> drop
 | 
					
						
							|  |  |  |     1 minutes over set-timeout ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-13 20:00:09 -04:00
										 |  |  | : (with-http-request) ( request quot: ( chunk -- ) -- response )
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |     swap
 | 
					
						
							|  |  |  |     request [ | 
					
						
							|  |  |  |         <request-socket> [ | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 out>> | 
					
						
							|  |  |  |                 [ request get write-request ] | 
					
						
							|  |  |  |                 with-output-stream*
 | 
					
						
							|  |  |  |             ] [ | 
					
						
							|  |  |  |                 in>> [ | 
					
						
							| 
									
										
										
										
											2009-06-18 14:47:08 -04:00
										 |  |  |                     read-response dup redirect? | 
					
						
							|  |  |  |                     request get redirects>> 0 > and [ t ] [ | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  |                         [ nip response set ] | 
					
						
							|  |  |  |                         [ read-response-body ] | 
					
						
							|  |  |  |                         [ ] | 
					
						
							|  |  |  |                         2tri f
 | 
					
						
							|  |  |  |                     ] if
 | 
					
						
							|  |  |  |                 ] with-input-stream*
 | 
					
						
							|  |  |  |             ] bi
 | 
					
						
							|  |  |  |         ] with-disposal | 
					
						
							|  |  |  |         [ do-redirect ] [ nip ] if
 | 
					
						
							|  |  |  |     ] with-variable ; inline recursive
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-15 12:30:22 -04:00
										 |  |  | : request-url ( url -- url' )
 | 
					
						
							|  |  |  |     dup >url dup protocol>> [ nip ] [ | 
					
						
							| 
									
										
										
										
											2013-07-15 13:28:28 -04:00
										 |  |  |         drop dup url? [ present ] when
 | 
					
						
							|  |  |  |         "http://" prepend >url | 
					
						
							| 
									
										
										
										
											2013-07-15 12:30:22 -04:00
										 |  |  |     ] if ensure-port ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | : <client-request> ( url method -- request )
 | 
					
						
							|  |  |  |     <request> | 
					
						
							|  |  |  |         swap >>method | 
					
						
							| 
									
										
										
										
											2013-07-15 12:30:22 -04:00
										 |  |  |         swap request-url >>url ; inline
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-14 20:52:00 -04:00
										 |  |  | PRIVATE>
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-14 20:52:00 -04:00
										 |  |  | : success? ( code -- ? ) 200 299 between? ;
 | 
					
						
							| 
									
										
										
										
											2008-04-22 15:37:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-13 20:00:09 -04:00
										 |  |  | ERROR: download-failed response ;
 | 
					
						
							| 
									
										
										
										
											2008-10-01 06:43:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-13 20:00:09 -04:00
										 |  |  | : check-response ( response -- response )
 | 
					
						
							|  |  |  |     dup code>> success? [ download-failed ] unless ;
 | 
					
						
							| 
									
										
										
										
											2008-04-22 15:37:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-12 22:29:35 -04:00
										 |  |  | : with-http-request* ( request quot: ( chunk -- ) -- response )
 | 
					
						
							| 
									
										
										
										
											2009-02-12 23:39:26 -05:00
										 |  |  |     [ (with-http-request) ] with-destructors ; inline
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-12 22:29:35 -04:00
										 |  |  | : with-http-request ( request quot: ( chunk -- ) -- response )
 | 
					
						
							|  |  |  |     with-http-request* check-response ; inline
 | 
					
						
							| 
									
										
										
										
											2008-10-13 02:01:29 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-12 22:29:35 -04:00
										 |  |  | : http-request* ( request -- response data )
 | 
					
						
							|  |  |  |     BV{ } clone [ '[ _ push-all ] with-http-request* ] keep
 | 
					
						
							|  |  |  |     B{ } like over content-encoding>> decode [ >>body ] keep ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-request ( request -- response data )
 | 
					
						
							|  |  |  |     http-request* [ check-response ] dip ;
 | 
					
						
							| 
									
										
										
										
											2013-10-12 13:57:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | : <get-request> ( url -- request )
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  |     "GET" <client-request> ;
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : http-get ( url -- response data )
 | 
					
						
							|  |  |  |     <get-request> http-request ;
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-get* ( url -- response data )
 | 
					
						
							|  |  |  |     <get-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-07 18:55:31 -05:00
										 |  |  | : download-name ( url -- name )
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |     present file-name "?" split1 drop "/" ?tail drop ;
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : download-to ( url file -- )
 | 
					
						
							| 
									
										
										
										
											2014-03-12 22:29:35 -04:00
										 |  |  |     binary [ | 
					
						
							|  |  |  |         <get-request> [ write ] with-http-request drop
 | 
					
						
							|  |  |  |     ] with-file-writer ;
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 11:57:45 -04:00
										 |  |  | : ?download-to ( url file -- )
 | 
					
						
							|  |  |  |     dup exists? [ 2drop ] [ download-to ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | : download ( url -- )
 | 
					
						
							|  |  |  |     dup download-name download-to ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-04 20:14:20 -04:00
										 |  |  | : <post-request> ( post-data url -- request )
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  |     "POST" <client-request> | 
					
						
							| 
									
										
										
										
											2008-06-04 20:14:20 -04:00
										 |  |  |         swap >>post-data ;
 | 
					
						
							| 
									
										
										
										
											2008-02-25 15:53:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-04 20:14:20 -04:00
										 |  |  | : http-post ( post-data url -- response data )
 | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  |     <post-request> http-request ;
 | 
					
						
							| 
									
										
										
										
											2008-09-17 05:35:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-post* ( post-data url -- response data )
 | 
					
						
							|  |  |  |     <post-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | : <put-request> ( post-data url -- request )
 | 
					
						
							|  |  |  |     "PUT" <client-request> | 
					
						
							|  |  |  |         swap >>post-data ;
 | 
					
						
							| 
									
										
										
										
											2008-09-17 05:35:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-22 20:08:38 -05:00
										 |  |  | : http-put ( post-data url -- response data )
 | 
					
						
							| 
									
										
										
										
											2008-09-17 05:35:30 -04:00
										 |  |  |     <put-request> http-request ;
 | 
					
						
							| 
									
										
										
										
											2009-01-28 04:58:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-put* ( post-data url -- response data )
 | 
					
						
							|  |  |  |     <put-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-14 20:52:00 -04:00
										 |  |  | : <delete-request> ( url -- request )
 | 
					
						
							|  |  |  |     "DELETE" <client-request> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-delete ( url -- response data )
 | 
					
						
							|  |  |  |     <delete-request> http-request ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-delete* ( url -- response data )
 | 
					
						
							|  |  |  |     <delete-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-11 17:45:26 -04:00
										 |  |  | : <head-request> ( url -- request )
 | 
					
						
							|  |  |  |     "HEAD" <client-request> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-head ( url -- response data )
 | 
					
						
							|  |  |  |     <head-request> http-request ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-head* ( url -- response data )
 | 
					
						
							|  |  |  |     <head-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-11 17:45:26 -04:00
										 |  |  | : <options-request> ( url -- request )
 | 
					
						
							|  |  |  |     "OPTIONS" <client-request> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-options ( url -- response data )
 | 
					
						
							|  |  |  |     <options-request> http-request ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-options* ( url -- response data )
 | 
					
						
							|  |  |  |     <options-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-11 17:45:26 -04:00
										 |  |  | : <trace-request> ( url -- request )
 | 
					
						
							|  |  |  |     "TRACE" <client-request> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-trace ( url -- response data )
 | 
					
						
							|  |  |  |     <trace-request> http-request ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-13 15:26:35 -04:00
										 |  |  | : http-trace* ( url -- response data )
 | 
					
						
							|  |  |  |     <trace-request> http-request* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-18 15:29:24 -04:00
										 |  |  | { "http.client" "debugger" } "http.client.debugger" require-when |