| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  | ! Copyright (C) 2016 John Benediktsson | 
					
						
							|  |  |  | ! See http://factorcode.org/license.txt for BSD license | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | USING: accessors calendar combinators combinators.short-circuit | 
					
						
							|  |  |  | formatting fry io io.directories io.encodings.binary | 
					
						
							|  |  |  | io.encodings.string io.encodings.utf8 io.files io.files.info | 
					
						
							|  |  |  | io.files.types io.pathnames io.servers kernel locals math | 
					
						
							| 
									
										
										
										
											2016-11-02 14:11:53 -04:00
										 |  |  | mime.types sequences splitting strings urls.encoding ;
 | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | IN: gopher.server | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: gopher-server < threaded-server | 
					
						
							|  |  |  |     { serving-hostname string } | 
					
						
							|  |  |  |     { serving-directory string } ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : send-file ( path -- )
 | 
					
						
							|  |  |  |     binary [ [ write ] each-block ] with-file-reader ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : gopher-type ( entry -- type )
 | 
					
						
							|  |  |  |     dup type>> { | 
					
						
							|  |  |  |         { +directory+ [ drop "1" ] } | 
					
						
							|  |  |  |         { +regular-file+ [ | 
					
						
							|  |  |  |             name>> mime-type { | 
					
						
							|  |  |  |                 { [ dup "text/" head? ] [ drop "0" ] } | 
					
						
							|  |  |  |                 { [ dup "image/gif" = ] [ drop "g" ] } | 
					
						
							|  |  |  |                 { [ dup "image/" head? ] [ drop "I" ] } | 
					
						
							|  |  |  |                 [ drop "9" ] | 
					
						
							|  |  |  |             } cond ] } | 
					
						
							|  |  |  |         [ 2drop f ] | 
					
						
							|  |  |  |     } case ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : file-modified ( entry -- string )
 | 
					
						
							|  |  |  |     modified>> "%Y-%b-%d %H:%M" strftime ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : file-size ( entry -- string )
 | 
					
						
							|  |  |  |     dup directory? [ | 
					
						
							|  |  |  |         drop "-  " | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         size>> { | 
					
						
							|  |  |  |             { [ dup 40 2^ >= ] [ 40 2^ /f "TB" ] } | 
					
						
							|  |  |  |             { [ dup 30 2^ >= ] [ 30 2^ /f "GB" ] } | 
					
						
							|  |  |  |             { [ dup 20 2^ >= ] [ 20 2^ /f "MB" ] } | 
					
						
							|  |  |  |             [ 10 2^ /f "KB" ] | 
					
						
							|  |  |  |         } cond "%.1f %s" sprintf | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: list-directory ( server path -- )
 | 
					
						
							|  |  |  |     path server serving-directory>> ?head drop [ | 
					
						
							| 
									
										
										
										
											2016-10-26 22:50:00 -04:00
										 |  |  |         [ "/" ] when-empty
 | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  |         "i[%s]\t\terror.host\t1\r\n\r\n" sprintf | 
					
						
							|  |  |  |         utf8 encode write
 | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             ".." swap parent-directory | 
					
						
							|  |  |  |             server serving-hostname>> | 
					
						
							|  |  |  |             server insecure>> | 
					
						
							| 
									
										
										
										
											2016-10-27 12:32:16 -04:00
										 |  |  |             "1%-69s\t%s\t%s\t%d\r\n" sprintf | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  |             utf8 encode write
 | 
					
						
							|  |  |  |         ] unless-empty
 | 
					
						
							|  |  |  |     ] bi
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     path [ | 
					
						
							|  |  |  |         [ name>> "." head? ] reject | 
					
						
							|  |  |  |         [ { [ directory? ] [ regular-file? ] } 1|| ] filter
 | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             [ gopher-type ] [ name>> ] bi
 | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 dup file-info [ file-modified ] [ file-size ] bi
 | 
					
						
							|  |  |  |                 "%-40s %s %10s" sprintf | 
					
						
							|  |  |  |             ] [ | 
					
						
							|  |  |  |                 path prepend-path | 
					
						
							| 
									
										
										
										
											2016-10-26 22:50:00 -04:00
										 |  |  |                 server serving-directory>> ?head drop
 | 
					
						
							| 
									
										
										
										
											2016-11-02 14:11:53 -04:00
										 |  |  |                 url-encode | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  |             ] bi
 | 
					
						
							|  |  |  |             server serving-hostname>> | 
					
						
							|  |  |  |             server insecure>> | 
					
						
							|  |  |  |             "%s%s\t%s\t%s\t%d\r\n" sprintf | 
					
						
							|  |  |  |             utf8 encode write
 | 
					
						
							|  |  |  |         ] each
 | 
					
						
							|  |  |  |     ] with-directory-entries ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : send-directory ( server path -- )
 | 
					
						
							|  |  |  |     dup ".gophermap" append-path dup exists? [ | 
					
						
							|  |  |  |         send-file 2drop
 | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         drop dup ".gopherhead" append-path | 
					
						
							|  |  |  |         dup exists? [ send-file ] [ drop ] if
 | 
					
						
							|  |  |  |         list-directory | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-gopher-path ( -- path )
 | 
					
						
							| 
									
										
										
										
											2016-10-27 12:32:16 -04:00
										 |  |  |     readln dup [ "\t\r\n" member? ] find drop [ head ] when*
 | 
					
						
							| 
									
										
										
										
											2016-11-02 14:11:53 -04:00
										 |  |  |     trim-tail-separators url-decode ;
 | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-28 18:18:06 -04:00
										 |  |  | M: gopher-server handle-client* | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  |     dup serving-directory>> read-gopher-path append-path | 
					
						
							|  |  |  |     dup file-info type>> { | 
					
						
							|  |  |  |         { +directory+ [ send-directory ] } | 
					
						
							|  |  |  |         { +regular-file+ [ nip send-file ] } | 
					
						
							|  |  |  |         [ 3drop ] | 
					
						
							|  |  |  |     } case flush ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : <gopher-server> ( directory port -- server )
 | 
					
						
							|  |  |  |     utf8 gopher-server new-threaded-server | 
					
						
							|  |  |  |         swap >>insecure | 
					
						
							|  |  |  |         "localhost" >>serving-hostname | 
					
						
							|  |  |  |         swap resolve-symlinks >>serving-directory | 
					
						
							|  |  |  |         "gopher.server" >>name | 
					
						
							|  |  |  |         binary >>encoding | 
					
						
							| 
									
										
										
										
											2016-10-28 18:18:06 -04:00
										 |  |  |         5 minutes >>timeout ;
 | 
					
						
							| 
									
										
										
										
											2016-10-26 19:47:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : start-gopher-server ( directory port -- server )
 | 
					
						
							|  |  |  |     <gopher-server> start-server ;
 |