diff --git a/collects/web-server/bindings.ss b/collects/web-server/bindings.ss index 1d8b699be0..d4846adf83 100644 --- a/collects/web-server/bindings.ss +++ b/collects/web-server/bindings.ss @@ -1,9 +1,7 @@ (module bindings mzscheme - (require (lib "list.ss")) - (provide extract-binding/single - extract-bindings - exists-binding?) - + (require (lib "list.ss") + (lib "contract.ss")) + ; extract-binding/single : sym (listof (cons str str)) -> str (define (extract-binding/single name bindings) (define lst (extract-bindings name bindings)) @@ -24,4 +22,9 @@ (define (exists-binding? name bindings) (if (assq name bindings) #t - #f))) \ No newline at end of file + #f)) + + (provide/contract + [extract-binding/single (symbol? (listof (cons/c symbol? any/c)) . -> . any/c)] + [extract-bindings (symbol? (listof (cons/c symbol? any/c)) . -> . (listof any/c))] + [exists-binding? (symbol? (listof (cons/c symbol? any/c)) . -> . boolean?)])) \ No newline at end of file diff --git a/collects/web-server/configuration-structures.ss b/collects/web-server/configuration-structures.ss index 3768301d93..12582865ed 100644 --- a/collects/web-server/configuration-structures.ss +++ b/collects/web-server/configuration-structures.ss @@ -1,19 +1,22 @@ (module configuration-structures mzscheme - (require "util.ss" + (require (lib "unitsig.ss") + (lib "contract.ss") + (lib "url.ss" "net")) + (require "response-structs.ss" "configuration-table-structs.ss") - (provide (struct timeouts (default-servlet password servlet-connection file-per-byte file-base)) - (struct paths (host-base log htdocs mime-types servlet))) - + ; configuration is now a unit. See sig.ss - + ; XXX contract + (define configuration? + unit/sig?) + ; host = (make-host (listof str) sym string - ; passwords resopnders timeouts paths) - (provide-define-struct - host (indices log-format log-path passwords responders timeouts paths)) - + ; passwords responders timeouts paths) + (define-struct host (indices log-format log-path passwords responders timeouts paths)) + ; passwords = (listof (list* relm:str protected-dir-regexp:str ; (listof (list user:sym password:str)))) - + ; responders = (make-responders (url tst -> response) ; (url tst -> response) ; (url (cons sym str) -> response) @@ -22,6 +25,31 @@ ; (url -> response) ; response ; response) - (provide-define-struct - responders - (servlet servlet-loading authentication servlets-refreshed passwords-refreshed file-not-found protocol collect-garbage))) + (define-struct responders + (servlet servlet-loading authentication servlets-refreshed passwords-refreshed file-not-found protocol collect-garbage)) + + (provide ; all-from + (struct timeouts (default-servlet password servlet-connection file-per-byte file-base)) + (struct paths (host-base log htdocs mime-types servlet))) + (provide/contract + [configuration? (any/c . -> . boolean?)] + [struct host + ([indices (listof string?)] + [log-format symbol?] + [log-path (or/c false/c path? string?)] + [passwords (or/c false/c path? string?)] + #;[passwords (listof (cons/c string? + (cons/c string? + (listof (list/c symbol? string?)))))] + [responders responders?] + [timeouts timeouts?] + [paths paths?])] + [struct responders + ([servlet (url? any/c . -> . response?)] + [servlet-loading (url? any/c . -> . response?)] + [authentication (url? (cons/c symbol? string?) . -> . response?)] + [servlets-refreshed (-> response?)] + [passwords-refreshed (-> response?)] + [file-not-found (url? . -> . response?)] + [protocol (url? . -> . response?)] + [collect-garbage (-> response?)])])) diff --git a/collects/web-server/configuration-table-structs.ss b/collects/web-server/configuration-table-structs.ss index 3b8ec6f1c4..5777164855 100644 --- a/collects/web-server/configuration-table-structs.ss +++ b/collects/web-server/configuration-table-structs.ss @@ -1,24 +1,55 @@ (module configuration-table-structs mzscheme - (require "util.ss") + (require (lib "contract.ss")) ; configuration-table = (make-configuration-table nat nat num host-table (listof (cons str host-table))) - (provide-define-struct - configuration-table - (port max-waiting initial-connection-timeout default-host virtual-hosts)) + (define-struct configuration-table + (port max-waiting initial-connection-timeout default-host virtual-hosts)) ; host-table = (make-host-table (listof str) sym messages timeouts paths) - (provide-define-struct host-table (indices log-format messages timeouts paths)) - - ; passwords = (listof (list* relm:str protected-dir-regexp:str (listof (list user:sym password:str)))) - ; passwords moved back to a separate file + (define-struct host-table (indices log-format messages timeouts paths)) ; messages = (make-messages str^6) - (provide-define-struct messages - (servlet ;servlet-loading - authentication servlets-refreshed passwords-refreshed file-not-found protocol collect-garbage)) - + (define-struct messages + (servlet authentication servlets-refreshed passwords-refreshed file-not-found protocol collect-garbage)) + ; timeouts = (make-timeouts nat^5) - (provide-define-struct timeouts (default-servlet password servlet-connection file-per-byte file-base)) + (define-struct timeouts (default-servlet password servlet-connection file-per-byte file-base)) ; paths = (make-paths str^6) - (provide-define-struct paths (conf host-base log htdocs servlet mime-types passwords))) + (define-struct paths (conf host-base log htdocs servlet mime-types passwords)) + + (provide/contract + [struct configuration-table + ([port natural-number/c] + [max-waiting natural-number/c] + [initial-connection-timeout natural-number/c] + [default-host host-table?] + [virtual-hosts (listof (cons/c string? host-table?))])] + [struct host-table + ([indices (listof string?)] + [log-format symbol?] + [messages messages?] + [timeouts timeouts?] + [paths paths?])] + [struct messages + ([servlet string?] + [authentication string?] + [servlets-refreshed string?] + [passwords-refreshed string?] + [file-not-found string?] + [protocol string?] + [collect-garbage string?])] + [struct timeouts + ([default-servlet number?] + [password number?] + [servlet-connection number?] + [file-per-byte number?] + [file-base number?])] + [struct paths + ([conf (or/c false/c path? string?)] + [host-base (or/c false/c path? string?)] + [log (or/c false/c path? string?)] + [htdocs (or/c false/c path? string?)] + [servlet (or/c false/c path? string?)] + [mime-types (or/c false/c path? string?)] + [passwords (or/c false/c path? string?)])])) diff --git a/collects/web-server/configuration-util.ss b/collects/web-server/configuration-util.ss index f1cbb82df3..4496735166 100644 --- a/collects/web-server/configuration-util.ss +++ b/collects/web-server/configuration-util.ss @@ -1,8 +1,8 @@ (module configuration-util mzscheme - (require (lib "file.ss") + (require (lib "contract.ss") + (lib "file.ss") (lib "pretty.ss")) - (require "configuration-table-structs.ss") - (provide (all-defined)) + (require "configuration-table-structs.ss") ; write-configuration-table : configuration-table path -> void ; writes out the new configuration file @@ -55,4 +55,9 @@ (define (write-to-file file-name x) (call-with-output-file file-name (lambda (out) (pretty-print x out)) - 'truncate))) \ No newline at end of file + 'truncate)) + + (provide/contract + [write-configuration-table (configuration-table? string? . -> . void)] + [format-host (host-table? . -> . list?)] + [write-to-file (string? list? . -> . void)])) \ No newline at end of file diff --git a/collects/web-server/configuration.ss b/collects/web-server/configuration.ss index b6f3e3022b..84e549b67e 100644 --- a/collects/web-server/configuration.ss +++ b/collects/web-server/configuration.ss @@ -1,5 +1,6 @@ -; configuration language example (module configuration mzscheme + (require (lib "unitsig.ss") + (lib "contract.ss")) (require "configuration-structures.ss" "configuration-table-structs.ss" "sig.ss" @@ -7,30 +8,6 @@ "parse-table.ss" "private/cache-table.ss" "response.ss") - (require (lib "unitsig.ss") - (lib "contract.ss")) - - (provide complete-configuration - get-configuration - build-developer-configuration - build-developer-configuration/vhosts ;; added 2/3/05 by Jacob - default-configuration-table-path - update-configuration) - - (provide/contract - [load-configuration (path? . -> . unit/sig?)] - [load-developer-configuration (path? . -> . unit/sig?)]) - - (provide error-response - servlet-loading-responder - gen-servlet-not-found - gen-servlet-responder - gen-servlets-refreshed - gen-passwords-refreshed - gen-authentication-responder - gen-protocol-responder - gen-file-not-found-responder - gen-collect-garbage-responder) (define default-configuration-table-path (build-path (collection-path "web-server") "configuration-table")) @@ -111,8 +88,6 @@ ; begin stolen from commander.ss, which was stolen from private/drscheme/eval.ss ; FIX - abstract this out to a namespace library somewhere (ask Robby and Matthew) - - (define to-be-copied-module-specs '(mzscheme ;; allow people (SamTH) to use MrEd primitives from servlets. @@ -122,7 +97,6 @@ (lib "mred.ss" "mred") (lib "servlet.ss" "web-server"))) - ; JBC : added error-handler hack; the right answer is only to transfer the 'mred' ; module binding when asked to, e.g. by a field in the configuration file. ; GregP: put this back in if Sam's code breaks @@ -203,7 +177,7 @@ ; gen-servlet-responder : str -> url tst -> response (define (gen-servlet-responder servlet-error-file) (lambda (url exn) - ; more here - use separate log file + ; XXX use separate log file ((error-display-handler) (format "Servlet exception:\n~a\n" (exn-message exn)) exn) @@ -296,4 +270,28 @@ (and (regexp-match (car x) host-name-possibly-followed-by-a-collon-and-a-port-number) (cadr x))) expanded-virtual-host-table) - default-host)))) + default-host))) + + (provide/contract + [complete-configuration (string? configuration-table? . -> . configuration?)] + [get-configuration (string? . -> . configuration-table?)] + ; XXX contract + [build-developer-configuration (list? . -> . configuration?)] + ; XXX contract + [build-developer-configuration/vhosts (list? . -> . configuration?)] + [default-configuration-table-path path?] + [update-configuration (configuration? (listof (cons/c symbol? any/c)) . -> . configuration?)] + [load-configuration (path? . -> . configuration?)] + [load-developer-configuration (path? . -> . configuration?)]) + (provide/contract + [error-response ((natural-number/c string? string?) (listof (cons/c symbol? string?)) . ->* . (response?))] + ; XXX contract + [servlet-loading-responder (string? any/c . -> . response?)] + [gen-servlet-not-found (string? . -> . (string? . -> . response?))] + [gen-servlet-responder (string? . -> . (string? any/c . -> . response?))] + [gen-servlets-refreshed (string? . -> . (-> response?))] + [gen-passwords-refreshed (string? . -> . (-> response?))] + [gen-authentication-responder (string? . -> . (string? (cons/c symbol? string?) . -> . response?))] + [gen-protocol-responder (string? . -> . (string? . -> . response?))] + [gen-file-not-found-responder (string? . -> . (string? . -> . response?))] + [gen-collect-garbage-responder (string? . -> . (-> response?))])) \ No newline at end of file diff --git a/collects/web-server/configure.ss b/collects/web-server/configure.ss index e3f5fb2cd6..331811673d 100644 --- a/collects/web-server/configure.ss +++ b/collects/web-server/configure.ss @@ -1,5 +1,4 @@ (module configure mzscheme - (provide servlet servlet-maker) (require (lib "unitsig.ss") (lib "servlet-sig.ss" "web-server") (lib "url.ss" "net") @@ -7,12 +6,17 @@ (lib "list.ss") (lib "pretty.ss") (lib "file.ss") + (lib "contract.ss") (only (lib "configuration.ss" "web-server") default-configuration-table-path) (lib "configuration-table-structs.ss" "web-server") (lib "parse-table.ss" "web-server") (lib "configuration-util.ss" "web-server") (all-except (lib "util.ss" "web-server") translate-escapes)) + (provide/contract + [servlet unit/sig?] + ; XXX contract + [servlet-maker (string? . -> . unit/sig?)]) ;; FIX ; - fuss with changing absolute paths into relative ones internally diff --git a/collects/web-server/dispatch-server-sig.ss b/collects/web-server/dispatch-server-sig.ss new file mode 100644 index 0000000000..083a5220ce --- /dev/null +++ b/collects/web-server/dispatch-server-sig.ss @@ -0,0 +1,13 @@ +(module dispatch-server-sig mzscheme + (require (lib "unitsig.ss")) + + (define-signature dispatch-server^ + (serve + serve-ports)) + + (define-signature dispatch-server-config^ + (port listen-ip max-waiting initial-connection-timeout + read-request dispatch)) + + (provide ; XXX contract signature + dispatch-server^ dispatch-server-config^)) \ No newline at end of file diff --git a/collects/web-server/dispatch-server-unit.ss b/collects/web-server/dispatch-server-unit.ss new file mode 100644 index 0000000000..d182817988 --- /dev/null +++ b/collects/web-server/dispatch-server-unit.ss @@ -0,0 +1,81 @@ +(module dispatch-server-unit mzscheme + (require (lib "tcp-sig.ss" "net") + (lib "unitsig.ss") + (lib "thread.ss") + (lib "contract.ss") + (lib "kw.ss")) + (require "web-server-structs.ss" + "connection-manager.ss" + "dispatch-server-sig.ss") + + (provide/contract + ; XXX contract + [dispatch-server@ unit/sig?]) + + ;; **************************************** + (define dispatch-server@ + (unit/sig dispatch-server^ + (import net:tcp^ (config : dispatch-server-config^)) + + ;; serve: -> -> void + ;; start the server and return a thunk to shut it down + (define (serve) + (define the-server-custodian (make-custodian)) + (start-connection-manager the-server-custodian) + (parameterize ([current-custodian the-server-custodian] + [current-server-custodian the-server-custodian] + [current-thread-initial-stack-size 3]) + (thread + (lambda () + (run-server config:port + handle-connection + #f + (lambda (exn) + #f) + (lambda (p mw re) + (tcp-listen p config:max-waiting #t config:listen-ip)) + tcp-close + tcp-accept + tcp-accept/enable-break)))) + (lambda () + (custodian-shutdown-all the-server-custodian))) + + ;; serve-ports : input-port output-port -> void + ;; returns immediately, spawning a thread to handle + ;; the connection + ;; NOTE: (GregP) should allow the user to pass in a connection-custodian + (define (serve-ports ip op) + (define server-cust (make-custodian)) + (start-connection-manager server-cust) + (parameterize ([current-custodian server-cust] + [current-server-custodian server-cust]) + (define connection-cust (make-custodian)) + (parameterize ([current-custodian connection-cust]) + (thread + (lambda () + (handle-connection ip op + (lambda (ip) + (values "127.0.0.1" + "127.0.0.1")))))))) + + ;; handle-connection : input-port output-port (input-port -> string string) -> void + ;; returns immediately, spawning a thread to handle + (define/kw (handle-connection ip op + #:optional + [port-addresses tcp-addresses]) + (define conn + (new-connection config:initial-connection-timeout + ip op (current-custodian) #f)) + (with-handlers ([exn:fail:network? + (lambda (e) + (kill-connection! conn) + (raise e))]) + (let connection-loop () + (define-values (req close?) (config:read-request conn config:port port-addresses)) + (adjust-connection-timeout! conn config:initial-connection-timeout) + (config:dispatch conn req) + (unless (connection-close? conn) + (set-connection-close?! conn close?)) + (cond + [(connection-close? conn) (kill-connection! conn)] + [else (connection-loop)]))))))) \ No newline at end of file diff --git a/collects/web-server/dispatchers/dispatch-files.ss b/collects/web-server/dispatchers/dispatch-files.ss index 8fee10ef1f..778f85cbc4 100644 --- a/collects/web-server/dispatchers/dispatch-files.ss +++ b/collects/web-server/dispatchers/dispatch-files.ss @@ -2,14 +2,17 @@ (require (lib "url.ss" "net") (lib "xml.ss" "xml") (lib "kw.ss") - (lib "list.ss")) + (lib "list.ss") + (lib "contract.ss")) (require "dispatch.ss" "../configuration.ss" "../util.ss" "../mime-types.ss" - "../response.ss") - (provide interface-version - make) + "../response.ss") + (provide/contract + [interface-version dispatcher-interface-version?]) + (provide ; XXX contract kw + make) (define interface-version 'v1) (define/kw (make #:key diff --git a/collects/web-server/dispatchers/dispatch-host.ss b/collects/web-server/dispatchers/dispatch-host.ss index 572d81aa4b..f552ef7434 100644 --- a/collects/web-server/dispatchers/dispatch-host.ss +++ b/collects/web-server/dispatchers/dispatch-host.ss @@ -1,11 +1,12 @@ (module dispatch-host mzscheme + (require (lib "contract.ss")) (require "dispatch.ss" "../servlet-helpers.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?] + [make ((symbol? . -> . dispatcher?) . -> . dispatcher?)]) (define interface-version 'v1) - (define (make lookup-dispatcher) - (lambda (conn req) - (let* ([host (get-host (request-uri req) (request-headers/raw req))]) - ((lookup-dispatcher host) conn req))))) \ No newline at end of file + (define ((make lookup-dispatcher) conn req) + (define host (get-host (request-uri req) (request-headers/raw req))) + ((lookup-dispatcher host) conn req))) \ No newline at end of file diff --git a/collects/web-server/dispatchers/dispatch-log.ss b/collects/web-server/dispatchers/dispatch-log.ss index 50b62b6b84..60c0ff3ac7 100644 --- a/collects/web-server/dispatchers/dispatch-log.ss +++ b/collects/web-server/dispatchers/dispatch-log.ss @@ -3,11 +3,14 @@ (lib "date.ss") (lib "kw.ss") (lib "async-channel.ss") - (lib "plt-match.ss")) + (lib "plt-match.ss") + (lib "contract.ss")) (require "dispatch.ss" "../servlet-helpers.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?]) + (provide ; XXX contract kw + make) (define interface-version 'v1) (define/kw (make #:key diff --git a/collects/web-server/dispatchers/dispatch-passwords.ss b/collects/web-server/dispatchers/dispatch-passwords.ss index 1efa3dfe0d..70feca3762 100644 --- a/collects/web-server/dispatchers/dispatch-passwords.ss +++ b/collects/web-server/dispatchers/dispatch-passwords.ss @@ -1,13 +1,16 @@ (module dispatch-passwords mzscheme - (require (lib "kw.ss")) + (require (lib "kw.ss") + (lib "contract.ss")) (require "dispatch.ss" (all-except "../util.ss" translate-escapes) "../configuration.ss" "../servlet-helpers.ss" "../connection-manager.ss" "../response.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?]) + (provide ; XXX contract kw + make) (define interface-version 'v1) (define/kw (make #:key diff --git a/collects/web-server/dispatchers/dispatch-pathprocedure.ss b/collects/web-server/dispatchers/dispatch-pathprocedure.ss index a6710fc05b..c1d052e6b5 100644 --- a/collects/web-server/dispatchers/dispatch-pathprocedure.ss +++ b/collects/web-server/dispatchers/dispatch-pathprocedure.ss @@ -1,9 +1,11 @@ (module dispatch-pathprocedure mzscheme + (require (lib "contract.ss")) (require "dispatch.ss" "../util.ss" "../response.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?] + [make (string? (-> response?) . -> . dispatcher?)]) (define interface-version 'v1) (define ((make the-path procedure) conn req) diff --git a/collects/web-server/dispatchers/dispatch-sequencer.ss b/collects/web-server/dispatchers/dispatch-sequencer.ss index ade520e799..cf7ae402c3 100644 --- a/collects/web-server/dispatchers/dispatch-sequencer.ss +++ b/collects/web-server/dispatchers/dispatch-sequencer.ss @@ -1,8 +1,11 @@ (module dispatch-sequencer mzscheme - (require (lib "list.ss")) + (require (lib "list.ss") + (lib "contract.ss")) (require "dispatch.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?]) + (provide ; XXX contract kw + make) (define interface-version 'v1) (define ((make . dispatchers) conn req) diff --git a/collects/web-server/dispatchers/dispatch-servlets.ss b/collects/web-server/dispatchers/dispatch-servlets.ss index e50ec2660c..4a10cc0356 100644 --- a/collects/web-server/dispatchers/dispatch-servlets.ss +++ b/collects/web-server/dispatchers/dispatch-servlets.ss @@ -2,7 +2,8 @@ (require (lib "url.ss" "net") (lib "kw.ss") (lib "plt-match.ss") - (lib "unitsig.ss")) + (lib "unitsig.ss") + (lib "contract.ss")) (require "dispatch.ss" "../web-server-structs.ss" "../connection-manager.ss" @@ -13,11 +14,15 @@ (all-except "../util.ss" translate-escapes) "../managers/manager.ss" "../managers/timeouts.ss" + "../managers/lru.ss" "../private/url.ss" "../private/servlet.ss" "../private/cache-table.ss") - (provide interface-version - make) + (provide/contract + [interface-version dispatcher-interface-version?]) + (provide ; XXX contract improve + ; XXX contract kw + make) (define interface-version 'v1) (define/kw (make config:instances config:scripts config:make-servlet-namespace @@ -362,4 +367,4 @@ ;; more here - make timeouts proportional to size of bindings (servlet-content-producer conn req)] [else - (next-dispatcher)])))) \ No newline at end of file + (next-dispatcher)])))) diff --git a/collects/web-server/dispatchers/dispatch.ss b/collects/web-server/dispatchers/dispatch.ss index 9aa88d8e00..70f3c91dff 100644 --- a/collects/web-server/dispatchers/dispatch.ss +++ b/collects/web-server/dispatchers/dispatch.ss @@ -1,14 +1,18 @@ (module dispatch mzscheme + (require (lib "contract.ss")) (require "../connection-structs.ss" "../request-structs.ss" "../response-structs.ss") - (require (lib "contract.ss") - (lib "list.ss")) - (provide dispatcher?) - (define dispatcher? (connection? request? . -> . response?)) - - (provide next-dispatcher - [struct exn:dispatcher ()]) + (define dispatcher? + (connection? request? . -> . void)) + (define dispatcher-interface-version? + symbol?) (define-struct exn:dispatcher ()) - (define (next-dispatcher) (raise (make-exn:dispatcher)))) \ No newline at end of file + (define (next-dispatcher) (raise (make-exn:dispatcher))) + + (provide/contract + [dispatcher? contract?] + [dispatcher-interface-version? (any/c . -> . boolean?)] + [next-dispatcher (-> void)] + [struct exn:dispatcher ()])) \ No newline at end of file diff --git a/collects/web-server/launch.ss b/collects/web-server/launch.ss index bbd0593d43..9161ea9d83 100644 --- a/collects/web-server/launch.ss +++ b/collects/web-server/launch.ss @@ -2,12 +2,14 @@ (module launch mzscheme (require (lib "cmdline.ss") (lib "pregexp.ss") - "util.ss" + (lib "contract.ss") + (lib "unitsig.ss") + (lib "tcp-sig.ss" "net")) + (require "util.ss" "web-server-unit.ss" "sig.ss" "configuration.ss" - (lib "unitsig.ss") - (lib "tcp-sig.ss" "net")) + "configuration-structures.ss") (define configuration@ (parse-command-line @@ -58,4 +60,5 @@ (export (open S))) #f net:tcp^) - (provide serve)) + (provide ; XXX contract + serve)) \ No newline at end of file diff --git a/collects/web-server/managers/lru.ss b/collects/web-server/managers/lru.ss index a7a63e214d..1c1873b092 100644 --- a/collects/web-server/managers/lru.ss +++ b/collects/web-server/managers/lru.ss @@ -1,8 +1,12 @@ (module lru mzscheme (require (lib "plt-match.ss") + (lib "contract.ss") (lib "kw.ss")) - (require "manager.ss") - (provide create-LRU-manager) + (require "manager.ss" + "../servlet-structs.ss") + (provide/contract + ; XXX contract kw + [create-LRU-manager ((expiration-handler? number? number? (-> boolean?)) any/c . ->* . (manager?))]) ;; Utility (define (make-counter) diff --git a/collects/web-server/managers/manager.ss b/collects/web-server/managers/manager.ss index f1931a9197..5e0164b0cc 100644 --- a/collects/web-server/managers/manager.ss +++ b/collects/web-server/managers/manager.ss @@ -1,5 +1,6 @@ (module manager mzscheme - (provide (all-defined)) + (require (lib "contract.ss")) + (require "../servlet-structs.ss") (define-struct manager (create-instance adjust-timeout! @@ -9,4 +10,20 @@ continuation-lookup)) (define-struct (exn:fail:servlet-manager:no-instance exn:fail) (expiration-handler)) - (define-struct (exn:fail:servlet-manager:no-continuation exn:fail) (expiration-handler))) + (define-struct (exn:fail:servlet-manager:no-continuation exn:fail) (expiration-handler)) + + (provide/contract + [struct manager ([create-instance (any/c (-> void) . -> . number?)] + [adjust-timeout! (number? number? . -> . void)] + [instance-lookup-data (number? . -> . any/c)] + [clear-continuations! (number? . -> . void)] + [continuation-store! (number? procedure? expiration-handler? . -> . (list/c number? number?))] + [continuation-lookup (number? number? number? . -> . procedure?)])] + [struct (exn:fail:servlet-manager:no-instance exn:fail) + ([msg string?] + [continuation-marks continuation-mark-set?] + [expiration-handler expiration-handler?])] + [struct (exn:fail:servlet-manager:no-continuation exn:fail) + ([msg string?] + [continuation-marks continuation-mark-set?] + [expiration-handler expiration-handler?])])) \ No newline at end of file diff --git a/collects/web-server/managers/timeouts.ss b/collects/web-server/managers/timeouts.ss index d446f4448a..5ecfffefb6 100644 --- a/collects/web-server/managers/timeouts.ss +++ b/collects/web-server/managers/timeouts.ss @@ -1,8 +1,11 @@ (module timeouts mzscheme - (require (lib "plt-match.ss")) + (require (lib "plt-match.ss") + (lib "contract.ss")) (require "manager.ss") - (require "../timer.ss") - (provide create-timeout-manager) + (require "../timer.ss" + "../servlet-structs.ss") + (provide/contract + [create-timeout-manager (expiration-handler? number? number? . -> . manager?)]) ;; Utility (define (make-counter) diff --git a/collects/web-server/monitor-server.ss b/collects/web-server/monitor-server.ss index d39a574852..b3b2e6f828 100644 --- a/collects/web-server/monitor-server.ss +++ b/collects/web-server/monitor-server.ss @@ -1,13 +1,9 @@ (module monitor-server mzscheme (require (lib "etc.ss") - "monitor-poke-web-server.ss" - "monitor-emailer.ss" + (lib "contract.ss") (lib "match.ss")) - - (provide monitor - default-server-port - default-poll-frequency-seconds - default-server-response-timeout-seconds) + (require "monitor-poke-web-server.ss" + "monitor-emailer.ss") (define default-server-port 80) (define default-poll-frequency-seconds 3600) @@ -33,4 +29,10 @@ [`(ok) (void)] [else (send-email (result->message result))]) (sleep poll-frequency-seconds) - (check-server)))))) \ No newline at end of file + (check-server))))) + + (provide/contract + [monitor ((string? string?) (number? number? number?) . -> . void)] + [default-server-port number?] + [default-poll-frequency-seconds number?] + [default-server-response-timeout-seconds number?])) \ No newline at end of file diff --git a/collects/web-server/parse-table.ss b/collects/web-server/parse-table.ss index 5cfc5502ea..560964f1c2 100644 --- a/collects/web-server/parse-table.ss +++ b/collects/web-server/parse-table.ss @@ -1,8 +1,8 @@ (module parse-table mzscheme - (require (lib "list.ss")) + (require (lib "list.ss") + (lib "contract.ss")) (require "configuration-table-structs.ss" "bindings.ss") - (provide parse-configuration-table) (define (get-binding key bindings default) (first (get-binding* key bindings (list default)))) @@ -83,4 +83,8 @@ ; nat? : tst -> bool (define (nat? x) - (and (number? x) (exact? x) (integer? x) (<= 0 x)))) + (and (number? x) (exact? x) (integer? x) (<= 0 x))) + + (provide/contract + ; XXX contract + [parse-configuration-table (list? . -> . configuration-table?)])) \ No newline at end of file diff --git a/collects/web-server/private/cache-table.ss b/collects/web-server/private/cache-table.ss index da6c2d7087..5ee5743ec6 100644 --- a/collects/web-server/private/cache-table.ss +++ b/collects/web-server/private/cache-table.ss @@ -36,5 +36,5 @@ [rename new-cache-table make-cache-table (-> cache-table?)] [cache-table-lookup! (cache-table? symbol? (-> any/c) . -> . any/c)] - [cache-table-clear! (cache-table? . -> . void?)]) - (provide cache-table?)) \ No newline at end of file + [cache-table-clear! (cache-table? . -> . void?)] + [cache-table? (any/c . -> . boolean?)])) \ No newline at end of file diff --git a/collects/web-server/private/servlet.ss b/collects/web-server/private/servlet.ss index 5e2d2ebde6..5fe2842acc 100644 --- a/collects/web-server/private/servlet.ss +++ b/collects/web-server/private/servlet.ss @@ -1,10 +1,13 @@ (module servlet mzscheme - (require "../managers/manager.ss") + (require (lib "contract.ss")) + (require "../managers/manager.ss" + "../servlet-structs.ss" + "../connection-structs.ss" + "../request-structs.ss") (define-struct (exn:fail:servlet:instance exn:fail) ()) (define-struct servlet (custodian namespace manager handler)) - (define-struct servlet-instance-data (mutex context)) - + (define-struct servlet-instance-data (mutex context)) (define-struct execution-context (connection request suspend)) (define current-servlet (make-thread-cell #f)) @@ -27,4 +30,26 @@ (define instance-id (thread-cell-ref current-servlet-instance-id)) ((manager-instance-lookup-data manager) instance-id)) - (provide (all-defined))) + (provide/contract + [struct (exn:fail:servlet:instance exn:fail) + ([msg string?] + [continuation-marks continuation-mark-set?])] + [struct servlet + ([custodian custodian?] + [namespace namespace?] + [manager manager?] + [handler (request? . -> . servlet-response?)])] + [struct servlet-instance-data + ([mutex semaphore?] + [context execution-context?])] + [struct execution-context + ([connection connection?] + [request request?] + [suspend procedure?])] + ; XXX contract maybe + [current-servlet thread-cell?] + ; XXX contract maybe + [current-servlet-instance-id thread-cell?] + [get-current-servlet-instance-id (-> number?)] + [current-servlet-manager (-> manager?)] + [current-servlet-instance-data (-> servlet-instance-data?)])) \ No newline at end of file diff --git a/collects/web-server/private/url.ss b/collects/web-server/private/url.ss index 6306ddb0a5..0cf0dc3b19 100644 --- a/collects/web-server/private/url.ss +++ b/collects/web-server/private/url.ss @@ -4,9 +4,9 @@ (lib "list.ss") (lib "plt-match.ss")) - (provide - match-url-params) (provide/contract + ; XXX contract maybe + [match-url-params (string? . -> . (or/c false/c (list/c string? string? string? string?)))] [continuation-url? (url? . -> . (or/c boolean? (list/c number? number? number?)))] [embed-ids ((list/c number? number? number?) url? . -> . string?)]) diff --git a/collects/web-server/servlet-helpers.ss b/collects/web-server/servlet-helpers.ss index 2c23bb5936..9db4152830 100644 --- a/collects/web-server/servlet-helpers.ss +++ b/collects/web-server/servlet-helpers.ss @@ -1,5 +1,5 @@ (module servlet-helpers mzscheme - (require (lib "list.ss") + (require (lib "contract.ss") (lib "etc.ss") (lib "plt-match.ss") (lib "xml.ss" "xml") @@ -8,21 +8,10 @@ (require "util.ss" "response.ss" "request-structs.ss" - "bindings.ss") - (provide get-host - (all-from "bindings.ss") - extract-user-pass - build-suspender - make-html-response/incremental - report-errors-to-browser - redirect-to - permanently - temporarily - see-other - (all-from "request-structs.ss") - request-bindings - request-headers - translate-escapes) + "bindings.ss" + "servlet-structs.ss") + (provide (all-from "bindings.ss") + (all-from "request-structs.ss")) (define (request-headers request) (map (match-lambda @@ -51,7 +40,7 @@ [(struct header (_ v)) (string->symbol (bytes->string/utf-8 v))])] [else DEFAULT-HOST-NAME])) - + ; build-suspender : (listof html) (listof html) [(listof (cons sym str))] [(listof (cons sym str))] -> str -> response (define build-suspender (opt-lambda (title content [body-attributes '([bgcolor "white"])] [head-attributes null]) @@ -134,4 +123,24 @@ ;; does the second part of the authorization header start with #"Basic " (define basic? (let ([rx (byte-regexp #"^Basic .*")]) - (lambda (a) (regexp-match rx a))))) \ No newline at end of file + (lambda (a) (regexp-match rx a)))) + + (provide ; all-from + translate-escapes) + (provide/contract + [get-host (url? (listof header?) . -> . symbol?)] + ; XXX contract maybe + [extract-user-pass ((listof header?) . -> . (or/c false/c (cons/c string? string?)))] + [build-suspender (((listof xexpr?) (listof xexpr?)) + ((listof (list/c symbol? string?)) (listof (list/c symbol? string?))) + . opt-> . + (k-url? . -> . xexpr?))] + [make-html-response/incremental (((string? . -> . void) . -> . void) . -> . response/incremental?)] + [report-errors-to-browser ((servlet-response? . -> . void) . -> . void)] + [redirect-to ((string?) (redirection-status?) . opt-> . response/full?)] + [permanently redirection-status?] + [temporarily redirection-status?] + [see-other redirection-status?] + [request-bindings (request? . -> . (listof (or/c (cons/c symbol? string?) + (cons/c symbol? bytes?))))] + [request-headers (request? . -> . (listof (cons/c symbol? string?)))])) \ No newline at end of file diff --git a/collects/web-server/servlet-language.ss b/collects/web-server/servlet-language.ss index 2c64e667af..27caa0bb8b 100644 --- a/collects/web-server/servlet-language.ss +++ b/collects/web-server/servlet-language.ss @@ -1,10 +1,11 @@ (module servlet-language mzscheme (require (lib "class.ss") (lib "tool.ss" "drscheme") + (lib "contract.ss") ;(lib "mred.ss" "mred") (lib "unitsig.ss")) - - (provide tool@) + (provide/contract + [tool@ unit/sig?]) (define tool@ (unit/sig drscheme:tool-exports^ @@ -99,5 +100,4 @@ ;(language-numbers (list -1000 1000)) )) - ))) - ) + )))) \ No newline at end of file diff --git a/collects/web-server/servlet-structs.ss b/collects/web-server/servlet-structs.ss new file mode 100644 index 0000000000..622f35c8eb --- /dev/null +++ b/collects/web-server/servlet-structs.ss @@ -0,0 +1,42 @@ +(module servlet-structs mzscheme + (require (lib "contract.ss") + (lib "xml.ss" "xml")) + (require "request-structs.ss" + "response-structs.ss") + + (define servlet-response? + any/c) + + (define (xexpr/callback? x) + (correct-xexpr? x + (lambda () #t) + (lambda (exn) + (if (procedure? (exn:invalid-xexpr-code exn)) + #t + (begin ((error-display-handler) (exn-message exn) exn) + #f))))) + + (define k-url? + string?) + + (define response-generator? + (k-url? . -> . servlet-response?)) + + (define url-transform? + (k-url? . -> . k-url?)) + + (define expiration-handler? + (or/c false/c + (request? . -> . response?))) + + (define embed/url? + (((request? . -> . any/c)) (expiration-handler?) . opt-> . string?)) + + (provide/contract + [servlet-response? contract?] + [xexpr/callback? (any/c . -> . boolean?)] + [response-generator? contract?] + [k-url? (any/c . -> . boolean?)] + [url-transform? contract?] + [expiration-handler? contract?] + [embed/url? contract?])) \ No newline at end of file diff --git a/collects/web-server/servlet.ss b/collects/web-server/servlet.ss index e1291e25f4..ea72b2a768 100644 --- a/collects/web-server/servlet.ss +++ b/collects/web-server/servlet.ss @@ -7,35 +7,8 @@ "private/servlet.ss" "private/url.ss" "servlet-helpers.ss" - "timer.ss" - "web-cells.ss") - - ;; CONTRACT HELPERS - (define servlet-response? any/c) - - (define (xexpr/callback? x) - (correct-xexpr? x - (lambda () #t) - (lambda (exn) - (if (procedure? (exn:invalid-xexpr-code exn)) - #t - (begin ((error-display-handler) (exn-message exn) exn) - #f))))) - - (define response-generator? - (string? . -> . servlet-response?)) - - (define url-transform? - (string? . -> . string?)) - - (define expiration-handler? - (request? . -> . void?)) - - (define (parameter/c c) - parameter?) - - (define embed/url? - (((request? . -> . any/c)) (expiration-handler?) . opt-> . string?)) + "web-cells.ss" + "servlet-structs.ss") ;; ************************************************************ ;; HELPERS @@ -52,10 +25,11 @@ ;; Weak contracts: the input is checked in output-response, and a message is ;; sent directly to the client (Web browser) instead of the terminal/log. (provide/contract - [xexpr/callback? (any/c . -> . boolean?)] [xexpr/callback->xexpr (embed/url? xexpr/callback? . -> . xexpr?)] - [current-url-transform (parameter/c url-transform?)] - [current-servlet-continuation-expiration-handler (parameter/c expiration-handler?)] + ; XXX contract + [current-url-transform parameter?] + ; XXX contract + [current-servlet-continuation-expiration-handler parameter?] [redirect/get (-> request?)] [redirect/get/forget (-> request?)] [adjust-timeout! (number? . -> . void?)] @@ -68,17 +42,18 @@ [send/suspend/callback (xexpr/callback? . -> . any/c)]) (require "url.ss") - (provide - (all-from "web-cells.ss") - (all-from "servlet-helpers.ss") - (all-from "url.ss")) + (provide (all-from "web-cells.ss") + (all-from "servlet-helpers.ss") + (all-from "url.ss") + (all-from "servlet-structs.ss")) ;; ************************************************************ ;; EXPORTS ;; current-url-transform : string? -> string? + (define (default-url-transformer x) x) (define current-url-transform - (make-parameter identity)) + (make-parameter default-url-transformer)) ;; current-servlet-continuation-expiration-handler : request -> response (define current-servlet-continuation-expiration-handler diff --git a/collects/web-server/sig.ss b/collects/web-server/sig.ss index 926df5f83b..12d21d48f4 100644 --- a/collects/web-server/sig.ss +++ b/collects/web-server/sig.ss @@ -1,21 +1,12 @@ (module sig mzscheme (require (lib "unitsig.ss")) - (provide - dispatch-server^ dispatch-server-config^ + (require "dispatch-server-sig.ss") + (provide ; XXX contract signature web-server^ servlet^ web-config^ web-config/pervasive^ web-config/local^) - (define-signature dispatch-server^ - (serve - serve-ports - ; for environment: - server-loop)) (define-signature web-server^ ((open dispatch-server^))) - (define-signature dispatch-server-config^ - (port listen-ip max-waiting initial-connection-timeout - read-request dispatch)) - (define-signature servlet^ (initial-request send/suspend send/finish send/back send/forward adjust-timeout!)) diff --git a/collects/web-server/timer.ss b/collects/web-server/timer.ss index c0a7fce8e6..749680d422 100644 --- a/collects/web-server/timer.ss +++ b/collects/web-server/timer.ss @@ -1,11 +1,8 @@ (module timer mzscheme - (require "timer-structs.ss") (require (lib "list.ss") + (lib "contract.ss") (lib "async-channel.ss")) - (provide timer? - start-timer reset-timer! increment-timer! - cancel-timer! - start-timer-manager) + (require "timer-structs.ss") (define timer-ch (make-async-channel)) @@ -86,7 +83,15 @@ (revise-timer! timer (+ (- (timer-expire-seconds timer) (current-inexact-milliseconds)) (* 1000 secs)) - (timer-action timer)))) + (timer-action timer))) + + (provide/contract + [timer? (any/c . -> . boolean?)] + [start-timer-manager (custodian? . -> . void)] + [start-timer (number? (-> void) . -> . timer?)] + [reset-timer! (timer? number? . -> . void)] + [increment-timer! (timer? number? . -> . void)] + [cancel-timer! (timer? . -> . void)])) ; --- timeout plan diff --git a/collects/web-server/url.ss b/collects/web-server/url.ss index b7e27b6c1d..db49998e56 100644 --- a/collects/web-server/url.ss +++ b/collects/web-server/url.ss @@ -1,18 +1,12 @@ (module url mzscheme (require (lib "list.ss") (lib "etc.ss") + (lib "contract.ss") (lib "url.ss" "net") (lib "struct.ss")) (require "private/url.ss" "request-structs.ss") - - ;; URL parsing - (provide (struct servlet-url (protocol host port servlets-root instance-id k-id nonce servlet-path extra-path)) - servlet-url->url-string - servlet-url->url-string/no-continuation - servlet-url->servlet-url/no-extra-path - request->servlet-url - uri->servlet-url) + (define-struct servlet-url (protocol host port servlets-root instance-id k-id nonce @@ -38,17 +32,17 @@ (define (servlet-url->url-string su) (let ([the-url (make-url (servlet-url-protocol su) - #f - #f ;(servlet-url-host su) - #f ;(servlet-url-port su) - #t - (append (reverse (rest (reverse (servlet-url-servlets-root su)))) - (list (make-path/param (path/param-path (first (reverse (servlet-url-servlets-root su)))) - empty)) - (servlet-url-servlet-path su) - (servlet-url-extra-path su)) - empty - #f)]) + #f + #f ;(servlet-url-host su) + #f ;(servlet-url-port su) + #t + (append (reverse (rest (reverse (servlet-url-servlets-root su)))) + (list (make-path/param (path/param-path (first (reverse (servlet-url-servlets-root su)))) + empty)) + (servlet-url-servlet-path su) + (servlet-url-extra-path su)) + empty + #f)]) (if (and (servlet-url-instance-id su) (servlet-url-k-id su) (servlet-url-nonce su)) @@ -88,4 +82,22 @@ (list (first (url-path uri))) k-instance k-id k-salt servlet-path - path))))) + path)))) + + (provide/contract + ; XXX contract maybe + [struct servlet-url ([protocol (or/c false/c string?)] + [host (or/c false/c string?)] + [port (or/c false/c natural-number/c)] + [servlets-root (listof path/param?)] + [instance-id number?] + [k-id number?] + [nonce number?] + [servlet-path (listof path/param?)] + [extra-path (listof path/param?)])] + [servlet-url->url-string (servlet-url? . -> . string?)] + [servlet-url->url-string/no-continuation (servlet-url? . -> . string?)] + [servlet-url->servlet-url/no-extra-path (servlet-url? . -> . servlet-url?)] + [request->servlet-url (request? . -> . servlet-url?)] + ; XXX contract maybe + [uri->servlet-url ((url?) ((or/c false/c string?) (or/c false/c natural-number/c)) . opt-> . servlet-url?)])) \ No newline at end of file diff --git a/collects/web-server/util.ss b/collects/web-server/util.ss index 19ca24028d..51b8564d80 100644 --- a/collects/web-server/util.ss +++ b/collects/web-server/util.ss @@ -8,24 +8,6 @@ (lib "uri-codec.ss" "net")) (require "request-structs.ss") - (provide provide-define-struct - extract-flag - translate-escapes - hash-table-empty? - url-path->string) - - (provide/contract - [valid-port? (any/c . -> . boolean?)] - [decompose-request ((request?) . ->* . (url? symbol? string?))] - [network-error ((symbol? string?) (listof any/c) . ->* . (void))] - [path->list (path? . -> . (cons/c (or/c path? (symbols 'up 'same)) - (listof (or/c path? (symbols 'up 'same)))))] - [url-path->path ((or/c (symbols 'up 'same) path?) string? . -> . path?)] - [directory-part (path? . -> . path?)] - [lowercase-symbol! ((or/c string? bytes?) . -> . symbol?)] - [exn->string ((or/c exn? any/c) . -> . string?)] - [build-path-unless-absolute (path? (or/c string? path?) . -> . path?)]) - ;; valid-port? : any/c -> boolean? (define (valid-port? p) (and (number? p) (integer? p) (exact? p) (<= 1 p 65535))) @@ -40,7 +22,7 @@ [else (list* "/" (maybe-join-params (car strs)) (loop (cdr strs)))])))) - + ;; needs to unquote things! (define (maybe-join-params s) (cond @@ -89,7 +71,7 @@ ;; Notes: (GregP) ;; 1. What's the significance of char # 255 ??? ;; 2. 255 isn't an ascii character. ascii is 7-bit - ;; 3. OK fuck this. It is only used in three places, some of them + ;; 3. OK f this. It is only used in three places, some of them ;; will involve bytes while the others may involve strings. So ;; I will just use regular expressions and get on with life. (define (prefix?-old prefix) @@ -152,20 +134,6 @@ [else (cons x acc)])) null (regexp-split #rx"/" p))))))) - - ; update-params : Url (U #f String) -> String - ; to create a new url just like the old one, but with a different parameter part - ;; GREGP: this is broken! replace with the version from new-kernel - ; (define (update-params uri params) - ; (url->string - ; (make-url (url-scheme uri) - ; (url-user uri) - ; (url-host uri) - ; (url-port uri) - ; (url-path uri) - ; params - ; (url-query uri) - ; (url-fragment uri)))) ; to convert a platform dependent path into a listof path parts such that ; (forall x (equal? (path->list x) (path->list (apply build-path (path->list x))))) @@ -178,19 +146,9 @@ [else ; conflate 'relative and #f new-acc]))))) - ; this should go somewhere that other collections can use it too - (define-syntax provide-define-struct - (lambda (stx) - (syntax-case stx () - [(_ (struct-name parent-name) (field ...)) - (syntax (begin (define-struct (struct-name parent-name) (field ...)) - (provide (struct struct-name (field ...)))))] - [(_ struct-name (field ...)) - (syntax (begin (define-struct struct-name (field ...)) - (provide (struct struct-name (field ...)))))]))) - ; this is used by launchers ; extract-flag : sym (listof (cons sym alpha)) alpha -> alpha + ; XXX remove (define (extract-flag name flags default) (let ([x (assq name flags)]) (if x @@ -199,9 +157,7 @@ ; hash-table-empty? : hash-table -> bool (define (hash-table-empty? table) - (let/ec out - (hash-table-for-each table (lambda (k v) (out #f))) - #t)) + (zero? (hash-table-count table))) ; This comes from Shriram's collection, and should be exported form there. ; translate-escapes : String -> String @@ -220,4 +176,20 @@ (cond [(char=? ic #\+) #\space] [else ic])) - (list* c (loop cs))]))))) \ No newline at end of file + (list* c (loop cs))])))) + + (provide/contract + [url-path->string ((listof (or/c string? path/param?)) . -> . string?)] + [extract-flag (symbol? (listof (cons/c symbol? any/c)) any/c . -> . any/c)] + [translate-escapes (string? . -> . string?)] + [hash-table-empty? (any/c . -> . boolean?)] + [valid-port? (any/c . -> . boolean?)] + [decompose-request ((request?) . ->* . (url? symbol? string?))] + [network-error ((symbol? string?) (listof any/c) . ->* . (void))] + [path->list (path? . -> . (cons/c (or/c path? (symbols 'up 'same)) + (listof (or/c path? (symbols 'up 'same)))))] + [url-path->path ((or/c (symbols 'up 'same) path?) string? . -> . path?)] + [directory-part (path? . -> . path?)] + [lowercase-symbol! ((or/c string? bytes?) . -> . symbol?)] + [exn->string ((or/c exn? any/c) . -> . string?)] + [build-path-unless-absolute (path? (or/c string? path?) . -> . path?)])) \ No newline at end of file diff --git a/collects/web-server/web-cells.ss b/collects/web-server/web-cells.ss index 6fc6accb2d..84c433d8a3 100644 --- a/collects/web-server/web-cells.ss +++ b/collects/web-server/web-cells.ss @@ -1,25 +1,25 @@ (module web-cells mzscheme - (require (lib "struct.ss")) - + (require (lib "struct.ss") + (lib "contract.ss")) + (define-struct (exn:fail:frame:top exn) ()) (define (exn:fail:frame:top-raise) (raise (make-exn:fail:frame:top "Reached top of stack" (current-continuation-marks)))) - (provide exn:fail:frame:top?) ;; frames (define-struct frame ()) (define-struct (frame:empty frame) ()) ; frame:ns : (alist * (box frame) * namespace) (define-struct (frame:ns frame) (annotations boxed-parent namespace)) - + ; frame:ns?/raise : frame -> frame (define (frame:ns?/raise f) (if (frame:ns? f) f (exn:fail:frame:top-raise))) - + ; make-frame/parent : (box frame) -> frame:ns (define (make-frame/parent parent-frame-box) (make-frame:ns (list) parent-frame-box (make-namespace 'empty))) @@ -32,7 +32,7 @@ (search-frames (frame:ns?/raise (unbox (frame:ns-boxed-parent a-frame))) predicate?))) - + ; frame-ref : frame:ns symbol -> any ; Lookups up the variable in the frame and its parent(s) (define (frame-ref a-frame var) @@ -47,12 +47,12 @@ ; frame-set? : frame:ns symbol -> boolean (define (frame-set? a-frame var) - (not - (not - (namespace-variable-value - var #f - (lambda () #f) - (frame:ns-namespace a-frame))))) + (not + (not + (namespace-variable-value + var #f + (lambda () #f) + (frame:ns-namespace a-frame))))) ; frame-set! : frame:ns symbol any -> void ; Sets the variable in the frame to a value @@ -60,12 +60,10 @@ (namespace-set-variable-value! var val #t (frame:ns-namespace a-frame))) - - ;; frame stacks + ;; frame stacks (define *global-root-id* (gensym)) - (define *session-root-id* (gensym)) - + ; *frame-stack* : (box frame) (define *frame-stack* (make-parameter @@ -79,33 +77,18 @@ ; global-root? : frame:ns -> boolean (define (global-root? a-frame) (annotation-present? *global-root-id* a-frame)) - - ; session-root? : frame:ns -> boolean - (define (session-root? a-frame) - (annotation-present? *session-root-id* a-frame)) - + ; make-frame/top : -> frame:ns (define (make-frame/top) - (let* ([cur-top-box (*frame-stack*)] - [cur-top (unbox cur-top-box)]) - (cond - #;[(not (frame:ns? cur-top)) - ; Construct global - (copy-struct frame:ns (make-frame/parent cur-top-box) - [frame:ns-annotations (list (cons *global-root-id* #t))])] - [(global-root? cur-top) - ; Construct session - (copy-struct frame:ns (make-frame/parent cur-top-box) - [frame:ns-annotations (list (cons *session-root-id* #t))])] - [else - ; Construct normal - (make-frame/parent cur-top-box)]))) + (define cur-top-box (*frame-stack*)) + (define cur-top (unbox cur-top-box)) + (make-frame/parent cur-top-box)) ; push-frame! : -> void ; Pushs a new frame onto the session stack (define (push-frame!) (*frame-stack* (box (make-frame/top)))) - + ; pop-frame! : -> void ; Pops the frame from the stack (define (pop-frame!) @@ -114,10 +97,10 @@ ; save-stack/push/return : (-> 'a) -> 'a ; Pushes a frame after the thunk's execution with the same parent as the call site (define (save-stack/push/return thunk) - (let ([initial-stack (*frame-stack*)]) - (begin0 (thunk) - (*frame-stack* initial-stack) - (push-frame!)))) + (define initial-stack (*frame-stack*)) + (begin0 (thunk) + (*frame-stack* initial-stack) + (push-frame!))) ; syntax version of above (define-syntax with-frame-after @@ -143,106 +126,42 @@ ; cells (define-struct cell (id)) - (define-struct (cell:global cell) ()) - (define-struct (cell:session cell) ()) (define-struct (cell:local cell) ()) + (define web-cell:local? cell:local?) + ; ext:make-'a 'b -> 'a - (define (ext:make-cell:global default) - (let ([new-name (gensym)]) - (frame-set! (search-stack global-root?) - new-name default) - (make-cell:global new-name))) - (define (ext:make-cell:session default) - (let ([new-name (gensym)]) - (frame-set! (search-stack global-root?) - new-name default) - (make-cell:session new-name))) - (define (ext:make-cell:local default) - (let ([new-name (gensym)]) - (frame-set! (search-stack global-root?) - new-name default) - (make-cell:local new-name))) - - ; cell:global-ref : cell:global -> any - ; returns the value of the global cell - (define (cell:global-ref gc) - (frame-ref (search-stack global-root?) - (cell-id gc))) - ; cell:global-set! : cell:global any -> void - ; sets the value of the global cell - (define (cell:global-set! gc nv) + (define (make-web-cell:local default) + (define new-name (gensym)) (frame-set! (search-stack global-root?) - (cell-id gc) - nv)) - - ; cell:session-ref : cell:session -> any - ; returns the value of the session cell - (define (cell:session-ref sc) - (frame-ref (search-stack session-root?) - (cell-id sc))) - ; cell:session-set! : cell:session any -> void - ; sets the value of the session cell - (define (cell:session-set! sc nv) - (frame-set! (search-stack session-root?) - (cell-id sc) - nv)) - + new-name default) + (make-cell:local new-name)) + ; cell:local-ref : cell:local -> any ; returns the value of the local cell - (define (cell:local-ref lc) + (define (web-cell:local-ref lc) (frame-ref (search-stack frame?) (cell-id lc))) ; cell:local-set! : cell:local any -> void ; sets the value of the local cell at the last place it was set, including the default - (define (cell:local-set! lc nv) + (define (web-cell:local-set! lc nv) (frame-set! (search-stack (lambda (f) (frame-set? f (cell-id lc)))) (cell-id lc) nv)) ; cell:local-mask : cell:local any -> void ; masks the local cell to the given value - (define (cell:local-mask lc nv) + (define (web-cell:local-mask lc nv) (frame-set! (search-stack frame?) (cell-id lc) nv)) - - ; cell-ref : cell -> any - (define (cell-ref c) - (cond - [(cell:global? c) (cell:global-ref c)] - [(cell:session? c) (cell:session-ref c)] - [(cell:local? c) (cell:local-ref c)])) - -; ;; linking parameters to cells -; (define *parameter-links* (ext:make-cell:session (list))) -; (define-struct parameter-link (parameter cell)) -; -; ; link-parameter : parameter cell -> void -; (define (link-parameter p c) -; (cell:session-set! *parameter-links* -; (cons (make-parameter-link p c) -; (cell:session-ref *parameter-links*)))) -; -; ; reinstall-linked-parameters : -> void -; (define (reinstall-linked-parameters) -; (for-each (lambda (link) -; ((parameter-link-parameter link) -; (cell-ref (parameter-link-cell link)))) -; (cell:session-ref *parameter-links*))) - - (provide with-frame - with-frame-after - (rename cell:global? web-cell:global?) - (rename ext:make-cell:global make-web-cell:global) - (rename cell:global-ref web-cell:global-ref) - (rename cell:global-set! web-cell:global-set!) - (rename cell:session? web-cell:session?) - (rename ext:make-cell:session make-web-cell:session) - (rename cell:session-ref web-cell:session-ref) - (rename cell:session-set! web-cell:session-set!) - (rename cell:local? web-cell:local?) - (rename ext:make-cell:local make-web-cell:local) - (rename cell:local-ref web-cell:local-ref) - (rename cell:local-set! web-cell:local-set!) - (rename cell:local-mask web-cell:local-mask))) \ No newline at end of file + + (provide with-frame ; syntax + with-frame-after) + (provide/contract + [exn:fail:frame:top? (any/c . -> . boolean?)] + [web-cell:local? (any/c . -> . boolean?)] + [make-web-cell:local (any/c . -> . web-cell:local?)] + [web-cell:local-ref (web-cell:local? . -> . any/c)] + [web-cell:local-set! (web-cell:local? any/c . -> . void)] + [web-cell:local-mask (web-cell:local? any/c . -> . void)])) \ No newline at end of file diff --git a/collects/web-server/web-server-structs.ss b/collects/web-server/web-server-structs.ss index 64939d7ca8..61f9526e23 100644 --- a/collects/web-server/web-server-structs.ss +++ b/collects/web-server/web-server-structs.ss @@ -1,9 +1,14 @@ (module web-server-structs mzscheme - (provide (all-defined)) + (require (lib "contract.ss")) + (require "contract.ss") (define current-server-custodian (make-parameter #f)) + (provide current-server-custodian) ; parameter ;; make-servlet-custodian: -> custodian ;; create a custodian for the dynamic extent of a servlet continuation (define (make-servlet-custodian) - (make-custodian (current-server-custodian)))) \ No newline at end of file + (make-custodian (current-server-custodian))) + + (provide/contract + [make-servlet-custodian (-> custodian?)])) \ No newline at end of file diff --git a/collects/web-server/web-server-unit.ss b/collects/web-server/web-server-unit.ss index 71f298b20f..36e575c253 100644 --- a/collects/web-server/web-server-unit.ss +++ b/collects/web-server/web-server-unit.ss @@ -1,9 +1,12 @@ (module web-server-unit mzscheme + (require (lib "tcp-sig.ss" "net") + (lib "contract.ss") + (lib "unitsig.ss")) (require "sig.ss" + "dispatch-server-unit.ss" + "dispatch-server-sig.ss" "web-server-structs.ss" - "connection-manager.ss" "configuration-structures.ss" - "servlet.ss" "private/cache-table.ss" (rename "private/request.ss" the-read-request read-request)) @@ -13,107 +16,11 @@ (prefix servlets: "dispatchers/dispatch-servlets.ss") (prefix path-procedure: "dispatchers/dispatch-pathprocedure.ss") (prefix log: "dispatchers/dispatch-log.ss") - (prefix host: "dispatchers/dispatch-host.ss")) - (require (lib "tcp-sig.ss" "net") - (lib "unitsig.ss") - (lib "string.ss") - (lib "list.ss") - (lib "url.ss" "net")) - - (provide web-server@) - - ;; **************************************** - (define dispatch-server@ - (unit/sig dispatch-server^ - (import net:tcp^ (config : dispatch-server-config^)) - - ;; serve: -> -> void - ;; start the server and return a thunk to shut it down - (define (serve) - (define the-server-custodian (make-custodian)) - (start-connection-manager the-server-custodian) - (parameterize ([current-custodian the-server-custodian] - [current-server-custodian the-server-custodian] - [current-thread-initial-stack-size 3]) - (thread - (lambda () - (start-listener)))) - (lambda () - (custodian-shutdown-all the-server-custodian))) - - ;; start-listener : -> void - ;; loops around starting a listener if the current listener dies - (define (start-listener) - (define listener - (tcp-listen config:port config:max-waiting - #t config:listen-ip)) - (define get-ports - (lambda () (tcp-accept listener))) - (with-handlers ([void (lambda (e) - ; If the exception did not kill the listener - (with-handlers ([void void]) - (tcp-close listener)) - ; Rethrow the error to this thread's error printer - (raise e))]) - (server-loop get-ports - tcp-addresses))) - - ;; server-loop: (-> input-port output-port) (input-port -> string string) -> void - ;; start a thread to handle each incoming connection - (define (server-loop get-ports port-addresses) - (let loop () - (define connection-cust (make-custodian)) - (parameterize ([current-custodian connection-cust]) - (define-values (ip op) (get-ports)) - (serve-ports/inner ip op - port-addresses)) - (loop))) - - ;; serve-ports : input-port output-port -> void - ;; returns immediately, spawning a thread to handle - ;; the connection - ;; NOTE: (GregP) should allow the user to pass in a connection-custodian - (define (serve-ports ip op) - (define server-cust (make-custodian)) - (start-connection-manager server-cust) - (parameterize ([current-custodian server-cust] - [current-server-custodian server-cust]) - (define connection-cust (make-custodian)) - (parameterize ([current-custodian connection-cust]) - (serve-ports/inner ip op - (lambda (ip) - (values "127.0.0.1" - "127.0.0.1")))))) - - ;; serve-ports/inner : input-port output-port (input-port -> string string) -> void - ;; returns immediately, spawning a thread to handle - (define (serve-ports/inner ip op port-addresses) - (thread - (lambda () - (define conn - (new-connection config:initial-connection-timeout - ip op (current-custodian) #f)) - (with-handlers ([exn:fail:network? - (lambda (e) - (kill-connection! conn) - (raise e))]) - (serve-connection conn port-addresses))))) - - ;; serve-connection: connection (input-port -> string string) -> void - ;; respond to all requests on this connection - (define (serve-connection conn port-addresses) - (let connection-loop () - (define-values (req close?) (config:read-request conn config:port port-addresses)) - (unless close? - (set-connection-close?! conn #f)) - (adjust-connection-timeout! conn config:initial-connection-timeout) - (config:dispatch conn req) - (when close? - (set-connection-close?! conn #t)) - (cond - [(connection-close? conn) (kill-connection! conn)] - [else (connection-loop)]))))) - + (prefix host: "dispatchers/dispatch-host.ss")) + (provide/contract + ; XXX contract + [web-server@ unit/sig?]) + (define web-config@->dispatch-server-config@ (unit/sig dispatch-server-config^ (import (config : web-config^)) diff --git a/collects/web-server/web-server.ss b/collects/web-server/web-server.ss index 6ac4b335d3..6d4133e09e 100644 --- a/collects/web-server/web-server.ss +++ b/collects/web-server/web-server.ss @@ -1,10 +1,15 @@ (module web-server mzscheme (require (lib "tcp-sig.ss" "net") (lib "unitsig.ss") + (lib "contract.ss") "sig.ss" "web-server-unit.ss" - "configuration.ss") - (provide serve) + "configuration.ss" + "configuration-structures.ss") + (provide/contract + [serve (case-> [configuration? . -> . (-> void?)] + [configuration? natural-number/c . -> . (-> void?)] + [configuration? natural-number/c string? . -> . (-> void?)])]) ; : configuration [nat] [(U str #f)] -> -> void (define serve @@ -29,6 +34,4 @@ (serve)) s)]) (export)) - net:tcp^)) - -) \ No newline at end of file + net:tcp^))) \ No newline at end of file diff --git a/collects/web-server/xexpr-callback.ss b/collects/web-server/xexpr-callback.ss deleted file mode 100644 index 8f32b7182d..0000000000 --- a/collects/web-server/xexpr-callback.ss +++ /dev/null @@ -1,17 +0,0 @@ -;; Mike Burns 2004 - -;; Used for send/suspend/callback. - -(module xexpr-callback mzscheme - (require (lib "xml.ss" "xml")) - (provide xexpr/callback?) - - ;; Is it a Xexpr, or an Xexpr with procedures? - (define (xexpr/callback? x) - (correct-xexpr? x - (lambda () #t) - (lambda (exn) - (if (procedure? (exn:invalid-xexpr-code exn)) - #t - (begin ((error-display-handler) (exn-message exn) exn) - #f))))))