@@ 15,11 15,10 @@ define : help-message args
tests
test-assert : string-contains (help-message '("./program")) "./program"
test-equal #\U : string-ref (help-message '("./program")) 0
- format #f "Usage: ~a [options]
+ format #f "Usage: ~a [DOWNLOAD_URL | --serve FOLDER] [options]
Options:
[link [link ...]] download file(s)
- --serve <folder> serve the files in FOLDER
--ip <ip> set server IP (default: [::])
--port <port> set server port (default: 8083)
--lazy hash served when they are requested instead of at startup (default: #f)
@@ 42,14 41,14 @@ define : main args
cond
: or (null? arguments) (member "--help" arguments) (member "-h" arguments)
help args
- : and {(length arguments) > 1} : equal? "--serve" : car arguments
+ : and {(length arguments) > 1} : equal? "--serve" : first arguments
let
: ip-opt : or (opt-member arguments "--ip") '("--ip" "::")
port-opt : or (opt-member arguments "--port") '("--port" "8083")
lazy : member "--lazy" arguments
serve (second arguments) (second ip-opt) (string->number (second port-opt)) (not lazy)
else
- let*
+ let*
: download-data : download-file : car arguments
output-opt : opt-member arguments "--output"
output-file
@@ 430,17 430,17 @@ define : hash-and-mime-if-unknown! serve
set! served-paths : vhash-cons (served-serverpath new-served) new-served : vhash-delete (served-serverpath served-cdr) served-paths
cons (car served-file) new-served
-define : server-serve-file range-requested begin-end served-file
+define : server-serve-file range-requested disallow-range begin-end served-file
define range-begin : car begin-end
define filesize
or : and=> (and=> (and=> (and=> served-file cdr) served-accesspath) stat) stat:size
. 32KiB
define range-end
- if : not range-requested
+ if : or disallow-range : and (< filesize 2MiB) : not range-requested
. #f
or
cdr begin-end
- ;; if no size is requested, optimize for streaming video
+ ;; if no size is requested, optimize for streaming video, since that’s tho only thing that really needs optimizing
min : - filesize 1
+ range-begin
cond
@@ 467,6 467,7 @@ define : server-serve-file range-request
cons `(content-range . ,(format #f "bytes ~d-~d/~d" range-begin range-end file-size))
. base-headers
. base-headers
+ ;; pretty-print : ` resp-headers ,headers
values
build-response
. #:headers headers
@@ 580,11 581,88 @@ define* : string-split-string s substr #
. pieces
+;; Headers for Tizen Smart-TV
+;; ((req-headers
+;; ((host "192.168.2.105" . 8083)
+;; (connection keep-alive)
+;; (user-agent
+;; .
+;; "Mozilla/5.0 (SMART-TV; Linux; Tizen 5.0) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/2.2 Chrome/63.0.3239.84 TV Safari/537.36")
+;; (accept
+;; (image/webp)
+;; (image/apng)
+;; (image/*)
+;; (*/* (q . 800)))
+;; (referer
+;; .
+;; #<<uri> scheme: http userinfo: #f host: "192.168.2.105" port: 8083 path: "/" query: #f fragment: #f>)
+;; (accept-encoding
+;; (1000 . "gzip")
+;; (1000 . "deflate"))
+;; (accept-language (1000 . "de-DE"))))
+
+
+;; Headers for IceCat:
+;; ((req-headers
+;; ((host "192.168.2.105" . 8083)
+;; (user-agent
+;; .
+;; "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0")
+;; (accept
+;; (video/webm)
+;; (video/ogg)
+;; (video/* (q . 900))
+;; (application/ogg (q . 700))
+;; (audio/* (q . 600))
+;; (*/* (q . 500)))
+;; (accept-language (1000 . "en-US") (500 . "en"))
+;; (referer
+;; .
+;; #<<uri> scheme: http userinfo: #f host: "192.168.2.105" port: 8083 path: "/drachenzaehmen-leicht-gemacht-1.mp4" query: #f fragment: #f>)
+;; (range bytes (10518541 . #f))
+;; (dnt . "1")
+;; (connection keep-alive)))
+
+;; Headers for Chromium:
+;; ((req-headers
+;; ((host "192.168.2.105" . 8083)
+;; (connection keep-alive)
+;; (dnt . "1")
+;; (accept-encoding (1000 . "identity") (0 . "*"))
+;; (user-agent
+;; .
+;; "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36")
+;; (accept (*/*))
+;; (referer
+;; .
+;; #<<uri> scheme: http userinfo: #f host: "192.168.2.105" port: 8083 path: "/drachenzaehmen-leicht-gemacht-1.mp4" query: #f fragment: #f>)
+;; (accept-language
+;; (1000 . "de-DE")
+;; (900 . "de")
+;; (800 . "en-US")
+;; (700 . "en"))
+;; (range bytes (6324235 . #f))))
+
+;; Wget
+;; ((req-headers
+;; ((user-agent . "Wget/1.20.3 (linux-gnu)")
+;; (accept (*/*))
+;; (accept-encoding (1000 . "identity"))
+;; (host "192.168.2.105" . 8083)
+;; (connection keep-alive)))
+
+;; Curl
+;; ((req-headers
+;; ((host "192.168.2.105" . 8083)
+;; (user-agent . "curl/7.71.0")
+;; (accept (*/*))))
+
define : server-file-download-handler folder-path request body
define headers : request-headers request
let*
: range-requested : assoc-item headers 'range
+ disallow-range : not : or range-requested : assoc-item headers 'accept-language ;; accept-language is typically interactive, so if it is not present, we fall back to providing the whole file in one go. This is just a heuristic, though. There is no good way to detect "will accept Range response, even though it did not request it".
begin-end
if : or (not range-requested) {(length range-requested) < 3}
. '(0 . #f)
@@ 599,6 677,9 @@ define : server-file-download-handler fo
;; ipv4 : inet-ntop AF_INET ip
ipv6 : inet-ntop AF_INET6 ip
;; pretty-print : list 'xalt xalt 'ipv6 ipv6 'peer peer
+ ;; pretty-print
+ ;; ` : req-headers ,headers
+ ;; disallow-range ,disallow-range
cond
: null? path-elements
server-list-files
@@ 613,7 694,7 @@ define : server-file-download-handler fo
alist-cons sha256
delete-duplicates : cons ipv6 : or (assoc-ref xalt sha256) : list
. xalt
- server-serve-file range-requested begin-end
+ server-serve-file range-requested disallow-range begin-end
hash-and-mime-if-unknown! served-file
define : sha256sum path