89 lines
3.7 KiB
Racket
89 lines
3.7 KiB
Racket
#lang racket/base
|
|
(require racket/contract)
|
|
(require web-server/servlet/setup
|
|
web-server/servlet/servlet-structs
|
|
web-server/managers/manager
|
|
web-server/http
|
|
web-server/http/response
|
|
net/url
|
|
web-server/dispatchers/dispatch
|
|
web-server/dispatchers/filesystem-map
|
|
web-server/configuration/responders
|
|
web-server/private/connection-manager
|
|
web-server/private/web-server-structs
|
|
web-server/private/servlet
|
|
web-server/private/cache-table)
|
|
(provide/contract
|
|
[interface-version dispatcher-interface-version/c])
|
|
(define interface-version 'v1)
|
|
|
|
(define url->servlet/c (url? . -> . servlet?))
|
|
(provide/contract
|
|
[url->servlet/c contract?]
|
|
[make-cached-url->servlet
|
|
(-> url->path/c
|
|
path->servlet/c
|
|
(values (-> void)
|
|
url->servlet/c))])
|
|
|
|
(define (make-cached-url->servlet
|
|
url->path
|
|
path->servlet)
|
|
(define config:scripts (make-cache-table))
|
|
(values (lambda ()
|
|
;; This is broken - only out of date or specifically mentioned scripts should be flushed. This destroys persistent state!
|
|
(cache-table-clear! config:scripts))
|
|
(lambda (uri)
|
|
(define-values (servlet-path _)
|
|
(with-handlers
|
|
([void (lambda (e)
|
|
(raise (make-exn:fail:filesystem:exists
|
|
(exn-message e)
|
|
(exn-continuation-marks e))))])
|
|
(url->path uri)))
|
|
(cache-table-lookup! config:scripts
|
|
(string->symbol (path->string servlet-path))
|
|
(lambda () (path->servlet servlet-path))))))
|
|
|
|
; -----
|
|
(provide/contract
|
|
[make (->* (url->servlet/c)
|
|
(#:responders-servlet-loading (url? any/c . -> . can-be-response?)
|
|
#:responders-servlet (url? any/c . -> . can-be-response?))
|
|
dispatcher/c)])
|
|
|
|
(define (make url->servlet
|
|
#:responders-servlet-loading [responders-servlet-loading servlet-loading-responder]
|
|
#:responders-servlet [responders-servlet servlet-error-responder])
|
|
(lambda (conn req)
|
|
(define uri (request-uri req))
|
|
(define instance-custodian (make-servlet-custodian))
|
|
(parameterize ([current-custodian instance-custodian]
|
|
[current-execution-context (make-execution-context req)]
|
|
[exit-handler
|
|
(lambda (r)
|
|
(kill-connection! conn)
|
|
(custodian-shutdown-all instance-custodian))])
|
|
(define maybe-response
|
|
(with-handlers ([exn:fail:filesystem:exists?
|
|
(lambda (the-exn) (next-dispatcher))]
|
|
[exn:dispatcher? raise]
|
|
[(lambda (x) #t)
|
|
(lambda (the-exn) (responders-servlet-loading uri the-exn))])
|
|
(define the-servlet (url->servlet uri))
|
|
(parameterize ([current-servlet the-servlet]
|
|
[current-custodian (servlet-custodian the-servlet)]
|
|
[current-directory (servlet-directory the-servlet)]
|
|
[current-namespace (servlet-namespace the-servlet)])
|
|
(with-handlers ([exn:dispatcher? raise]
|
|
[(lambda (x) #t)
|
|
(lambda (exn) (responders-servlet uri exn))])
|
|
(call-with-continuation-barrier
|
|
(lambda ()
|
|
(call-with-continuation-prompt
|
|
(lambda ()
|
|
((servlet-handler the-servlet) req))
|
|
servlet-prompt)))))))
|
|
|
|
(output-response conn (any->response maybe-response)))))
|