racket/collects/web-server/servlet-dispatch.rkt
Jay McCarthy 80b6ceeff1 Fixes PR11024.
The problem was that when the connection is closed its custodian is shutdown, thus killing the thread that was going to bring the server down. The difference between curl and the browser was that even though they both use HTTP/1.1, the browser actually leaves the connection open longer.
2010-07-15 10:14:16 -06:00

137 lines
4.8 KiB
Racket

; Derived from plai/web/server, which was based on an older version of this
; Also derived from planet/untyped/instaservlet
#lang racket
(require (prefix-in net: net/sendurl)
racket/contract
racket/list
racket/unit
racket/serialize
net/tcp-unit
net/tcp-sig
net/ssl-tcp-unit)
(require web-server/web-server
web-server/managers/lru
web-server/managers/manager
web-server/configuration/namespace
web-server/http
web-server/stuffers
web-server/servlet/setup
web-server/dispatchers/dispatch
(prefix-in filter: web-server/dispatchers/dispatch-filter)
(prefix-in servlets: web-server/dispatchers/dispatch-servlets))
(define send-url (make-parameter net:send-url))
(provide/contract
[dispatch/servlet (((request? . -> . response/c))
(#:regexp regexp?
#:current-directory path-string?
#:namespace (listof module-path?)
#:stateless? boolean?
#:stuffer (stuffer/c serializable? bytes?)
#:manager manager?)
. ->* .
dispatcher/c)]
[serve/launch/wait (((semaphore? . -> . dispatcher/c))
(#:launch-path (or/c false/c string?)
#:banner? boolean?
#:listen-ip (or/c false/c string?)
#:port number?
#:ssl-cert (or/c false/c path-string?)
#:ssl-key (or/c false/c path-string?))
. ->* .
void)])
(define (dispatch/servlet
start
#:regexp
[servlet-regexp #rx""]
#:current-directory
[servlet-current-directory (current-directory)]
#:namespace
[servlet-namespace empty]
#:stateless?
[stateless? #f]
#:stuffer
[stuffer default-stuffer]
#:manager
[manager
(make-threshold-LRU-manager
(lambda (request)
`(html (head (title "Page Has Expired."))
(body (p "Sorry, this page has expired. Please go back."))))
(* 64 1024 1024))])
(define servlet-box (box #f))
(define make-servlet-namespace
(make-make-servlet-namespace #:to-be-copied-module-specs servlet-namespace))
(filter:make
servlet-regexp
(servlets:make
(lambda (url)
(or (unbox servlet-box)
(let ([servlet
(parameterize ([current-custodian (make-custodian)]
[current-namespace
(make-servlet-namespace
#:additional-specs
default-module-specs)])
(if stateless?
(make-stateless.servlet servlet-current-directory stuffer manager start)
(make-v2.servlet servlet-current-directory manager start)))])
(set-box! servlet-box servlet)
servlet))))))
(define (serve/launch/wait
dispatcher
#:launch-path
[launch-path #f]
#:banner?
[banner? #t]
#:listen-ip
[listen-ip "127.0.0.1"]
#:port
[port 8000]
#:ssl-cert
[ssl-cert #f]
#:ssl-key
[ssl-key #f])
(define ssl? (and ssl-cert ssl-key))
(define server-url
(string-append (if ssl? "https" "http")
"://localhost"
(if (and (not ssl?) (= port 80))
"" (format ":~a" port))))
(define sema (make-semaphore 0))
(define shutdown-server
(serve #:dispatch (dispatcher sema)
#:listen-ip listen-ip
#:port port
#:tcp@ (if ssl?
(let ()
(define-unit-binding ssl-tcp@
(make-ssl-tcp@
ssl-cert ssl-key
#f #f #f #f #f)
(import) (export tcp^))
ssl-tcp@)
tcp@)))
(when launch-path
((send-url) (string-append server-url launch-path) #t))
(when banner?
(printf "Your Web application is running at ~a.\n"
(if launch-path
(string-append server-url launch-path)
server-url))
(printf "Click 'Stop' at any time to terminate the Web Server.\n"))
(let ([bye (lambda ()
(when banner? (printf "\nWeb Server stopped.\n"))
(shutdown-server))])
(with-handlers ([exn:break? (lambda (exn) (bye))])
(semaphore-wait/enable-break sema)
; Give the final response time to get there
(sleep 2)
;; We can get here if a /quit url is visited
(bye))))