80 lines
3.1 KiB
Racket
80 lines
3.1 KiB
Racket
#lang racket/base
|
|
|
|
(provide sleep
|
|
random-hex-string
|
|
extend-url-string-query
|
|
web-respond/status!
|
|
web-request!)
|
|
|
|
(require racket/dict)
|
|
(require (only-in file/sha1 bytes->hex-string))
|
|
(require (only-in racket/random crypto-random-bytes))
|
|
(require net/url)
|
|
(require syndicate/actor)
|
|
(require syndicate/drivers/timer)
|
|
(require syndicate/drivers/web)
|
|
|
|
(module+ test (require rackunit))
|
|
|
|
(define (sleep sec)
|
|
(define timer-id (gensym 'sleep))
|
|
(until (message (timer-expired timer-id _))
|
|
(on-start (send! (set-timer timer-id (* sec 1000.0) 'relative)))))
|
|
|
|
(define (random-hex-string half-length)
|
|
(bytes->hex-string (crypto-random-bytes half-length)))
|
|
|
|
(define (extend-url-string-query urlstr extension)
|
|
(define u (string->url urlstr))
|
|
(url->string (struct-copy url u [query (append (url-query u) extension)])))
|
|
|
|
(define (web-respond/status! id code message [body #""])
|
|
(web-respond/bytes! id
|
|
#:header (web-response-header
|
|
#:code code
|
|
#:message message
|
|
#:headers '())
|
|
body))
|
|
|
|
(define (web-request! verb urlstr
|
|
#:body [request-body #""]
|
|
#:headers [headers '()]
|
|
#:redirect-budget [redirect-budget 0])
|
|
(define req-id (gensym 'req))
|
|
(define u (string->url urlstr))
|
|
(define res (url->resource u))
|
|
(define-values (resp response-body)
|
|
(react/suspend (k)
|
|
(on-start
|
|
(printf "~a --> ~a ~a ~v\n" req-id verb urlstr request-body)
|
|
(send! (web-request req-id
|
|
'outbound
|
|
(web-request-header verb res headers (url-query u))
|
|
request-body)))
|
|
(stop-when (message (web-response-complete req-id $resp $response-body))
|
|
(printf "~a <-- ~v ~v\n" req-id resp response-body)
|
|
(k resp response-body))))
|
|
(define location (dict-ref (web-response-header-headers resp) 'location #f))
|
|
(if (and (eq? (web-response-header-code-type resp) 'redirection)
|
|
(positive? redirect-budget)
|
|
location)
|
|
(web-request! verb location
|
|
#:body request-body
|
|
#:headers headers
|
|
#:redirect-budget (- redirect-budget 1))
|
|
(values resp response-body)))
|
|
|
|
(module+ test
|
|
(check-equal? (extend-url-string-query "http://localhost/" '((a . "hi")))
|
|
"http://localhost/?a=hi")
|
|
(check-equal? (extend-url-string-query "http://localhost/" '())
|
|
"http://localhost/")
|
|
(check-equal? (extend-url-string-query "http://localhost?foo=bar" '())
|
|
"http://localhost?foo=bar")
|
|
(check-equal? (extend-url-string-query "http://localhost/?foo=bar" '())
|
|
"http://localhost/?foo=bar")
|
|
(check-equal? (extend-url-string-query "http://localhost?foo=bar" '((a . "hi")))
|
|
"http://localhost?foo=bar&a=hi")
|
|
(check-equal? (extend-url-string-query "http://localhost/?foo=bar" '((a . "hi")))
|
|
"http://localhost/?foo=bar&a=hi"))
|