diff --git a/collects/tests/web-server/servlet/helpers-test.ss b/collects/tests/web-server/servlet/helpers-test.ss index 44c1428d62..0d8f67c00d 100644 --- a/collects/tests/web-server/servlet/helpers-test.ss +++ b/collects/tests/web-server/servlet/helpers-test.ss @@ -1,7 +1,6 @@ #lang scheme/base (require (planet "test.ss" ("schematics" "schemeunit.plt" 2)) - web-server/http - web-server/servlet/helpers) + web-server/servlet) (provide helpers-tests) (define (dehead hs) diff --git a/collects/web-server/lang/lang-api.ss b/collects/web-server/lang/lang-api.ss index c97d075743..6a301544b0 100644 --- a/collects/web-server/lang/lang-api.ss +++ b/collects/web-server/lang/lang-api.ss @@ -1,18 +1,16 @@ #lang scheme (require net/url web-server/http - "abort-resume.ss" - "web.ss" - "web-cells.ss" - "web-param.ss" - "file-box.ss" - "web-extras.ss") + web-server/lang/abort-resume + web-server/lang/web + web-server/lang/web-cells + web-server/lang/web-param + web-server/lang/file-box) (provide (except-out (all-from-out scheme) #%module-begin) (all-from-out net/url web-server/http - "abort-resume.ss" - "web.ss" - "web-cells.ss" - "web-param.ss" - "file-box.ss" - "web-extras.ss")) + web-server/lang/abort-resume + web-server/lang/web + web-server/lang/web-cells + web-server/lang/web-param + web-server/lang/file-box)) diff --git a/collects/web-server/lang/web-extras.ss b/collects/web-server/lang/web-extras.ss deleted file mode 100644 index 1c16778323..0000000000 --- a/collects/web-server/lang/web-extras.ss +++ /dev/null @@ -1,10 +0,0 @@ -#lang scheme/base -(require net/url - scheme/contract - "web.ss" - web-server/http) -(provide/contract - [redirect/get (-> request?)]) - -(define (redirect/get) - (send/suspend/url (lambda (k-url) (redirect-to (url->string k-url) temporarily)))) diff --git a/collects/web-server/lang/web.ss b/collects/web-server/lang/web.ss index cdd9e22b62..92af75a734 100644 --- a/collects/web-server/lang/web.ss +++ b/collects/web-server/lang/web.ss @@ -85,3 +85,9 @@ [(struct binding:form (id kont)) (deserialize (read (open-input-bytes kont)))] [_ #f]))) + +(provide/contract + [redirect/get (-> request?)]) + +(define (redirect/get) + (send/suspend/url (lambda (k-url) (redirect-to (url->string k-url) temporarily)))) diff --git a/collects/web-server/scribblings/configuration.scrbl b/collects/web-server/scribblings/configuration.scrbl index 2b78de0d17..ea9dd0356d 100644 --- a/collects/web-server/scribblings/configuration.scrbl +++ b/collects/web-server/scribblings/configuration.scrbl @@ -13,7 +13,7 @@ configuring the @web-server . @section[#:tag "configuration-table-structs.ss"]{Configuration Table Structure} @(require (for-label web-server/configuration/configuration-table-structs)) -@defmodule[web-server/configuration/configuration-table-structs] +@defmodule[web-server/configuration/configuration-table-structs]{ @filepath{configuration/configuration-table-structs.ss} provides the following structures that represent a standard configuration (see @secref["web-server-unit.ss"]) of the @web-server . @@ -79,11 +79,14 @@ the configuration table S-expression file format described in [mime-types (or/c false/c path-string?)] [passwords (or/c false/c path-string?)])] +} + @; ------------------------------------------------------------ @section[#:tag "configuration-table.ss"]{Configuration Table} @(require (for-label web-server/configuration/configuration-table)) +@(require (for-label web-server/dispatchers/dispatch-log)) -@defmodule[web-server/configuration/configuration-table] +@defmodule[web-server/configuration/configuration-table]{ @filepath{configuration/configuration-table.ss} provides functions for reading, writing, parsing, and printing @scheme[configuration-table] @@ -147,8 +150,6 @@ where a @scheme[host-table-sexpr] is: In this syntax, the @scheme['messages] paths are relative to the @scheme['configuration-root] directory. All the paths in @scheme['paths] are relative to @scheme['host-root] (other than @scheme['host-root] obviously.) -@(require (for-label web-server/dispatchers/dispatch-log)) - Allowable @scheme['log-format]s are those accepted by @scheme[log-format->format]. Note: You almost always want to leave everything in the @scheme['paths] section the default except the @scheme['host-root]. @@ -162,12 +163,14 @@ This function reads a @scheme[configuration-table] from @scheme[path]. void]{ This function writes a @scheme[configuration-table] to @scheme[path]. } + +} @; ------------------------------------------------------------ @section[#:tag "namespace.ss"]{Servlet Namespaces} @(require (for-label web-server/configuration/namespace)) -@defmodule[web-server/configuration/namespace] +@defmodule[web-server/configuration/namespace]{ @filepath{configuration/namespace.ss} provides a function to help create the @scheme[make-servlet-namespace] procedure needed by the @scheme[make] functions @@ -195,6 +198,8 @@ Example: #:to-be-copied-module-specs `((lib "database.ss" "my-module"))) ] } + +} @subsection{Why this is useful} @@ -215,7 +220,7 @@ of servlets can share different sets of modules. @section[#:tag "responders.ss"]{Standard Responders} @(require (for-label web-server/configuration/responders)) -@defmodule[web-server/configuration/responders] +@defmodule[web-server/configuration/responders]{ @filepath{configuration/responders.ss} provides some functions that help constructing HTTP responders. These functions are used by the default dispatcher constructor (see @secref["web-server-unit.ss"]) to @@ -278,3 +283,5 @@ the @scheme[header]s as, you guessed it, headers. (-> response?)]{ Returns a function that generates a standard "Garbage collection run" message with content from @scheme[file]. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/dispatchers.scrbl b/collects/web-server/scribblings/dispatchers.scrbl index d051cf1509..0d07bf4c98 100644 --- a/collects/web-server/scribblings/dispatchers.scrbl +++ b/collects/web-server/scribblings/dispatchers.scrbl @@ -34,7 +34,7 @@ documentation will be useful. @section[#:tag "dispatch.ss"]{General} @(require (for-label web-server/dispatchers/dispatch)) -@defmodule[web-server/dispatchers/dispatch] +@defmodule[web-server/dispatchers/dispatch]{ @filepath{dispatchers/dispatch.ss} provides a few functions for dispatchers in general. @@ -75,11 +75,13 @@ Consider the following example dispatcher, that captures the essence of URL rewr [request-uri (rule (request-uri req))])))) ] +} + @; ------------------------------------------------------------ @section[#:tag "filesystem-map.ss"]{Mapping URLs to Paths} @(require (for-label web-server/dispatchers/filesystem-map)) -@defmodule[web-server/dispatchers/filesystem-map] +@defmodule[web-server/dispatchers/filesystem-map]{ @filepath{dispatchers/filesystem-map.ss} provides a means of mapping URLs to paths on the filesystem. @@ -114,6 +116,8 @@ URLs to paths on the filesystem. servlets when using the servlet dispatchers. It will return a @scheme[exn:fail:filesystem:exists?] exception if the path does not match. } + +} @; ------------------------------------------------------------ @section[#:tag "dispatch-sequencer.ss"]{Sequencing} diff --git a/collects/web-server/scribblings/dummy-language-servlet.ss b/collects/web-server/scribblings/dummy-stateless-servlet.ss similarity index 69% rename from collects/web-server/scribblings/dummy-language-servlet.ss rename to collects/web-server/scribblings/dummy-stateless-servlet.ss index 95ce4bd630..dff242b2ab 100644 --- a/collects/web-server/scribblings/dummy-language-servlet.ss +++ b/collects/web-server/scribblings/dummy-stateless-servlet.ss @@ -1,5 +1,6 @@ #lang scheme/base +(define interface-version #f) (define start #f) (provide (all-defined-out)) diff --git a/collects/web-server/scribblings/dummy-servlet.ss b/collects/web-server/scribblings/dummy-v1-servlet.ss similarity index 85% rename from collects/web-server/scribblings/dummy-servlet.ss rename to collects/web-server/scribblings/dummy-v1-servlet.ss index f4e3347977..c531e268e9 100644 --- a/collects/web-server/scribblings/dummy-servlet.ss +++ b/collects/web-server/scribblings/dummy-v1-servlet.ss @@ -3,7 +3,6 @@ (define interface-version #f) (define timeout #f) (define start #f) -(define manager #f) (provide (all-defined-out)) diff --git a/collects/web-server/scribblings/dummy-v2-servlet.ss b/collects/web-server/scribblings/dummy-v2-servlet.ss new file mode 100644 index 0000000000..37ca879cd1 --- /dev/null +++ b/collects/web-server/scribblings/dummy-v2-servlet.ss @@ -0,0 +1,8 @@ +#lang scheme/base + +(define interface-version #f) +(define start #f) +(define manager #f) + +(provide (all-defined-out)) + diff --git a/collects/web-server/scribblings/extending.scrbl b/collects/web-server/scribblings/extending.scrbl new file mode 100644 index 0000000000..5f22a74928 --- /dev/null +++ b/collects/web-server/scribblings/extending.scrbl @@ -0,0 +1,16 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:style 'toc]{Extending the Web Server} + +@local-table-of-contents[] + +@include-section["configuration.scrbl"] + +@include-section["servlet-setup.scrbl"] + +@include-section["dispatchers.scrbl"] + +@include-section["web-config-unit.scrbl"] +@include-section["web-server-unit.scrbl"] +@include-section["private.scrbl"] diff --git a/collects/web-server/scribblings/formlets.scrbl b/collects/web-server/scribblings/formlets.scrbl index 839d6d148e..07337d67df 100644 --- a/collects/web-server/scribblings/formlets.scrbl +++ b/collects/web-server/scribblings/formlets.scrbl @@ -100,7 +100,7 @@ The rest of the manual gives the details of @tech{formlet} usage and extension. @section{Syntactic Shorthand} @(require (for-label web-server/formlets/syntax)) -@defmodule[web-server/formlets/syntax] +@defmodule[web-server/formlets/syntax]{ Most users will want to use the syntactic shorthand for creating @tech{formlet}s. @@ -116,10 +116,12 @@ Most users will want to use the syntactic shorthand for creating @tech{formlet}s @scheme[(#%# _xexpr ...)] renders an @xexpr forest. } +} + @section{Functional Usage} @(require (for-label web-server/formlets/lib)) -@defmodule[web-server/formlets/lib] +@defmodule[web-server/formlets/lib]{ The syntactic shorthand abbreviates the construction of @deftech{formlet}s with the following library. These combinators may be used directly to construct low-level formlets, such as those for new INPUT element @@ -191,11 +193,13 @@ types. Refer to @secref["input-formlets"] for example low-level formlets using t any/c]{ Runs the processing stage of @scheme[f] on the bindings in @scheme[r]. } + +} @section[#:tag "input-formlets"]{Predefined Formlets} @(require (for-label web-server/formlets/input)) -@defmodule[web-server/formlets/input] +@defmodule[web-server/formlets/input]{ There are a few basic @tech{formlet}s provided by this library. @@ -213,10 +217,12 @@ There are a few basic @tech{formlet}s provided by this library. Equivalent to @scheme[(cross (pure string->symbol) input-string)]. } +} + @section{Utilities} @(require (for-label web-server/formlets/servlet)) -@defmodule[web-server/formlets/servlet] +@defmodule[web-server/formlets/servlet]{ A few utilities are provided for using @tech{formlet}s in Web applications. @@ -232,3 +238,5 @@ A few utilities are provided for using @tech{formlet}s in Web applications. xexpr?]{ Like @scheme[send/formlet], but for use with @scheme[send/suspend/dispatch]. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/http.scrbl b/collects/web-server/scribblings/http.scrbl index f7cd419972..2dcf19e8e3 100644 --- a/collects/web-server/scribblings/http.scrbl +++ b/collects/web-server/scribblings/http.scrbl @@ -14,7 +14,7 @@ The @web-server implements many HTTP RFCs that are provided by this module. @section[#:tag "request-structs.ss"]{Requests} @(require (for-label web-server/http/request-structs)) -@defmodule[web-server/http/request-structs] +@defmodule[web-server/http/request-structs]{ @defstruct[header ([field bytes?] [value bytes?])]{ @@ -82,11 +82,13 @@ Here is an example typical of what you will find in many applications: (get-number (request-number))])) ] +} + @; ------------------------------------------------------------ @section[#:tag "bindings.ss"]{Bindings} @(require (for-label web-server/http/bindings)) -@defmodule[web-server/http/bindings] +@defmodule[web-server/http/bindings]{ These functions, while convenient, could introduce subtle bugs into your application. Examples: that they are case-insensitive could introduce @@ -142,11 +144,13 @@ Here is an example typical of what you will find in many applications: (request-bindings req)))) ] +} + @; ------------------------------------------------------------ @section[#:tag "response-structs.ss"]{Responses} @(require (for-label web-server/http/response-structs)) -@defmodule[web-server/http/response-structs] +@defmodule[web-server/http/response-structs]{ @defstruct[response/basic ([code number?] @@ -225,12 +229,13 @@ Here is an example typical of what you will find in many applications: @warning{If you include a Content-Length header in a response that is inaccurate, there @bold{will be an error} in transmission that the server @bold{will not catch}.} - +} + @; ------------------------------------------------------------ @section[#:tag "redirect.ss"]{Redirect} @(require (for-label web-server/http/redirect)) -@defmodule[web-server/http/redirect] +@defmodule[web-server/http/redirect]{ @defproc[(redirect-to [uri string?] [perm/temp redirection-status? temporarily] @@ -254,11 +259,13 @@ transmission that the server @bold{will not catch}.} @defthing[see-other redirection-status?]{A @scheme[redirection-status?] for "see-other" redirections.} +} + @; ------------------------------------------------------------ @section[#:tag "basic-auth.ss"]{Basic Authentication} @(require (for-label web-server/http/basic-auth)) -@defmodule[web-server/http/basic-auth] +@defmodule[web-server/http/basic-auth]{ An implementation of HTTP Basic Authentication. @@ -270,3 +277,5 @@ An implementation of HTTP Basic Authentication. Example: @scheme[(extract-user-pass (request-headers/raw req))] might return @scheme[(cons #"aladin" #"open sesame")]. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/lang-web-cells.scrbl b/collects/web-server/scribblings/lang-web-cells.scrbl new file mode 100644 index 0000000000..ba4017ed20 --- /dev/null +++ b/collects/web-server/scribblings/lang-web-cells.scrbl @@ -0,0 +1,27 @@ +#lang scribble/doc +@(require "web-server.ss") + +@; ------------------------------------------------------------ +@title[#:tag "lang/web-cells.ss"]{Stateless Web Cells} +@(require (for-label web-server/lang/web-cells)) + +@defmodule[web-server/lang/web-cells]{The +@schememodname[web-server/lang/web-cells] library provides the same +API as @schememodname[web-server/servlet/web-cells], but in a way +compatible with the Web Language. The one difference is that +@scheme[make-web-cell] is syntax, rather than a function. + +@deftogether[( +@defproc[(web-cell? [v any/c]) + boolean?] +@defform[(make-web-cell default-expr)] +@defproc[(web-cell-ref [wc web-cell?]) + any/c] +@defproc[(web-cell-shadow [wc web-cell?] + [v any/c]) + void] +)]{ + +See @schememodname[web-server/servlet/web-cells].} + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/lang.scrbl b/collects/web-server/scribblings/lang.scrbl index 147ea263e5..b981b02179 100644 --- a/collects/web-server/scribblings/lang.scrbl +++ b/collects/web-server/scribblings/lang.scrbl @@ -1,98 +1,20 @@ #lang scribble/doc @(require "web-server.ss") -@title[#:tag "lang" - #:style 'toc]{Web Language} +@title[#:tag "lang/web.ss"]{Stateless Web Interaction} -@defmodulelang[web-server] - -The @web-server allows servlets to be written in a special Web -language that is nearly identical to Scheme. Herein we discuss how it -is different and what API is provided. +@(require (for-label web-server/lang/abort-resume)) +@defmodule[web-server/lang/abort-resume]{ -@local-table-of-contents[] +@defproc[(send/suspend [response-generator (continuation? . -> . any)]) + any]{ + Captures the current continuation in a serializable way and calls @scheme[response-generator] with it, returning the result. +} + +} -@; ------------------------------------------------------------ -@section[#:tag "considerations"]{Usage Considerations} - -A servlet has the following process performed on it automatically: -@itemize[ - @item{All uses of @scheme[letrec] are removed and replaced with equivalent uses of - @scheme[let] and imperative features. (@filepath{lang/elim-letrec.ss})} - @item{The program is converted into ANF (Administrative Normal Form), - making all continuations explicit. (@filepath{lang/anormal.ss})} - @item{All continuations (and other continuations marks) are recorded in the - continuation marks of the expression - they are the continuation of. (@filepath{lang/elim-callcc.ss})} - @item{All calls to external modules are identified and marked. - (@filepath{lang/elim-callcc.ss})} - @item{All uses of @scheme[call/cc] are removed and replaced with - equivalent gathering of the continuations through the continuation-marks. - (@filepath{lang/elim-callcc.ss})} - @item{The program is defunctionalized with a serializable data-structure for each - anonymous lambda. (@filepath{lang/defun.ss})} -] - -This process allows the continuations captured by your servlet to be serialized. -This means they may be stored on the client's browser or the server's disk. -Thus, your servlet has no cost to the server other than execution. This is -very attractive if you've used Scheme servlets and had memory problems. - -This process IS defined on all of PLT Scheme and occurs AFTER macro-expansion, -so you are free to use all interesting features of PLT Scheme. However, there -are some considerations you must make. - -First, this process drastically changes the structure of your program. It -will create an immense number of lambdas and structures your program -did not normally contain. The performance implication of this has not been -studied with PLT Scheme. However, it is theoretically a benefit. The main -implications would be due to optimizations MzScheme attempts to perform -that will no longer apply. Ideally, your program should be optimized first. - -Second, the defunctionalization process is sensitive to the syntactic structure -of your program. Therefore, if you change your program in a trivial way, for example, -changing a constant, then all serialized continuations will be obsolete and will -error when deserialization is attempted. This is a feature, not a bug! - -Third, the values in the lexical scope of your continuations must be serializable -for the continuations itself to be serializable. This means that you must use -@scheme[define-serializable-struct] rather than @scheme[define-struct], and take -care to use modules that do the same. Similarly, you may not use @scheme[parameterize], -because parameterizations are not serializable. - -Fourth, and related, this process only runs on your code, not on the code you -@scheme[require]. Thus, your continuations---to be capturable---must not -be in the context of another module. For example, the following will not work: -@schemeblock[ - (define requests - (map (lambda (rg) (send/suspend/url rg)) - response-generators)) -] -because @scheme[map] is not transformed by the process. However, if you defined -your own @scheme[map] function, there would be no problem. - -Fifth, the store is NOT serialized. If you rely on the store you will -be taking huge risks. You will be assuming that the serialized continuation -is invoked before the server is restarted or the memory is garbage collected. - -This process is derived from the paper -@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/pcmkf-cont-from-gen-stack-insp/" "\"Continuations from Generalized Stack Inspection\""]. -We thank Greg Pettyjohn for his initial implementation of this algorithm. - -@; ------------------------------------------------------------ -@section[#:tag "reprovided"]{Reprovided API} - -The APIs from @scheme[net/url], @secref["request-structs.ss"], -@secref["response-structs.ss"], and @secref["helpers.ss"] are reprovided -by the Web language API. - -@; ------------------------------------------------------------ -@section[#:tag "lang/web.ss"]{Web} @(require (for-label web-server/lang/web)) - -@defmodule[web-server/lang/web] - -@filepath{lang/web.ss} provides the most basic Web functionality. +@defmodule[web-server/lang/web]{ @defproc[(send/suspend/url [response-generator (url? . -> . response?)]) request?]{ @@ -122,11 +44,18 @@ by the Web language API. @scheme[send/suspend/dispatch]. } +@deftogether[( +@defproc[(redirect/get) request?] +)]{ + +See @schememodname[web-server/servlet/web].} +} + @; ------------------------------------------------------------ @section[#:tag "lang/stuff-url.ss"]{Stuff URL} @(require (for-label web-server/lang/stuff-url)) -@defmodule[web-server/lang/stuff-url] +@defmodule[web-server/lang/stuff-url]{ @filepath{lang/stuff-url.ss} provides an interface for "stuffing" serializable values into URLs. Currently there is a particular @@ -164,112 +93,4 @@ In the future, we will offer the facilities to: @item{Encrypt the serialized value.} @item{Only use the CAS if the URL would be too long. (URLs may only be 1024 characters.)} ] - -@; ------------------------------------------------------------ -@section[#:tag "lang/web-extras.ss"]{Web Extras} -@(require (for-label web-server/lang/web-extras)) - -@defmodule[web-server/lang/web-extras]{The -@schememodname[web-server/lang/web-extras] library provides -@scheme[redirect/get] as -@schememodname[web-server/servlet/web] except it uses -@scheme[send/suspend/url].} - -@deftogether[( -@defproc[(redirect/get) request?] -)]{ - -See @schememodname[web-server/servlet/web].} - -@; ------------------------------------------------------------ -@section[#:tag "lang/file-box.ss"]{File Boxes} -@(require (for-label web-server/lang/file-box)) - -@defmodule[web-server/lang/file-box] - -As mentioned earlier, it is dangerous to rely on the store in -Web Language servlets, due to the deployment scenarios available -to them. @filepath{lang/file-box.ss} provides a simple API to replace -boxes in a safe way. - -@defproc[(file-box? [v any/c]) - boolean?]{Checks if @scheme[v] is a file-box.} - -@defproc[(file-box [p path?] - [v serializable?]) - file-box?]{ - Creates a file-box that is stored at @scheme[p], with the default - contents of @scheme[v]. -} - -@defproc[(file-unbox [fb file-box?]) - serializable?]{ - Returns the value inside @scheme[fb] -} - -@defproc[(file-box-set? [fb file-box?]) - boolean?]{ - Returns @scheme[#t] if @scheme[fb] contains a value. -} - -@defproc[(file-box-set! [fb file-box?] - [v serializable?]) - void]{ - Saves @scheme[v] in the file represented by @scheme[fb]. -} - -@warning{If you plan on using a load-balancer, make sure your file-boxes -are on a shared medium.} - -@; ------------------------------------------------------------ -@section[#:tag "lang/web-param.ss"]{Web Parameters} -@(require (for-label web-server/lang/web-param)) - -@defmodule[web-server/lang/web-param] - -As mentioned earlier, it is not easy to use @scheme[parameterize] in the -Web Language. @filepath{lang/web-param.ss} provides (roughly) the same -functionality in a way that is serializable. Like other serializable -things in the Web Language, they are sensitive to source code modification. - -@defform[(make-web-parameter default)]{ - Expands to the definition of a web-parameter with - @scheme[default] as the default value. A web-parameter is - a procedure that, when called with zero arguments, returns @scheme[default] - or the last value @scheme[web-parameterize]d in the dynamic context - of the call. -} - -@defproc[(web-parameter? [v any/c]) - boolean?]{ - Checks if @scheme[v] appears to be a web-parameter. -} - -@defform[(web-parameterize ([web-parameter-expr value-expr] ...) expr ...)]{ - Runs @scheme[(begin expr ...)] such that the web-parameters that - the @scheme[web-parameter-expr]s evaluate to are bound to the @scheme[value-expr]s. - From the perspective of the @scheme[value-expr]s, this is like @scheme[let]. -} - -@; ------------------------------------------------------------ -@section[#:tag "lang/web-cells.ss"]{Web Cells} -@(require (for-label web-server/lang/web-cells)) - -@defmodule[web-server/lang/web-cells]{The -@schememodname[web-server/lang/web-cells] library provides the same -API as @schememodname[web-server/servlet/web-cells], but in a way -compatible with the Web Language. The one difference is that -@scheme[make-web-cell] is syntax, rather than a function.} - -@deftogether[( -@defproc[(web-cell? [v any/c]) - boolean?] -@defform[(make-web-cell default-expr)] -@defproc[(web-cell-ref [wc web-cell?]) - any/c] -@defproc[(web-cell-shadow [wc web-cell?] - [v any/c]) - void] -)]{ - -See @schememodname[web-server/servlet/web-cells].} +} \ No newline at end of file diff --git a/collects/web-server/scribblings/managers.scrbl b/collects/web-server/scribblings/managers.scrbl index 8ad0a0e31b..24ceb3a4a5 100644 --- a/collects/web-server/scribblings/managers.scrbl +++ b/collects/web-server/scribblings/managers.scrbl @@ -18,7 +18,7 @@ pluggable through the manager interface. @(require (for-label web-server/managers/manager) (for-label web-server/servlet/servlet-structs)) -@defmodule[web-server/managers/manager] +@defmodule[web-server/managers/manager]{ @filepath{managers/manager.ss} defines the manager interface. It is required by the users and implementers of managers. @@ -59,12 +59,14 @@ the users and implementers of managers. This exception should be thrown by a manager when a continuation is looked up that does not exist. } + +} @; ------------------------------------------------------------ @section[#:tag "none.ss"]{No Continuations} @(require (for-label web-server/managers/none)) -@defmodule[web-server/managers/none] +@defmodule[web-server/managers/none]{ @filepath{managers/none.ss} defines a manager constructor: @@ -81,13 +83,15 @@ the users and implementers of managers. } If you are considering using this manager, also consider using the -Web Language. (See @secref["lang"].) +Web Language. (See @secref["stateless-servlets"].) + +} @; ------------------------------------------------------------ @section[#:tag "timeouts.ss"]{Timeouts} @(require (for-label web-server/managers/timeouts)) -@defmodule[web-server/managers/timeouts] +@defmodule[web-server/managers/timeouts]{ @filepath{managers/timeouts.ss} defines a manager constructor: @@ -113,11 +117,13 @@ Web Language. (See @secref["lang"].) This manager has been found to be... problematic... in large-scale deployments of the @web-server . +} + @; ------------------------------------------------------------ @section[#:tag "lru.ss"]{LRU} @(require (for-label web-server/managers/lru)) -@defmodule[web-server/managers/lru] +@defmodule[web-server/managers/lru]{ @filepath{managers/lru.ss} defines a manager constructor: @@ -168,4 +174,5 @@ The recommended usage of this manager is codified as the following function: continuations, until the memory is back under control. If the load stays low, it will still efficiently expire old continuations. } - \ No newline at end of file + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/private.scrbl b/collects/web-server/scribblings/private.scrbl index 2214fc6a7f..80b1b5e166 100644 --- a/collects/web-server/scribblings/private.scrbl +++ b/collects/web-server/scribblings/private.scrbl @@ -14,7 +14,7 @@ Some of these are documented here. @section[#:tag "timer.ss"]{Timers} @(require (for-label web-server/private/timer)) -@defmodule[web-server/private/timer] +@defmodule[web-server/private/timer]{ @filepath{private/timer.ss} provides a functionality for running procedures after a given amount of time, that may be extended. @@ -55,12 +55,13 @@ procedures after a given amount of time, that may be extended. Cancels the firing of @scheme[t] ever and frees resources used by @scheme[t]. } +} @; ------------------------------------------------------------ @section[#:tag "connection-manager.ss"]{Connection Manager} @(require (for-label web-server/private/connection-manager)) -@defmodule[web-server/private/connection-manager] +@defmodule[web-server/private/connection-manager]{ @filepath{private/connection-manager.ss} provides functionality for managing pairs of input and output ports. We have plans to allow a number of different strategies @@ -102,6 +103,8 @@ for doing this. void]{ Calls @scheme[reset-timer!] with the timer behind @scheme[c] with @scheme[t]. } + +} @; ------------------------------------------------------------ @section[#:tag "dispatch-server-unit.ss"]{Dispatching Server} @@ -114,7 +117,7 @@ This dispatching server component is useful on its own. @subsection{Dispatching Server Signatures} -@defmodule[web-server/private/dispatch-server-sig] +@defmodule[web-server/private/dispatch-server-sig]{ The @schememodname[web-server/private/dispatch-server-sig] library provides two signatures. @@ -152,10 +155,11 @@ The @scheme[dispatch-server^] signature is an alias for @defthing[dispatch dispatcher?]{How to handle requests.} } +} @subsection{Dispatching Server Unit} -@defmodule[web-server/private/dispatch-server-unit] +@defmodule[web-server/private/dispatch-server-unit]{ The @schememodname[web-server/private/dispatch-server-unit] module provides the unit that actually implements a dispatching server. @@ -166,6 +170,8 @@ provides the unit that actually implements a dispatching server. @secref["connection-manager.ss"] to manage connections. } +} + @; ------------------------------------------------------------ @section[#:tag "closure.ss"]{Serializable Closures} @(require (for-label web-server/private/closure) @@ -173,7 +179,7 @@ provides the unit that actually implements a dispatching server. @defmodule[web-server/private/closure]{ -The defunctionalization process of the Web Language (see @secref["lang"]) +The defunctionalization process of the Web Language (see @secref["stateless-servlets"]) requires an explicit representation of closures that is serializable. @filepath{private/closure.ss} is this representation. It provides: @@ -239,7 +245,7 @@ Here is an example: @section[#:tag "cache-table.ss"]{Cache Table} @(require (for-label web-server/private/cache-table)) -@defmodule[web-server/private/cache-table] +@defmodule[web-server/private/cache-table]{ @filepath{private/cache-table.ss} provides a set of caching hash table functions. @@ -267,11 +273,13 @@ functions. Determines if @scheme[v] is a cache table. } +} + @; ------------------------------------------------------------ @section[#:tag "mime-types.ss"]{MIME Types} @(require (for-label web-server/private/mime-types)) -@defmodule[web-server/private/mime-types] +@defmodule[web-server/private/mime-types]{ @filepath{private/mime-types.ss} provides function for dealing with @filepath{mime.types} files. @@ -287,12 +295,14 @@ files. Uses a @scheme[read-mime-types] with @scheme[p] and constructs a function from paths to their MIME type. } + +} @; ------------------------------------------------------------ @section[#:tag "mod-map.ss"]{Serialization Utilities} @(require (for-label web-server/private/mod-map)) -@defmodule[web-server/private/mod-map] +@defmodule[web-server/private/mod-map]{ The @schememodname[scheme/serialize] library provides the functionality of serializing values. @filepath{private/mod-map.ss} @@ -309,12 +319,14 @@ compresses the serialized representation. Expands multiple occurrences of the same module in the module map of the compressed serialized representation, @scheme[csv]. } + +} @; ------------------------------------------------------------ @section[#:tag "url-param.ss"]{URL Param} @(require (for-label web-server/private/url-param)) -@defmodule[web-server/private/url-param] +@defmodule[web-server/private/url-param]{ The @web-server needs to encode information in URLs. If this data is stored in the query string, than it will be overridden by browsers that @@ -337,6 +349,8 @@ with this process. @scheme[u], if there is one, returning @scheme[#f] otherwise. } +} + @; ------------------------------------------------------------ @section[#:tag "util.ss"]{Miscellaneous Utilities} @(require (for-label web-server/private/util)) diff --git a/collects/web-server/scribblings/running.scrbl b/collects/web-server/scribblings/running.scrbl index 5dc58db836..d86c77fcb1 100644 --- a/collects/web-server/scribblings/running.scrbl +++ b/collects/web-server/scribblings/running.scrbl @@ -34,7 +34,7 @@ You are given the entire @schememodname[web-server/servlet] API. @subsection{Customization API} -@defmodule[web-server/insta/insta] +@defmodule[web-server/insta/insta] { The following API is provided to customize the server instance: @@ -47,6 +47,8 @@ The following API is provided to customize the server instance: This instructs the Web server to serve static files, such as stylesheet and images, from @scheme[path]. } +} + @; ------------------------------------------------------------ @include-section["servlet-env.scrbl"] @@ -79,8 +81,13 @@ To run the web server with MrEd, use @; ------------------------------------------------------------ @section[#:tag "web-server.ss"]{Functional} @(require (for-label web-server/web-server)) +@(require (for-label web-server/dispatchers/filesystem-map) + (for-label web-server/web-config-unit) + (for-label web-server/web-config-sig) + (for-label web-server/configuration/configuration-table) + (prefix-in files: (for-label web-server/dispatchers/dispatch-files))) -@defmodule[web-server/web-server] +@defmodule[web-server/web-server]{ @filepath{web-server.ss} provides a number of functions for easing embedding of the @web-server in other applications, or loading a custom @@ -102,12 +109,6 @@ dispatcher. Here's an example of a simple web server that serves files from a given path: -@(require (for-label web-server/dispatchers/filesystem-map) - (for-label web-server/web-config-unit) - (for-label web-server/web-config-sig) - (for-label web-server/configuration/configuration-table) - (prefix-in files: (for-label web-server/dispatchers/dispatch-files))) - @schemeblock[ (define (start-file-server base) (serve @@ -157,4 +158,6 @@ from a given path: @defproc[(do-not-return) void]{ This function does not return. If you are writing a script to load the @web-server you are likely to want to call this functions at the end of your script. +} + } \ No newline at end of file diff --git a/collects/web-server/scribblings/servlet-definition.scrbl b/collects/web-server/scribblings/servlet-definition.scrbl new file mode 100644 index 0000000000..8fba4e47e4 --- /dev/null +++ b/collects/web-server/scribblings/servlet-definition.scrbl @@ -0,0 +1,12 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:style 'toc #:tag "module-servlets"]{Defining a Servlet} + +A @defterm{servlet} is a module with particular exports. There three kinds of servlets. + +@local-table-of-contents[] + +@include-section["v1-servlet.scrbl"] +@include-section["v2-servlet.scrbl"] +@include-section["stateless-servlet.scrbl"] diff --git a/collects/web-server/scribblings/servlet-env.scrbl b/collects/web-server/scribblings/servlet-env.scrbl index ae4e3cb0b5..3e5e4bcf94 100644 --- a/collects/web-server/scribblings/servlet-env.scrbl +++ b/collects/web-server/scribblings/servlet-env.scrbl @@ -5,7 +5,7 @@ #:style 'toc]{Simple Single Servlet Servers} @(require (for-label web-server/servlet-env)) -@defmodule[web-server/servlet-env] +@defmodule[web-server/servlet-env]{ The @web-server provides a way to quickly configure and start a server instance. @@ -119,3 +119,5 @@ the top-level interacts with continuations. (Read: Don't do it.) MIME types are looked up at @scheme[mime-types-path]. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/servlet-setup.scrbl b/collects/web-server/scribblings/servlet-setup.scrbl new file mode 100644 index 0000000000..c10f91b277 --- /dev/null +++ b/collects/web-server/scribblings/servlet-setup.scrbl @@ -0,0 +1,53 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:tag "setup.ss"]{Setting Up Servlets} +@(require (for-label web-server/servlet/setup)) + +@defmodule[web-server/servlet/setup]{ + +This module is used internally to build and load servlets. It may be useful to those who are trying to extend the server. + +@defproc[(make-v1.servlet [directory path?] + [timeout integer?] + [start (request? . -> . response?)]) + servlet?]{ + Creates a version 1 servlet that uses @scheme[directory] as its current directory, a timeout manager with a @scheme[timeout] timeout, and @scheme[start] as the request handler. +} + +@defproc[(make-v2.servlet [directory path?] + [manager manager?] + [start (request? . -> . response?)]) + servlet?]{ + Creates a version 2 servlet that uses @scheme[directory] as its current directory, a @scheme[manager] as the continuation manager, and @scheme[start] as the request handler. +} + +@defproc[(make-stateless.servlet [directory path?] + [start (request? . -> . response?)]) + servlet?]{ + Creates a stateless @schememodname[web-server] servlet that uses @scheme[directory] as its current directory and @scheme[start] as the request handler. +} + +@defthing[default-module-specs (listof module-path?)]{ + The modules that the Web Server needs to share with all servlets. +} + +@defthing[path->servlet/c contract?]{ +Equivalent to @scheme[(path? . -> . servlet?)]. +} + +@defproc[(make-default-path->servlet + [#:make-servlet-namespace + make-servlet-namespace + make-servlet-namespace? + (make-make-servlet-namespace)] + [#:timeouts-default-servlet + timeouts-default-servlet + integer? + 30]) + path->servlet/c]{ + Constructs a procedure that loads a servlet from the path in a namespace created with @scheme[make-servlet-namespace], + using a timeout manager with @scheme[timeouts-default-servlet] as the default timeout (if no manager is given.) +} + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/servlet.scrbl b/collects/web-server/scribblings/servlet.scrbl deleted file mode 100644 index 74f6beb06c..0000000000 --- a/collects/web-server/scribblings/servlet.scrbl +++ /dev/null @@ -1,427 +0,0 @@ -#lang scribble/doc -@(require "web-server.ss") - -@title[#:tag "servlet" - #:style 'toc]{Scheme Servlets} - -@defmodule[web-server/servlet] - -The @web-server allows servlets to be written in Scheme. It -provides the supporting API, described below, for the construction -of these servlets. - -@local-table-of-contents[] - -@; ------------------------------------------------------------ -@section[#:tag "module-servlets"]{Definition} -@(require (for-label "dummy-servlet.ss")) @; to give a binding context - -@declare-exporting[#:use-sources (web-server/scribblings/dummy-servlet)] - -A @defterm{servlet} is a module that provides the following: - -@defthing[interface-version (one-of/c 'v1 'v2 'stateless)]{ - A symbol indicating the servlet interface the servlet conforms - to. This influences the other provided identifiers. -} - -@defthing[timeout integer?]{ - Only if @scheme[interface-version] is @scheme['v1]. - - This number is used as the @scheme[continuation-timeout] argument to - a timeout-based continuation manager used for this servlet. (See - @secref["timeouts.ss"].) (i.e., you do not have a choice of the manager - for this servlet and will be given a timeout-based manager.) -} - -@defthing[manager manager?]{ - Only if @scheme[interface-version] is @scheme['v2]. - - The manager for the continuations of this servlet. -} - -@defproc[(start [initial-request request?]) - response?]{ - This function is called when an instance of this servlet is started. - The argument is the HTTP request that initiated the instance. -} - -An example version 1 module: -@schememod[ - scheme - - (define interface-version 'v1) - (define timeout (* 60 60 24)) - (define (start req) - `(html (head (title "Hello World!")) - (body (h1 "Hi Mom!")))) - ] - -An example version 2 module: -@(require (for-label web-server/managers/none)) -@schememod[ - scheme - (require web-server/managers/none) - - (define interface-version 'v2) - (define manager - (create-none-manager - (lambda (req) - `(html (head (title "No Continuations Here!")) - (body (h1 "No Continuations Here!")))))) - (define (start req) - `(html (head (title "Hello World!")) - (body (h1 "Hi Mom!")))) - ] - -An example @scheme['stateless] servlet module: -@schememod[ - web-server - (define interface-version 'stateless) - (define (start req) - `(html (body (h2 "Look ma, no state!")))) -] - -@; ------------------------------------------------------------ -@section[#:tag "servlet-structs.ss"]{Contracts} -@(require (for-label web-server/servlet/servlet-structs - web-server/servlet)) - -@defmodule[web-server/servlet/servlet-structs] - -@filepath{servlet/servlet-structs.ss} provides a number of contracts -for use in servlets. - -@defthing[k-url? contract?]{ -Equivalent to @scheme[string?]. - -Example: @scheme["http://localhost:8080/servlets;1*1*20131636/examples/add.ss"]} - -@defthing[response-generator? contract?]{ -Equivalent to @scheme[(k-url? . -> . response?)]. - -Example: @schemeblock[(lambda (k-url) - `(html - (body - (a ([href ,k-url]) - "Click Me to Invoke the Continuation!"))))] -} - -@defthing[expiration-handler/c contract?]{ -Equivalent to @scheme[(or/c false/c (request? . -> . response?))]. - -Example: @schemeblock[(lambda (req) - `(html (head (title "Expired")) - (body (h1 "Expired") - (p "This URL has expired. " - "Please return to the home page."))))] -} - -@defthing[embed/url/c contract?]{ -Equivalent to @scheme[(((request? . -> . any/c)) (expiration-handler/c) . opt-> . string?)]. - -This is what @scheme[send/suspend/dispatch] gives to its function argument. -} - -@; ------------------------------------------------------------ -@section[#:tag "web.ss"]{Web} -@(require (for-label web-server/servlet/web)) - -@defmodule[web-server/servlet/web]{The -@schememodname[web-server/servlet/web] library provides the primary -functions of interest for the servlet developer.} - -@defproc[(send/back [response response?]) - void?]{ - Sends @scheme[response] to the client. No continuation is captured, so the servlet is done. - - Example: - @schemeblock[ - (send/back - `(html - (body - (h1 "The sum is: " - ,(+ first-number - second-number))))) - ] -} - -@defthing[current-servlet-continuation-expiration-handler (parameter/c expiration-handler/c)]{ - Holds the @scheme[expiration-handler/c] to be used when a continuation - captured in this context is expired, then looked up. - - Example: - @schemeblock[ - (parameterize - ([current-servlet-continuation-expiration-handler - (lambda (req) - `(html (head (title "Custom Expiration!"))))]) - (send/suspend - ...)) - ] -} - -@defproc[(send/suspend [make-response response-generator?] - [exp expiration-handler/c (current-servlet-continuation-expiration-handler)]) - request?]{ - Captures the current continuation, stores it with @scheme[exp] as the expiration - handler, and binds it to a URL. @scheme[make-response] is called with this URL and - is expected to generate a @scheme[response?], which is sent to the client. If the - continuation URL is invoked, the captured continuation is invoked and the request is - returned from this call to @scheme[send/suspend]. - - Example: - @schemeblock[ - (send/suspend - (lambda (k-url) - `(html (head (title "Enter a number")) - (body - (form ([action ,k-url]) - "Enter a number: " - (input ([name "number"])) - (input ([type "submit"]))))))) - ] - - When this form is submitted by the browser, the request will be sent to the URL generated by @scheme[send/suspend]. - Thus, the request will be ``returned'' from @scheme[send/suspend] to the continuation of this call. -} - -@defproc[(send/suspend/dispatch [make-response (embed/url/c . -> . response?)]) - any/c]{ - Calls @scheme[make-response] with a function that, when called with a procedure from - @scheme[request?] to @scheme[any/c] will generate a URL, that when invoked will call - the function with the @scheme[request?] object and return the result to the caller of - @scheme[send/suspend/dispatch]. - - Use @scheme[send/suspend/dispatch] when there are multiple `logical' continuations of a page. - For example, we could either add to a number or subtract from it: - @schemeblock[ - (define (count-dot-com i) - (count-dot-com - (send/suspend/dispatch - (lambda (embed/url) - `(html - (head (title "Count!")) - (body - (h2 (a ([href - ,(embed/url - (lambda (req) - (sub1 i)))]) - "-")) - (h1 ,(number->string i)) - (h2 (a ([href - ,(embed/url - (lambda (req) - (add1 i)))]) - "+")))))))) - ] - It is very common that the return value of @scheme[send/suspend/dispatch] is irrevelant in - your application and you may think of it as ``embedding'' value-less callbacks. -} - -@defproc[(clear-continuation-table!) - void?]{ - Calls the servlet's manager's @scheme[clear-continuation-table!] function. Normally, this deletes all the previously - captured continuations. -} - -@defproc[(send/forward [make-response response-generator?] - [exp expiration-handler/c (current-servlet-continuation-expiration-handler)]) - request?]{ - Calls @scheme[clear-continuation-table!], then @scheme[send/suspend]. - - Use this if the user can logically go `forward' in your application, but cannot go backward. -} - -@defproc[(send/finish [response response?]) - void?]{ - Calls @scheme[clear-continuation-table!], then @scheme[send/back]. - - Use this if the user is truly `done' with your application. For example, it may be used to display the post-logout page: - @schemeblock[ - (send/finish - `(html (head (title "Logged out")) - (body (p "Thank you for using the services " - "of the Add Two Numbers, Inc.")))) - ] -} - -@defproc[(redirect/get) - request?]{ - Calls @scheme[send/suspend] with @scheme[redirect-to]. - - This implements the Post-Redirect-Get pattern. - Use this to prevent the @onscreen["Refresh"] button from duplicating effects, such as adding items to a database. -} - -@defproc[(redirect/get/forget) - request?]{ - Calls @scheme[send/forward] with @scheme[redirect-to]. -} - -@defproc[(adjust-timeout! [t number?]) - void?]{ - Calls the servlet's manager's @scheme[adjust-timeout!] function. - - @warning{This is deprecated and will be removed in a future release.} -} - -@defproc[(continuation-url? [u url?]) - (or/c false/c (list/c number? number? number?))]{ - Checks if @scheme[u] is a URL that refers to a continuation, if so - returns the instance id, continuation id, and nonce. -} - -@; ------------------------------------------------------------ -@section[#:tag "helpers.ss"]{Helpers} -@(require (for-label web-server/servlet/helpers)) - -@defmodule[web-server/servlet/helpers] - -@defproc[(with-errors-to-browser [send/finish-or-back (response? . -> . request?)] - [thunk (-> any)]) - any]{ - Calls @scheme[thunk] with an exception handler that generates an HTML error page - and calls @scheme[send/finish-or-back]. - - Example: - @schemeblock[ - (with-errors-to-browser - send/back - (lambda () - (/ 1 (get-number (request-number))))) - ] -} - -@; ------------------------------------------------------------ -@section[#:tag "web-cells.ss"]{Web Cells} -@(require (for-label web-server/servlet/web-cells)) - -@defmodule[web-server/servlet/web-cells]{The -@schememodname[web-server/servlet/web-cells] library provides the -interface to Web cells.} - -A Web cell is a kind of state defined relative to the @defterm{frame tree}. -The frame-tree is a mirror of the user's browsing session. Every time a -continuation is invoked, a new frame (called the @defterm{current frame}) is -created as a child of the current frame when the continuation was captured. - -You should use Web cells if you want an effect to be encapsulated in all -interactions linked from (in a transitive sense) the HTTP response being -generated. For more information on their semantics, consult the paper -@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-state-web/" -"\"Interaction-Safe State for the Web\""]. - -@defproc[(web-cell? [v any/c]) - boolean?]{ - Determines if @scheme[v] is a web-cell. -} - -@defproc[(make-web-cell [v any/c]) - web-cell?]{ - Creates a web-cell with a default value of @scheme[v]. -} - -@defproc[(web-cell-ref [wc web-cell?]) - any/c]{ - Looks up the value of @scheme[wc] found in the nearest - frame. -} - -@defproc[(web-cell-shadow [wc web-cell?] - [v any/c]) - void]{ - Binds @scheme[wc] to @scheme[v] in the current frame, shadowing any - other bindings to @scheme[wc] in the current frame. -} - -Below is an extended example that demonstrates how Web cells allow -the creation of reusable Web abstractions without requiring global -transformations of the program into continuation or store passing style. -@schememod[ - web-server/insta - - (define (start initial-request) - (define counter1 (make-counter)) - (define counter2 (make-counter)) - (define include1 (include-counter counter1)) - (define include2 (include-counter counter2)) - (send/suspend/dispatch - (lambda (embed/url) - `(html - (body (h2 "Double Counters") - (div (h3 "First") - ,(include1 embed/url)) - (div (h3 "Second") - ,(include2 embed/url))))))) - -(define (make-counter) - (make-web-cell 0)) - -(define (include-counter a-counter) - (let/cc k - (let loop () - (k - (lambda (embed/url) - `(div (h3 ,(number->string (web-cell-ref a-counter))) - (a ([href - ,(embed/url - (lambda _ - @code:comment{A new frame has been created} - (define last (web-cell-ref a-counter)) - @code:comment{We can inspect the value at the parent} - (web-cell-shadow a-counter (add1 last)) - @code:comment{The new frame has been modified} - (loop)))]) - "+"))))))) -] - -@; ------------------------------------------------------------ -@section[#:tag "setup.ss"]{Setup} -@(require (for-label web-server/servlet/setup)) - -@defmodule[web-server/servlet/setup] - -This module is used internally to build and load servlets. It may be useful to those who are trying to extend the server. - -@defproc[(make-v1.servlet [directory path?] - [timeout integer?] - [start (request? . -> . response?)]) - servlet?]{ - Creates a version 1 servlet that uses @scheme[directory] as its current directory, a timeout manager with a @scheme[timeout] timeout, and @scheme[start] as the request handler. -} - -@defproc[(make-v2.servlet [directory path?] - [manager manager?] - [start (request? . -> . response?)]) - servlet?]{ - Creates a version 2 servlet that uses @scheme[directory] as its current directory, a @scheme[manager] as the continuation manager, and @scheme[start] as the request handler. -} - -@defproc[(make-stateless.servlet [directory path?] - [start (request? . -> . response?)]) - servlet?]{ - Creates a stateless @schememodname[web-server] servlet that uses @scheme[directory] as its current directory and @scheme[start] as the request handler. -} - -@defthing[default-module-specs (listof module-path?)]{ - The modules that the Web Server needs to share with all servlets. -} - -@defthing[path->servlet/c contract?]{ -Equivalent to @scheme[(path? . -> . servlet?)]. -} - -@defproc[(make-default-path->servlet - [#:make-servlet-namespace - make-servlet-namespace - make-servlet-namespace? - (make-make-servlet-namespace)] - [#:timeouts-default-servlet - timeouts-default-servlet - integer? - 30]) - path->servlet/c]{ - Constructs a procedure that loads a servlet from the path in a namespace created with @scheme[make-servlet-namespace], - using a timeout manager with @scheme[timeouts-default-servlet] as the default timeout (if no manager is given.) -} \ No newline at end of file diff --git a/collects/web-server/scribblings/stateless-servlet.scrbl b/collects/web-server/scribblings/stateless-servlet.scrbl new file mode 100644 index 0000000000..c900979363 --- /dev/null +++ b/collects/web-server/scribblings/stateless-servlet.scrbl @@ -0,0 +1,95 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:tag "stateless-servlets"]{Stateless Servlets} +@defmodulelang[web-server] + +@(require (for-label "dummy-stateless-servlet.ss")) @; to give a binding context +@declare-exporting[#:use-sources (web-server/scribblings/dummy-stateless-servlet)] + +@defthing[interface-version (one-of/c 'stateless)]{ + This indicates that the servlet is a stateless servlet. +} + +@defproc[(start [initial-request request?]) + response?]{ + This function is called when an instance of this servlet is started. + The argument is the HTTP request that initiated the instance. +} + +An example @scheme['stateless] servlet module: +@schememod[ + web-server + (define interface-version 'stateless) + (define (start req) + `(html (body (h2 "Look ma, no state!")))) +] + +The @schememodname[web-server] language automatically provides the @schememodname[web-server/lang/lang-api] API. + +@; ------------------------------------------------------------ +@section[#:tag "considerations"]{Usage Considerations} + +A servlet has the following process performed on it automatically: +@itemize[ + @item{All uses of @scheme[letrec] are removed and replaced with equivalent uses of + @scheme[let] and imperative features. (@filepath{lang/elim-letrec.ss})} + @item{The program is converted into ANF (Administrative Normal Form), + making all continuations explicit. (@filepath{lang/anormal.ss})} + @item{All continuations (and other continuations marks) are recorded in the + continuation marks of the expression + they are the continuation of. (@filepath{lang/elim-callcc.ss})} + @item{All calls to external modules are identified and marked. + (@filepath{lang/elim-callcc.ss})} + @item{All uses of @scheme[call/cc] are removed and replaced with + equivalent gathering of the continuations through the continuation-marks. + (@filepath{lang/elim-callcc.ss})} + @item{The program is defunctionalized with a serializable data-structure for each + anonymous lambda. (@filepath{lang/defun.ss})} +] + +This process allows the continuations captured by your servlet to be serialized. +This means they may be stored on the client's browser or the server's disk. +Thus, your servlet has no cost to the server other than execution. This is +very attractive if you've used Scheme servlets and had memory problems. + +This process IS defined on all of PLT Scheme and occurs AFTER macro-expansion, +so you are free to use all interesting features of PLT Scheme. However, there +are some considerations you must make. + +First, this process drastically changes the structure of your program. It +will create an immense number of lambdas and structures your program +did not normally contain. The performance implication of this has not been +studied with PLT Scheme. However, it is theoretically a benefit. The main +implications would be due to optimizations MzScheme attempts to perform +that will no longer apply. Ideally, your program should be optimized first. + +Second, the defunctionalization process is sensitive to the syntactic structure +of your program. Therefore, if you change your program in a trivial way, for example, +changing a constant, then all serialized continuations will be obsolete and will +error when deserialization is attempted. This is a feature, not a bug! + +Third, the values in the lexical scope of your continuations must be serializable +for the continuations itself to be serializable. This means that you must use +@scheme[define-serializable-struct] rather than @scheme[define-struct], and take +care to use modules that do the same. Similarly, you may not use @scheme[parameterize], +because parameterizations are not serializable. + +Fourth, and related, this process only runs on your code, not on the code you +@scheme[require]. Thus, your continuations---to be capturable---must not +be in the context of another module. For example, the following will not work: +@schemeblock[ + (define requests + (map (lambda (rg) (send/suspend/url rg)) + response-generators)) +] +because @scheme[map] is not transformed by the process. However, if you defined +your own @scheme[map] function, there would be no problem. + +Fifth, the store is NOT serialized. If you rely on the store you will +be taking huge risks. You will be assuming that the serialized continuation +is invoked before the server is restarted or the memory is garbage collected. + +This process is derived from the paper +@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/pcmkf-cont-from-gen-stack-insp/" "Continuations from Generalized Stack Inspection"]. +We thank Greg Pettyjohn for his initial implementation of this algorithm. \ No newline at end of file diff --git a/collects/web-server/scribblings/v1-servlet.scrbl b/collects/web-server/scribblings/v1-servlet.scrbl new file mode 100644 index 0000000000..315b49c2e0 --- /dev/null +++ b/collects/web-server/scribblings/v1-servlet.scrbl @@ -0,0 +1,36 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title{Version 1 Servlets} +@(require (for-label "dummy-v1-servlet.ss")) @; to give a binding context +@declare-exporting[#:use-sources (web-server/scribblings/dummy-v1-servlet)] + +@defthing[interface-version (one-of/c 'v1)]{ + This indicates that the servlet is a version one servlet. +} + +@defthing[timeout integer?]{ + This number is used as the @scheme[continuation-timeout] argument to + a timeout-based continuation manager used for this servlet. (See + @secref["timeouts.ss"].) (i.e., you do not have a choice of the manager + for this servlet and will be given a timeout-based manager.) +} + +@defproc[(start [initial-request request?]) + response?]{ + This function is called when an instance of this servlet is started. + The argument is the HTTP request that initiated the instance. +} + +An example version 1 module: +@schememod[ + scheme + + (define interface-version 'v1) + (define timeout (* 60 60 24)) + (define (start req) + `(html (head (title "Hello World!")) + (body (h1 "Hi Mom!")))) + ] + +These servlets should use the @schememodname[web-server/servlet] API. \ No newline at end of file diff --git a/collects/web-server/scribblings/v2-servlet.scrbl b/collects/web-server/scribblings/v2-servlet.scrbl new file mode 100644 index 0000000000..84c7b2edcc --- /dev/null +++ b/collects/web-server/scribblings/v2-servlet.scrbl @@ -0,0 +1,39 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title{Version 2 Servlets} +@(require (for-label "dummy-v2-servlet.ss")) @; to give a binding context +@declare-exporting[#:use-sources (web-server/scribblings/dummy-v2-servlet)] + +@defthing[interface-version (one-of/c 'v2)]{ + This indicates that the servlet is a version two servlet. +} + +@defthing[manager manager?]{ + The manager for the continuations of this servlet. See @secref["managers"] for options. +} + +@defproc[(start [initial-request request?]) + response?]{ + This function is called when an instance of this servlet is started. + The argument is the HTTP request that initiated the instance. +} + +An example version 2 module: +@(require (for-label web-server/managers/none)) +@schememod[ + scheme + (require web-server/managers/none) + + (define interface-version 'v2) + (define manager + (create-none-manager + (lambda (req) + `(html (head (title "No Continuations Here!")) + (body (h1 "No Continuations Here!")))))) + (define (start req) + `(html (head (title "Hello World!")) + (body (h1 "Hi Mom!")))) + ] + +These servlets should use the @schememodname[web-server/servlet] API. \ No newline at end of file diff --git a/collects/web-server/scribblings/web-cells.scrbl b/collects/web-server/scribblings/web-cells.scrbl new file mode 100644 index 0000000000..6ba6e8dda3 --- /dev/null +++ b/collects/web-server/scribblings/web-cells.scrbl @@ -0,0 +1,87 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:tag "web-cells.ss"]{Web Cells} +@(require (for-label web-server/servlet/web-cells)) + +@defmodule[web-server/servlet/web-cells]{The +@schememodname[web-server/servlet/web-cells] library provides the +interface to Web cells. + +A Web cell is a kind of state defined relative to the @defterm{frame tree}. +The frame-tree is a mirror of the user's browsing session. Every time a +continuation is invoked, a new frame (called the @defterm{current frame}) is +created as a child of the current frame when the continuation was captured. + +You should use Web cells if you want an effect to be encapsulated in all +interactions linked from (in a transitive sense) the HTTP response being +generated. For more information on their semantics, consult the paper +@href-link["http://www.cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-state-web/" +"\"Interaction-Safe State for the Web\""]. + +@defproc[(web-cell? [v any/c]) + boolean?]{ + Determines if @scheme[v] is a web-cell. +} + +@defproc[(make-web-cell [v any/c]) + web-cell?]{ + Creates a web-cell with a default value of @scheme[v]. +} + +@defproc[(web-cell-ref [wc web-cell?]) + any/c]{ + Looks up the value of @scheme[wc] found in the nearest + frame. +} + +@defproc[(web-cell-shadow [wc web-cell?] + [v any/c]) + void]{ + Binds @scheme[wc] to @scheme[v] in the current frame, shadowing any + other bindings to @scheme[wc] in the current frame. +} + +Below is an extended example that demonstrates how Web cells allow +the creation of reusable Web abstractions without requiring global +transformations of the program into continuation or store passing style. +@schememod[ + web-server/insta + + (define (start initial-request) + (define counter1 (make-counter)) + (define counter2 (make-counter)) + (define include1 (include-counter counter1)) + (define include2 (include-counter counter2)) + (send/suspend/dispatch + (lambda (embed/url) + `(html + (body (h2 "Double Counters") + (div (h3 "First") + ,(include1 embed/url)) + (div (h3 "Second") + ,(include2 embed/url))))))) + +(define (make-counter) + (make-web-cell 0)) + +(define (include-counter a-counter) + (let/cc k + (let loop () + (k + (lambda (embed/url) + `(div (h3 ,(number->string (web-cell-ref a-counter))) + (a ([href + ,(embed/url + (lambda _ + @code:comment{A new frame has been created} + (define last (web-cell-ref a-counter)) + @code:comment{We can inspect the value at the parent} + (web-cell-shadow a-counter (add1 last)) + @code:comment{The new frame has been modified} + (loop)))]) + "+"))))))) +] +} + +@include-section["lang-web-cells.scrbl"] \ No newline at end of file diff --git a/collects/web-server/scribblings/web-config-unit.scrbl b/collects/web-server/scribblings/web-config-unit.scrbl index 3a1341207a..875a12f702 100644 --- a/collects/web-server/scribblings/web-config-unit.scrbl +++ b/collects/web-server/scribblings/web-config-unit.scrbl @@ -1,15 +1,18 @@ #lang scribble/doc @(require "web-server.ss") -@title[#:tag "web-config-unit.ss"]{Web Config Unit} +@title[#:tag "web-config-unit.ss" + #:style 'toc]{Web Config Unit} @(require (for-label web-server/web-config-unit) (for-label web-server/web-config-sig)) The @web-server offers a unit-based approach to configuring the server. +@local-table-of-contents[] + @section{Configuration Signature} -@defmodule[web-server/web-config-sig] +@defmodule[web-server/web-config-sig]{ @defsignature[web-config^ ()]{ @@ -41,10 +44,12 @@ Provides contains the following identifiers. Passed to @scheme[servlets:make]. } } + +} @section{Configuration Units} -@defmodule[web-server/web-config-unit] +@defmodule[web-server/web-config-unit]{ @defproc[(configuration-table->web-config@ [path path?] [#:port port (or/c false/c port-number?) #f] @@ -63,3 +68,5 @@ Provides contains the following identifiers. (unit? web-config^)]{ Parses @scheme[sexpr] as a configuration-table and constructs a @scheme[web-config^] unit. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/web-server-unit.scrbl b/collects/web-server/scribblings/web-server-unit.scrbl index d830b52d59..88094ea6c1 100644 --- a/collects/web-server/scribblings/web-server-unit.scrbl +++ b/collects/web-server/scribblings/web-server-unit.scrbl @@ -1,15 +1,18 @@ #lang scribble/doc @(require "web-server.ss") -@title[#:tag "web-server-unit.ss"]{Web Server Unit} +@title[#:tag "web-server-unit.ss" + #:style 'toc]{Web Server Unit} @(require (for-label web-server/web-server-sig) (for-label web-server/web-server-unit)) The @web-server offers a unit-based approach to running the server. +@local-table-of-contents[] + @section{Signature} -@defmodule[web-server/web-server-sig] +@defmodule[web-server/web-server-sig]{ @defsignature[web-server^ ()]{ @@ -25,9 +28,11 @@ The @web-server offers a unit-based approach to running the server. } } +} + @section{Unit} -@defmodule[web-server/web-server-unit] +@defmodule[web-server/web-server-unit]{ @defthing[web-server@ (unit/c (web-config^ tcp^) (web-server^))]{ @@ -50,3 +55,5 @@ operations: Using this @scheme[dispatcher?], it loads a dispatching server that provides @scheme[serve] and @scheme[serve-ports] functions that operate as expected. } + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/web-server.scrbl b/collects/web-server/scribblings/web-server.scrbl index 2fd884ee87..9d83fa09af 100644 --- a/collects/web-server/scribblings/web-server.scrbl +++ b/collects/web-server/scribblings/web-server.scrbl @@ -11,22 +11,8 @@ develop Web applications in Scheme. @table-of-contents[] @include-section["running.scrbl"] - -@include-section["http.scrbl"] - -@include-section["servlet.scrbl"] -@include-section["lang.scrbl"] - -@include-section["formlets.scrbl"] - -@include-section["configuration.scrbl"] -@include-section["dispatchers.scrbl"] -@include-section["web-config-unit.scrbl"] -@include-section["web-server-unit.scrbl"] -@include-section["managers.scrbl"] - -@include-section["private.scrbl"] - +@include-section["writing.scrbl"] +@include-section["extending.scrbl"] @include-section["faq.scrbl"] @; ------------------------------------------------------------ diff --git a/collects/web-server/scribblings/web.scrbl b/collects/web-server/scribblings/web.scrbl new file mode 100644 index 0000000000..146712abc5 --- /dev/null +++ b/collects/web-server/scribblings/web.scrbl @@ -0,0 +1,167 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:tag "web.ss"]{Web Interaction} +@(require (for-label web-server/servlet/web)) + +@defmodule[web-server/servlet/web]{The +@schememodname[web-server/servlet/web] library provides the primary +functions of interest for the servlet developer. + +@defproc[(send/back [response response?]) + void?]{ + Sends @scheme[response] to the client. No continuation is captured, so the servlet is done. + + Example: + @schemeblock[ + (send/back + `(html + (body + (h1 "The sum is: " + ,(+ first-number + second-number))))) + ] +} + +@defproc[(send/suspend [make-response response-generator?] + [exp expiration-handler/c (current-servlet-continuation-expiration-handler)]) + request?]{ + Captures the current continuation, stores it with @scheme[exp] as the expiration + handler, and binds it to a URL. @scheme[make-response] is called with this URL and + is expected to generate a @scheme[response?], which is sent to the client. If the + continuation URL is invoked, the captured continuation is invoked and the request is + returned from this call to @scheme[send/suspend]. + + Example: + @schemeblock[ + (send/suspend + (lambda (k-url) + `(html (head (title "Enter a number")) + (body + (form ([action ,k-url]) + "Enter a number: " + (input ([name "number"])) + (input ([type "submit"]))))))) + ] + + When this form is submitted by the browser, the request will be sent to the URL generated by @scheme[send/suspend]. + Thus, the request will be ``returned'' from @scheme[send/suspend] to the continuation of this call. +} + +@defproc[(send/suspend/dispatch [make-response (embed/url/c . -> . response?)]) + any/c]{ + Calls @scheme[make-response] with a function that, when called with a procedure from + @scheme[request?] to @scheme[any/c] will generate a URL, that when invoked will call + the function with the @scheme[request?] object and return the result to the caller of + @scheme[send/suspend/dispatch]. + + Use @scheme[send/suspend/dispatch] when there are multiple `logical' continuations of a page. + For example, we could either add to a number or subtract from it: + @schemeblock[ + (define (count-dot-com i) + (count-dot-com + (send/suspend/dispatch + (lambda (embed/url) + `(html + (head (title "Count!")) + (body + (h2 (a ([href + ,(embed/url + (lambda (req) + (sub1 i)))]) + "-")) + (h1 ,(number->string i)) + (h2 (a ([href + ,(embed/url + (lambda (req) + (add1 i)))]) + "+")))))))) + ] + It is very common that the return value of @scheme[send/suspend/dispatch] is irrevelant in + your application and you may think of it as ``embedding'' value-less callbacks. +} + +@defproc[(send/forward [make-response response-generator?] + [exp expiration-handler/c (current-servlet-continuation-expiration-handler)]) + request?]{ + Calls @scheme[clear-continuation-table!], then @scheme[send/suspend]. + + Use this if the user can logically go `forward' in your application, but cannot go backward. +} + +@defproc[(send/finish [response response?]) + void?]{ + Calls @scheme[clear-continuation-table!], then @scheme[send/back]. + + Use this if the user is truly `done' with your application. For example, it may be used to display the post-logout page: + @schemeblock[ + (send/finish + `(html (head (title "Logged out")) + (body (p "Thank you for using the services " + "of the Add Two Numbers, Inc.")))) + ] +} + +@defproc[(redirect/get) + request?]{ + Calls @scheme[send/suspend] with @scheme[redirect-to]. + + This implements the Post-Redirect-Get pattern. + Use this to prevent the @onscreen["Refresh"] button from duplicating effects, such as adding items to a database. +} + +@defproc[(redirect/get/forget) + request?]{ + Calls @scheme[send/forward] with @scheme[redirect-to]. +} + +@defthing[current-servlet-continuation-expiration-handler (parameter/c expiration-handler/c)]{ + Holds the @scheme[expiration-handler/c] to be used when a continuation + captured in this context is expired, then looked up. + + Example: + @schemeblock[ + (parameterize + ([current-servlet-continuation-expiration-handler + (lambda (req) + `(html (head (title "Custom Expiration!"))))]) + (send/suspend + ...)) + ] +} + +@defproc[(clear-continuation-table!) + void?]{ + Calls the servlet's manager's @scheme[clear-continuation-table!] function. Normally, this deletes all the previously + captured continuations. +} + +@defproc[(with-errors-to-browser [send/finish-or-back (response? . -> . request?)] + [thunk (-> any)]) + any]{ + Calls @scheme[thunk] with an exception handler that generates an HTML error page + and calls @scheme[send/finish-or-back]. + + Example: + @schemeblock[ + (with-errors-to-browser + send/back + (lambda () + (/ 1 (get-number (request-number))))) + ] +} + +@defproc[(adjust-timeout! [t number?]) + void?]{ + Calls the servlet's manager's @scheme[adjust-timeout!] function. + + @warning{This is deprecated and will be removed in a future release.} +} + +@defproc[(continuation-url? [u url?]) + (or/c false/c (list/c number? number? number?))]{ + Checks if @scheme[u] is a URL that refers to a continuation, if so + returns the instance id, continuation id, and nonce. +} + +} \ No newline at end of file diff --git a/collects/web-server/scribblings/writing.scrbl b/collects/web-server/scribblings/writing.scrbl new file mode 100644 index 0000000000..1d18388c9c --- /dev/null +++ b/collects/web-server/scribblings/writing.scrbl @@ -0,0 +1,167 @@ +#lang scribble/doc +@(require "web-server.ss") + +@title[#:style 'toc]{Writing Servlets} + +@local-table-of-contents[] + +@include-section["servlet-definition.scrbl"] + +@; ------------------------------------------------------------ +@section{APIs} + +There are two API sets provided by the Web Server. One is for standard servlets, the other is for stateless servlets. + +@subsection{Standard API} + +@defmodule[web-server/servlet]{ + +This API provides: +@itemize{ + @item{@schememodname[web-server/servlet/web-cells],} + @item{@schememodname[web-server/http/bindings],} + @item{@schememodname[web-server/http],} + @item{@schememodname[web-server/servlet/servlet-structs], and} + @item{@schememodname[web-server/servlet/web].}} +} + +@subsection{Stateless API} + +@defmodule[web-server/lang/lang-api]{ + +This API provides: +@itemize{ + @item{@schememodname[net/url],} + @item{@schememodname[web-server/http],} + @item{@schememodname[web-server/lang/abort-resume],} + @item{@schememodname[web-server/lang/web],} + @item{@schememodname[web-server/lang/web-cells],} + @item{@schememodname[web-server/lang/web-param], and} + @item{@schememodname[web-server/lang/file-box].}} +} + +@; ------------------------------------------------------------ +@section[#:tag "servlet-structs.ss"]{Common Contracts} +@(require (for-label web-server/servlet/servlet-structs + web-server/servlet)) + +@defmodule[web-server/servlet/servlet-structs]{ + +@filepath{servlet/servlet-structs.ss} provides a number of contracts +for use in servlets. + +@defthing[k-url? contract?]{ +Equivalent to @scheme[string?]. + +Example: @scheme["http://localhost:8080/servlets;1*1*20131636/examples/add.ss"]} + +@defthing[response-generator? contract?]{ +Equivalent to @scheme[(k-url? . -> . response?)]. + +Example: @schemeblock[(lambda (k-url) + `(html + (body + (a ([href ,k-url]) + "Click Me to Invoke the Continuation!"))))] +} + +@defthing[expiration-handler/c contract?]{ +Equivalent to @scheme[(or/c false/c (request? . -> . response?))]. + +Example: @schemeblock[(lambda (req) + `(html (head (title "Expired")) + (body (h1 "Expired") + (p "This URL has expired. " + "Please return to the home page."))))] +} + +@defthing[embed/url/c contract?]{ +Equivalent to @scheme[(((request? . -> . any/c)) (expiration-handler/c) . opt-> . string?)]. + +This is what @scheme[send/suspend/dispatch] gives to its function argument. +} + +} + +@; ------------------------------------------------------------ +@include-section["http.scrbl"] +@include-section["web.scrbl"] +@include-section["lang.scrbl"] +@include-section["web-cells.scrbl"] + +@; ------------------------------------------------------------ +@section[#:tag "lang/file-box.ss"]{File Boxes} +@(require (for-label web-server/lang/file-box)) + +@defmodule[web-server/lang/file-box]{ + +As mentioned earlier, it is dangerous to rely on the store in +Web Language servlets, due to the deployment scenarios available +to them. @filepath{lang/file-box.ss} provides a simple API to replace +boxes in a safe way. + +@defproc[(file-box? [v any/c]) + boolean?]{Checks if @scheme[v] is a file-box.} + +@defproc[(file-box [p path?] + [v serializable?]) + file-box?]{ + Creates a file-box that is stored at @scheme[p], with the default + contents of @scheme[v]. +} + +@defproc[(file-unbox [fb file-box?]) + serializable?]{ + Returns the value inside @scheme[fb] +} + +@defproc[(file-box-set? [fb file-box?]) + boolean?]{ + Returns @scheme[#t] if @scheme[fb] contains a value. +} + +@defproc[(file-box-set! [fb file-box?] + [v serializable?]) + void]{ + Saves @scheme[v] in the file represented by @scheme[fb]. +} + +@warning{If you plan on using a load-balancer, make sure your file-boxes +are on a shared medium.} + +} + +@; ------------------------------------------------------------ +@section[#:tag "lang/web-param.ss"]{Stateless Web Parameters} +@(require (for-label web-server/lang/web-param)) + +@defmodule[web-server/lang/web-param]{ + +It is not easy to use @scheme[parameterize] in the +Web Language. @filepath{lang/web-param.ss} provides (roughly) the same +functionality in a way that is serializable. Like other serializable +things in the Web Language, they are sensitive to source code modification. + +@defform[(make-web-parameter default)]{ + Expands to the definition of a web-parameter with + @scheme[default] as the default value. A web-parameter is + a procedure that, when called with zero arguments, returns @scheme[default] + or the last value @scheme[web-parameterize]d in the dynamic context + of the call. +} + +@defproc[(web-parameter? [v any/c]) + boolean?]{ + Checks if @scheme[v] appears to be a web-parameter. +} + +@defform[(web-parameterize ([web-parameter-expr value-expr] ...) expr ...)]{ + Runs @scheme[(begin expr ...)] such that the web-parameters that + the @scheme[web-parameter-expr]s evaluate to are bound to the @scheme[value-expr]s. + From the perspective of the @scheme[value-expr]s, this is like @scheme[let]. +} +} + +@; ------------------------------------------------------------ +@include-section["formlets.scrbl"] +@include-section["managers.scrbl"] diff --git a/collects/web-server/servlet.ss b/collects/web-server/servlet.ss index 7618766551..6b833ea39d 100644 --- a/collects/web-server/servlet.ss +++ b/collects/web-server/servlet.ss @@ -1,12 +1,10 @@ #lang scheme/base -(require web-server/servlet/helpers - web-server/servlet/web-cells +(require web-server/servlet/web-cells web-server/http/bindings web-server/http web-server/servlet/servlet-structs web-server/servlet/web) -(provide (all-from-out web-server/servlet/helpers - web-server/servlet/web-cells +(provide (all-from-out web-server/servlet/web-cells web-server/http/bindings web-server/http web-server/servlet/servlet-structs diff --git a/collects/web-server/servlet/helpers.ss b/collects/web-server/servlet/helpers.ss deleted file mode 100644 index 1d3c3aea88..0000000000 --- a/collects/web-server/servlet/helpers.ss +++ /dev/null @@ -1,20 +0,0 @@ -#lang scheme/base -(require scheme/contract) -(require "../private/util.ss" - web-server/http) - -(define (with-errors-to-browser send/finish-or-back thunk) - (with-handlers ([exn? (lambda (exn) - (send/finish-or-back - `(html (head (title "Servlet Error")) - (body ([bgcolor "white"]) - (p "The following error occured: " - (pre ,(exn->string exn)))))))]) - (thunk))) - -(provide/contract - [with-errors-to-browser - ((response? . -> . request?) - (-> any) - . -> . - any)]) diff --git a/collects/web-server/servlet/web.ss b/collects/web-server/servlet/web.ss index 20c37fe17f..ffac07e465 100644 --- a/collects/web-server/servlet/web.ss +++ b/collects/web-server/servlet/web.ss @@ -133,3 +133,20 @@ ; redirect/get : -> request (define redirect/get (make-redirect/get send/suspend)) (define redirect/get/forget (make-redirect/get send/forward)) + + +(define (with-errors-to-browser send/finish-or-back thunk) + (with-handlers ([exn? (lambda (exn) + (send/finish-or-back + `(html (head (title "Servlet Error")) + (body ([bgcolor "white"]) + (p "The following error occured: " + (pre ,(exn->string exn)))))))]) + (thunk))) + +(provide/contract + [with-errors-to-browser + ((response? . -> . request?) + (-> any) + . -> . + any)]) \ No newline at end of file