File: servlet-dispatch.rkt

package info (click to toggle)
racket 7.9%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 178,684 kB
  • sloc: ansic: 282,112; lisp: 234,887; pascal: 70,954; sh: 27,112; asm: 16,268; makefile: 4,613; cpp: 2,715; ada: 1,681; javascript: 1,244; cs: 879; exp: 499; csh: 422; python: 274; xml: 106; perl: 104
file content (161 lines) | stat: -rw-r--r-- 6,193 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;; Derived from plai/web/server, which was based on an older version
;; of this Also derived from planet/untyped/instaservlet
#lang racket/base
(require (prefix-in net: net/sendurl)
         racket/match
         racket/local
         racket/contract
         racket/async-channel
         racket/list
         (only-in racket/tcp listen-port-number?)
         racket/unit
         racket/serialize
         net/url)
(require web-server/web-server
         web-server/managers/lru
         web-server/managers/manager
         web-server/configuration/namespace
         web-server/configuration/responders
         web-server/http
         web-server/stuffers
         web-server/servlet/setup
         web-server/servlet/servlet-structs
         web-server/dispatchers/dispatch
         web-server/safety-limits
         (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? . -> . can-be-response?))
                    (#:regexp regexp?
                     #:current-directory path-string?
                     #:stateless? boolean?
                     #:stuffer (stuffer/c serializable? bytes?)
                     #:manager manager?
                     #:responders-servlet-loading (url? any/c . -> . can-be-response?)
                     #:responders-servlet (url? any/c . -> . can-be-response?))
                    . ->* .
                    dispatcher/c)]
 [serve/launch/wait (((semaphore? . -> . dispatcher/c))
                     (#:launch-path (or/c #f string?)
                      #:connection-close? boolean?
                      #:banner? boolean?
                      #:listen-ip (or/c #f string?)
                      #:port listen-port-number?
                      #:max-waiting timeout/c
                      #:safety-limits safety-limits?
                      #:ssl-cert (or/c #f path-string?)
                      #:ssl-key (or/c #f path-string?))
                     . ->* .
                     any)])

(define (dispatch/servlet
         start
         #:regexp
         [servlet-regexp #rx""]
         #:current-directory
         [servlet-current-directory (current-directory)]
         #:stateless?
         [stateless? #f]
         #:stuffer
         [stuffer default-stuffer]
         #:responders-servlet-loading
         [responders-servlet-loading servlet-loading-responder]
         #:responders-servlet
         [responders-servlet servlet-error-responder]
         #:manager
         [manager
          (make-threshold-LRU-manager
           (lambda (request)
             (response/xexpr
              `(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 namespace-now (current-namespace))
  (filter:make
   servlet-regexp
   (servlets:make
    #:responders-servlet-loading responders-servlet-loading
    #:responders-servlet responders-servlet
    (lambda (url)
      (or (unbox servlet-box)
          (let ([servlet
                 (parameterize ([current-custodian (make-custodian)]
                                [current-namespace namespace-now])
                   (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

         #:connection-close?
         [connection-close? #f]
         #:launch-path
         [launch-path #f]
         #:banner?
         [banner? #t]

         #:listen-ip
         [listen-ip "127.0.0.1"]
         #:port
         [port-arg 8000]
         
         #:max-waiting [_max-waiting 511]
         #:safety-limits [limits (make-safety-limits #:max-waiting _max-waiting)]
         
         #:ssl-cert
         [ssl-cert #f]
         #:ssl-key
         [ssl-key #f])
  (define ssl? (and ssl-cert ssl-key))
  (define sema (make-semaphore 0))
  (define confirm-ch (make-async-channel 1))
  (define shutdown-server
    (serve #:confirmation-channel confirm-ch
           #:connection-close? connection-close?
           #:dispatch (dispatcher sema)
           #:listen-ip listen-ip
           #:port port-arg
           #:safety-limits limits
           #:dispatch-server-connect@ (if ssl?
                                        (make-ssl-connect@ ssl-cert ssl-key)
                                        raw:dispatch-server-connect@)))
  (define serve-res (async-channel-get confirm-ch))
  (if (exn? serve-res)
    (begin
      (when banner? (eprintf "There was an error starting the Web server.\n"))
      (match serve-res
        [(app exn-message (regexp "tcp-listen: listen on .+ failed \\(Address already in use; errno=.+\\)" (list _)))
         (when banner? (eprintf "\tThe TCP port (~a) is already in use.\n" port-arg))]
        [_
         (void)]))
    (local [(define port serve-res)
            (define server-url
              (string-append (if ssl? "https" "http")
                             "://localhost"
                             (if (and (not ssl?) (= port 80))
                               "" (format ":~a" port))))]
      (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 "Stop this program at any time to terminate the Web Server.\n")
        (flush-output))
      (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))))))