| 
									
										
										
										
											2008-02-22 00:47:06 -05:00
										 |  |  | ! Copyright (C) 2005, 2008 Slava Pestov. | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2008-09-10 23:11:40 -04:00
										 |  |  | USING: accessors assocs kernel math math.parser namespaces make | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  | sequences io io.sockets io.streams.string io.files io.timeouts | 
					
						
							|  |  |  | strings splitting calendar continuations accessors vectors | 
					
						
							|  |  |  | math.order hashtables byte-arrays prettyprint | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | io.encodings | 
					
						
							|  |  |  | io.encodings.string | 
					
						
							|  |  |  | io.encodings.ascii | 
					
						
							|  |  |  | io.encodings.8-bit | 
					
						
							|  |  |  | io.encodings.binary | 
					
						
							|  |  |  | io.streams.duplex | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  | fry debugger summary ascii urls present | 
					
						
							|  |  |  | http http.parsers ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | IN: http.client | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : url-host ( url -- string )
 | 
					
						
							|  |  |  |     [ host>> ] [ port>> ] bi dup "http" protocol-port =
 | 
					
						
							|  |  |  |     [ drop ] [ ":" swap number>string 3append ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : write-request-header ( request -- request )
 | 
					
						
							|  |  |  |     dup header>> >hashtable | 
					
						
							|  |  |  |     over url>> host>> [ over url>> url-host "host" pick set-at ] when
 | 
					
						
							|  |  |  |     over post-data>> [ | 
					
						
							|  |  |  |         [ raw>> length "content-length" pick set-at ] | 
					
						
							|  |  |  |         [ content-type>> "content-type" pick set-at ] | 
					
						
							|  |  |  |         bi
 | 
					
						
							|  |  |  |     ] when*
 | 
					
						
							|  |  |  |     over cookies>> f like [ unparse-cookie "cookie" pick set-at ] when*
 | 
					
						
							|  |  |  |     write-header ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GENERIC: >post-data ( object -- post-data )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: post-data >post-data ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: string >post-data "application/octet-stream" <post-data> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: byte-array >post-data "application/octet-stream" <post-data> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: assoc >post-data assoc>query "application/x-www-form-urlencoded" <post-data> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: f >post-data ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : unparse-post-data ( request -- request )
 | 
					
						
							|  |  |  |     [ >post-data ] change-post-data ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : write-post-data ( request -- request )
 | 
					
						
							|  |  |  |     dup method>> "POST" = [ dup post-data>> raw>> write ] when ;  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : write-request ( request -- )
 | 
					
						
							|  |  |  |     unparse-post-data | 
					
						
							|  |  |  |     write-request-line | 
					
						
							|  |  |  |     write-request-header | 
					
						
							|  |  |  |     write-post-data | 
					
						
							|  |  |  |     flush
 | 
					
						
							|  |  |  |     drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-response-line ( response -- response )
 | 
					
						
							|  |  |  |     read-crlf parse-response-line first3
 | 
					
						
							|  |  |  |     [ >>version ] [ >>code ] [ >>message ] tri* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-response-header ( response -- response )
 | 
					
						
							|  |  |  |     read-header >>header | 
					
						
							|  |  |  |     dup "set-cookie" header parse-set-cookie >>cookies | 
					
						
							|  |  |  |     dup "content-type" header [ | 
					
						
							|  |  |  |         parse-content-type | 
					
						
							|  |  |  |         [ >>content-type ] | 
					
						
							|  |  |  |         [ >>content-charset ] bi*
 | 
					
						
							|  |  |  |     ] when* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-response ( -- response )
 | 
					
						
							|  |  |  |     <response> | 
					
						
							|  |  |  |     read-response-line | 
					
						
							|  |  |  |     read-response-header ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 16:37:49 -04:00
										 |  |  | : max-redirects 10 ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ERROR: too-many-redirects ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: too-many-redirects summary | 
					
						
							|  |  |  |     drop
 | 
					
						
							|  |  |  |     [ "Redirection limit of " % max-redirects # " exceeded" % ] "" make ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | DEFER: (http-request) | 
					
						
							| 
									
										
										
										
											2008-03-07 18:21:20 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-05-05 18:31:46 -04:00
										 |  |  | : do-redirect ( response data -- response data )
 | 
					
						
							|  |  |  |     over code>> 300 399 between? [ | 
					
						
							|  |  |  |         drop
 | 
					
						
							| 
									
										
										
										
											2008-04-22 16:37:49 -04:00
										 |  |  |         redirects inc
 | 
					
						
							|  |  |  |         redirects get max-redirects < [ | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  |             request get
 | 
					
						
							| 
									
										
										
										
											2008-06-02 16:00:03 -04:00
										 |  |  |             swap "location" header redirect-url | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |             "GET" >>method (http-request) | 
					
						
							| 
									
										
										
										
											2008-02-25 15:53:18 -05:00
										 |  |  |         ] [ | 
					
						
							| 
									
										
										
										
											2008-04-22 16:37:49 -04:00
										 |  |  |             too-many-redirects | 
					
						
							|  |  |  |         ] if
 | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  |     ] when ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 15:53:18 -05:00
										 |  |  | PRIVATE>
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  | : read-chunk-size ( -- n )
 | 
					
						
							| 
									
										
										
										
											2008-09-05 19:56:35 -04:00
										 |  |  |     read-crlf ";" split1 drop [ blank? ] trim-right | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  |     hex> [ "Bad chunk size" throw ] unless* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  | : read-chunks ( -- )
 | 
					
						
							| 
									
										
										
										
											2008-05-20 19:24:32 -04:00
										 |  |  |     read-chunk-size dup zero?
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |     [ drop ] [ read % read-crlf B{ } assert= read-chunks ] if ;
 | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : read-response-body ( response -- response data )
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |     dup "transfer-encoding" header "chunked" = [ | 
					
						
							|  |  |  |         binary decode-input | 
					
						
							|  |  |  |         [ read-chunks ] B{ } make | 
					
						
							|  |  |  |         over content-charset>> decode | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         dup content-charset>> decode-input | 
					
						
							|  |  |  |         input-stream get contents
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : (http-request) ( request -- response data )
 | 
					
						
							| 
									
										
										
										
											2008-03-07 18:21:20 -05:00
										 |  |  |     dup request [ | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |         dup url>> url-addr ascii [ | 
					
						
							| 
									
										
										
										
											2008-05-05 03:19:25 -04:00
										 |  |  |             1 minutes timeouts | 
					
						
							|  |  |  |             write-request | 
					
						
							| 
									
										
										
										
											2008-03-07 18:21:20 -05:00
										 |  |  |             read-response | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  |             read-response-body | 
					
						
							|  |  |  |         ] with-client | 
					
						
							|  |  |  |         do-redirect | 
					
						
							| 
									
										
										
										
											2008-03-07 18:21:20 -05:00
										 |  |  |     ] with-variable ;
 | 
					
						
							| 
									
										
										
										
											2008-02-07 18:55:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : success? ( code -- ? ) 200 = ;
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-22 15:37:26 -04:00
										 |  |  | ERROR: download-failed response body ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | M: download-failed error. | 
					
						
							|  |  |  |     "HTTP download failed:" print nl
 | 
					
						
							| 
									
										
										
										
											2008-07-02 22:52:28 -04:00
										 |  |  |     [ response>> . nl ] [ body>> write ] bi ;
 | 
					
						
							| 
									
										
										
										
											2008-04-22 15:37:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | : check-response ( response data -- response data )
 | 
					
						
							|  |  |  |     over code>> success? [ download-failed ] unless ;
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  | : http-request ( request -- response data )
 | 
					
						
							|  |  |  |     (http-request) check-response ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : <get-request> ( url -- request )
 | 
					
						
							|  |  |  |     <request> | 
					
						
							|  |  |  |         "GET" >>method | 
					
						
							|  |  |  |         swap >url ensure-port >>url ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : http-get ( url -- response data )
 | 
					
						
							|  |  |  |     <get-request> http-request ;
 | 
					
						
							| 
									
										
										
										
											2008-01-31 02:15:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 -- )
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  |     #! Downloads the contents of a URL to a file. | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |     swap http-get | 
					
						
							| 
									
										
										
										
											2008-09-10 23:11:40 -04:00
										 |  |  |     [ content-charset>> ] [ '[ _ write ] ] bi*
 | 
					
						
							| 
									
										
										
										
											2008-06-12 04:50:20 -04:00
										 |  |  |     with-file-writer ;
 | 
					
						
							| 
									
										
										
										
											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 )
 | 
					
						
							| 
									
										
										
										
											2008-02-29 01:57:38 -05:00
										 |  |  |     <request> | 
					
						
							| 
									
										
										
										
											2008-05-05 18:31:46 -04:00
										 |  |  |         "POST" >>method | 
					
						
							| 
									
										
										
										
											2008-06-02 16:00:03 -04:00
										 |  |  |         swap >url ensure-port >>url | 
					
						
							| 
									
										
										
										
											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 ;
 |