From b76aa843ab09e8c1c5f5de9e033b7170ed64acd4 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 10 Jan 2008 20:07:32 +0000 Subject: [PATCH] move doc sub-dirs to scribblings sub-dirs svn: r8281 --- collects/file/{doc => scribblings}/common.ss | 0 collects/file/{doc => scribblings}/file.scrbl | 0 collects/file/{doc => scribblings}/gif.scrbl | 0 .../file/{doc => scribblings}/gunzip.scrbl | 0 collects/file/{doc => scribblings}/gzip.scrbl | 0 collects/file/{doc => scribblings}/info.ss | 0 collects/file/{doc => scribblings}/md5.scrbl | 0 collects/file/{doc => scribblings}/tar.scrbl | 0 collects/file/{doc => scribblings}/zip.scrbl | 0 .../{doc => scribblings}/graphics.scrbl | 0 .../graphics/{doc => scribblings}/info.ss | 0 .../aligned-editor-canvas-class.scrbl | 0 .../aligned-editor-snip-class.scrbl | 0 .../aligned-pasteboard-intf.scrbl | 0 .../aligned-pasteboard-parent-intf.scrbl | 0 .../aligned-pasteboard.scrbl | 0 .../aligned-pasteboard/common.ss | 0 .../horizontal-pasteboard-class.scrbl | 0 .../stretchable-snip-intf.scrbl | 0 .../vertical-pasteboard-class.scrbl | 0 .../{doc => scribblings}/bitmap-label.scrbl | 0 .../cache-image-snip.scrbl | 0 collects/mrlib/{doc => scribblings}/common.ss | 0 collects/mrlib/{doc => scribblings}/gif.scrbl | 0 .../{doc => scribblings}/graph/common.ss | 0 .../graph/graph-pasteboard-intf.scrbl | 0 .../graph/graph-pasteboard-mixin.scrbl | 0 .../graph/graph-snip-intf.scrbl | 0 .../graph/graph-snip-mixin.scrbl | 0 .../{doc => scribblings}/graph/graph.scrbl | 0 .../{doc => scribblings}/include-bitmap.scrbl | 0 collects/mrlib/{doc => scribblings}/info.ss | 0 .../interactive-value-port.scrbl | 0 .../mrlib/{doc => scribblings}/mrlib.scrbl | 0 .../{doc => scribblings}/name-message.scrbl | 0 .../{doc => scribblings}/path-dialog.scrbl | 0 .../mrlib/{doc => scribblings}/plot.scrbl | 0 collects/net/{doc => scribblings}/cgi.scrbl | 0 collects/net/{doc => scribblings}/common.ss | 0 collects/net/{doc => scribblings}/info.ss | 0 collects/net/{doc => scribblings}/net.scrbl | 0 .../net/{doc => scribblings}/sendmail.scrbl | 0 .../net/{doc => scribblings}/sendurl.scrbl | 0 collects/net/{doc => scribblings}/smtp.scrbl | 0 collects/net/{doc => scribblings}/url.scrbl | 0 collects/scribblings/guide/guide.scrbl | 2 +- .../scribblings/configuration.scrbl | 260 +++++++++++ .../web-server/scribblings/dispatchers.scrbl | 376 +++++++++++++++ .../scribblings/dummy-language-servlet.ss | 6 + .../web-server/scribblings/dummy-servlet.ss | 9 + collects/web-server/scribblings/faq.scrbl | 13 + collects/web-server/scribblings/info.ss | 3 + collects/web-server/scribblings/lang.scrbl | 292 ++++++++++++ .../web-server/scribblings/managers.scrbl | 160 +++++++ collects/web-server/scribblings/private.scrbl | 422 +++++++++++++++++ collects/web-server/scribblings/running.scrbl | 80 ++++ .../web-server/scribblings/servlet-env.scrbl | 31 ++ collects/web-server/scribblings/servlet.scrbl | 429 ++++++++++++++++++ .../scribblings/web-config-unit.scrbl | 68 +++ .../scribblings/web-server-unit.scrbl | 52 +++ .../web-server/scribblings/web-server.scrbl | 38 ++ collects/web-server/scribblings/web-server.ss | 31 ++ 62 files changed, 2271 insertions(+), 1 deletion(-) rename collects/file/{doc => scribblings}/common.ss (100%) rename collects/file/{doc => scribblings}/file.scrbl (100%) rename collects/file/{doc => scribblings}/gif.scrbl (100%) rename collects/file/{doc => scribblings}/gunzip.scrbl (100%) rename collects/file/{doc => scribblings}/gzip.scrbl (100%) rename collects/file/{doc => scribblings}/info.ss (100%) rename collects/file/{doc => scribblings}/md5.scrbl (100%) rename collects/file/{doc => scribblings}/tar.scrbl (100%) rename collects/file/{doc => scribblings}/zip.scrbl (100%) rename collects/graphics/{doc => scribblings}/graphics.scrbl (100%) rename collects/graphics/{doc => scribblings}/info.ss (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/aligned-editor-canvas-class.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/aligned-editor-snip-class.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/aligned-pasteboard-intf.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/aligned-pasteboard-parent-intf.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/aligned-pasteboard.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/common.ss (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/horizontal-pasteboard-class.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/stretchable-snip-intf.scrbl (100%) rename collects/mrlib/{doc => scribblings}/aligned-pasteboard/vertical-pasteboard-class.scrbl (100%) rename collects/mrlib/{doc => scribblings}/bitmap-label.scrbl (100%) rename collects/mrlib/{doc => scribblings}/cache-image-snip.scrbl (100%) rename collects/mrlib/{doc => scribblings}/common.ss (100%) rename collects/mrlib/{doc => scribblings}/gif.scrbl (100%) rename collects/mrlib/{doc => scribblings}/graph/common.ss (100%) rename collects/mrlib/{doc => scribblings}/graph/graph-pasteboard-intf.scrbl (100%) rename collects/mrlib/{doc => scribblings}/graph/graph-pasteboard-mixin.scrbl (100%) rename collects/mrlib/{doc => scribblings}/graph/graph-snip-intf.scrbl (100%) rename collects/mrlib/{doc => scribblings}/graph/graph-snip-mixin.scrbl (100%) rename collects/mrlib/{doc => scribblings}/graph/graph.scrbl (100%) rename collects/mrlib/{doc => scribblings}/include-bitmap.scrbl (100%) rename collects/mrlib/{doc => scribblings}/info.ss (100%) rename collects/mrlib/{doc => scribblings}/interactive-value-port.scrbl (100%) rename collects/mrlib/{doc => scribblings}/mrlib.scrbl (100%) rename collects/mrlib/{doc => scribblings}/name-message.scrbl (100%) rename collects/mrlib/{doc => scribblings}/path-dialog.scrbl (100%) rename collects/mrlib/{doc => scribblings}/plot.scrbl (100%) rename collects/net/{doc => scribblings}/cgi.scrbl (100%) rename collects/net/{doc => scribblings}/common.ss (100%) rename collects/net/{doc => scribblings}/info.ss (100%) rename collects/net/{doc => scribblings}/net.scrbl (100%) rename collects/net/{doc => scribblings}/sendmail.scrbl (100%) rename collects/net/{doc => scribblings}/sendurl.scrbl (100%) rename collects/net/{doc => scribblings}/smtp.scrbl (100%) rename collects/net/{doc => scribblings}/url.scrbl (100%) create mode 100644 collects/web-server/scribblings/configuration.scrbl create mode 100644 collects/web-server/scribblings/dispatchers.scrbl create mode 100644 collects/web-server/scribblings/dummy-language-servlet.ss create mode 100644 collects/web-server/scribblings/dummy-servlet.ss create mode 100644 collects/web-server/scribblings/faq.scrbl create mode 100644 collects/web-server/scribblings/info.ss create mode 100644 collects/web-server/scribblings/lang.scrbl create mode 100644 collects/web-server/scribblings/managers.scrbl create mode 100644 collects/web-server/scribblings/private.scrbl create mode 100644 collects/web-server/scribblings/running.scrbl create mode 100644 collects/web-server/scribblings/servlet-env.scrbl create mode 100644 collects/web-server/scribblings/servlet.scrbl create mode 100644 collects/web-server/scribblings/web-config-unit.scrbl create mode 100644 collects/web-server/scribblings/web-server-unit.scrbl create mode 100644 collects/web-server/scribblings/web-server.scrbl create mode 100644 collects/web-server/scribblings/web-server.ss diff --git a/collects/file/doc/common.ss b/collects/file/scribblings/common.ss similarity index 100% rename from collects/file/doc/common.ss rename to collects/file/scribblings/common.ss diff --git a/collects/file/doc/file.scrbl b/collects/file/scribblings/file.scrbl similarity index 100% rename from collects/file/doc/file.scrbl rename to collects/file/scribblings/file.scrbl diff --git a/collects/file/doc/gif.scrbl b/collects/file/scribblings/gif.scrbl similarity index 100% rename from collects/file/doc/gif.scrbl rename to collects/file/scribblings/gif.scrbl diff --git a/collects/file/doc/gunzip.scrbl b/collects/file/scribblings/gunzip.scrbl similarity index 100% rename from collects/file/doc/gunzip.scrbl rename to collects/file/scribblings/gunzip.scrbl diff --git a/collects/file/doc/gzip.scrbl b/collects/file/scribblings/gzip.scrbl similarity index 100% rename from collects/file/doc/gzip.scrbl rename to collects/file/scribblings/gzip.scrbl diff --git a/collects/file/doc/info.ss b/collects/file/scribblings/info.ss similarity index 100% rename from collects/file/doc/info.ss rename to collects/file/scribblings/info.ss diff --git a/collects/file/doc/md5.scrbl b/collects/file/scribblings/md5.scrbl similarity index 100% rename from collects/file/doc/md5.scrbl rename to collects/file/scribblings/md5.scrbl diff --git a/collects/file/doc/tar.scrbl b/collects/file/scribblings/tar.scrbl similarity index 100% rename from collects/file/doc/tar.scrbl rename to collects/file/scribblings/tar.scrbl diff --git a/collects/file/doc/zip.scrbl b/collects/file/scribblings/zip.scrbl similarity index 100% rename from collects/file/doc/zip.scrbl rename to collects/file/scribblings/zip.scrbl diff --git a/collects/graphics/doc/graphics.scrbl b/collects/graphics/scribblings/graphics.scrbl similarity index 100% rename from collects/graphics/doc/graphics.scrbl rename to collects/graphics/scribblings/graphics.scrbl diff --git a/collects/graphics/doc/info.ss b/collects/graphics/scribblings/info.ss similarity index 100% rename from collects/graphics/doc/info.ss rename to collects/graphics/scribblings/info.ss diff --git a/collects/mrlib/doc/aligned-pasteboard/aligned-editor-canvas-class.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/aligned-editor-canvas-class.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/aligned-editor-canvas-class.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/aligned-editor-canvas-class.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/aligned-editor-snip-class.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/aligned-editor-snip-class.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/aligned-editor-snip-class.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/aligned-editor-snip-class.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard-intf.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard-intf.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard-intf.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard-intf.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard-parent-intf.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard-parent-intf.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard-parent-intf.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard-parent-intf.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/aligned-pasteboard.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/aligned-pasteboard.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/common.ss b/collects/mrlib/scribblings/aligned-pasteboard/common.ss similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/common.ss rename to collects/mrlib/scribblings/aligned-pasteboard/common.ss diff --git a/collects/mrlib/doc/aligned-pasteboard/horizontal-pasteboard-class.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/horizontal-pasteboard-class.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/horizontal-pasteboard-class.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/horizontal-pasteboard-class.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/stretchable-snip-intf.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/stretchable-snip-intf.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/stretchable-snip-intf.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/stretchable-snip-intf.scrbl diff --git a/collects/mrlib/doc/aligned-pasteboard/vertical-pasteboard-class.scrbl b/collects/mrlib/scribblings/aligned-pasteboard/vertical-pasteboard-class.scrbl similarity index 100% rename from collects/mrlib/doc/aligned-pasteboard/vertical-pasteboard-class.scrbl rename to collects/mrlib/scribblings/aligned-pasteboard/vertical-pasteboard-class.scrbl diff --git a/collects/mrlib/doc/bitmap-label.scrbl b/collects/mrlib/scribblings/bitmap-label.scrbl similarity index 100% rename from collects/mrlib/doc/bitmap-label.scrbl rename to collects/mrlib/scribblings/bitmap-label.scrbl diff --git a/collects/mrlib/doc/cache-image-snip.scrbl b/collects/mrlib/scribblings/cache-image-snip.scrbl similarity index 100% rename from collects/mrlib/doc/cache-image-snip.scrbl rename to collects/mrlib/scribblings/cache-image-snip.scrbl diff --git a/collects/mrlib/doc/common.ss b/collects/mrlib/scribblings/common.ss similarity index 100% rename from collects/mrlib/doc/common.ss rename to collects/mrlib/scribblings/common.ss diff --git a/collects/mrlib/doc/gif.scrbl b/collects/mrlib/scribblings/gif.scrbl similarity index 100% rename from collects/mrlib/doc/gif.scrbl rename to collects/mrlib/scribblings/gif.scrbl diff --git a/collects/mrlib/doc/graph/common.ss b/collects/mrlib/scribblings/graph/common.ss similarity index 100% rename from collects/mrlib/doc/graph/common.ss rename to collects/mrlib/scribblings/graph/common.ss diff --git a/collects/mrlib/doc/graph/graph-pasteboard-intf.scrbl b/collects/mrlib/scribblings/graph/graph-pasteboard-intf.scrbl similarity index 100% rename from collects/mrlib/doc/graph/graph-pasteboard-intf.scrbl rename to collects/mrlib/scribblings/graph/graph-pasteboard-intf.scrbl diff --git a/collects/mrlib/doc/graph/graph-pasteboard-mixin.scrbl b/collects/mrlib/scribblings/graph/graph-pasteboard-mixin.scrbl similarity index 100% rename from collects/mrlib/doc/graph/graph-pasteboard-mixin.scrbl rename to collects/mrlib/scribblings/graph/graph-pasteboard-mixin.scrbl diff --git a/collects/mrlib/doc/graph/graph-snip-intf.scrbl b/collects/mrlib/scribblings/graph/graph-snip-intf.scrbl similarity index 100% rename from collects/mrlib/doc/graph/graph-snip-intf.scrbl rename to collects/mrlib/scribblings/graph/graph-snip-intf.scrbl diff --git a/collects/mrlib/doc/graph/graph-snip-mixin.scrbl b/collects/mrlib/scribblings/graph/graph-snip-mixin.scrbl similarity index 100% rename from collects/mrlib/doc/graph/graph-snip-mixin.scrbl rename to collects/mrlib/scribblings/graph/graph-snip-mixin.scrbl diff --git a/collects/mrlib/doc/graph/graph.scrbl b/collects/mrlib/scribblings/graph/graph.scrbl similarity index 100% rename from collects/mrlib/doc/graph/graph.scrbl rename to collects/mrlib/scribblings/graph/graph.scrbl diff --git a/collects/mrlib/doc/include-bitmap.scrbl b/collects/mrlib/scribblings/include-bitmap.scrbl similarity index 100% rename from collects/mrlib/doc/include-bitmap.scrbl rename to collects/mrlib/scribblings/include-bitmap.scrbl diff --git a/collects/mrlib/doc/info.ss b/collects/mrlib/scribblings/info.ss similarity index 100% rename from collects/mrlib/doc/info.ss rename to collects/mrlib/scribblings/info.ss diff --git a/collects/mrlib/doc/interactive-value-port.scrbl b/collects/mrlib/scribblings/interactive-value-port.scrbl similarity index 100% rename from collects/mrlib/doc/interactive-value-port.scrbl rename to collects/mrlib/scribblings/interactive-value-port.scrbl diff --git a/collects/mrlib/doc/mrlib.scrbl b/collects/mrlib/scribblings/mrlib.scrbl similarity index 100% rename from collects/mrlib/doc/mrlib.scrbl rename to collects/mrlib/scribblings/mrlib.scrbl diff --git a/collects/mrlib/doc/name-message.scrbl b/collects/mrlib/scribblings/name-message.scrbl similarity index 100% rename from collects/mrlib/doc/name-message.scrbl rename to collects/mrlib/scribblings/name-message.scrbl diff --git a/collects/mrlib/doc/path-dialog.scrbl b/collects/mrlib/scribblings/path-dialog.scrbl similarity index 100% rename from collects/mrlib/doc/path-dialog.scrbl rename to collects/mrlib/scribblings/path-dialog.scrbl diff --git a/collects/mrlib/doc/plot.scrbl b/collects/mrlib/scribblings/plot.scrbl similarity index 100% rename from collects/mrlib/doc/plot.scrbl rename to collects/mrlib/scribblings/plot.scrbl diff --git a/collects/net/doc/cgi.scrbl b/collects/net/scribblings/cgi.scrbl similarity index 100% rename from collects/net/doc/cgi.scrbl rename to collects/net/scribblings/cgi.scrbl diff --git a/collects/net/doc/common.ss b/collects/net/scribblings/common.ss similarity index 100% rename from collects/net/doc/common.ss rename to collects/net/scribblings/common.ss diff --git a/collects/net/doc/info.ss b/collects/net/scribblings/info.ss similarity index 100% rename from collects/net/doc/info.ss rename to collects/net/scribblings/info.ss diff --git a/collects/net/doc/net.scrbl b/collects/net/scribblings/net.scrbl similarity index 100% rename from collects/net/doc/net.scrbl rename to collects/net/scribblings/net.scrbl diff --git a/collects/net/doc/sendmail.scrbl b/collects/net/scribblings/sendmail.scrbl similarity index 100% rename from collects/net/doc/sendmail.scrbl rename to collects/net/scribblings/sendmail.scrbl diff --git a/collects/net/doc/sendurl.scrbl b/collects/net/scribblings/sendurl.scrbl similarity index 100% rename from collects/net/doc/sendurl.scrbl rename to collects/net/scribblings/sendurl.scrbl diff --git a/collects/net/doc/smtp.scrbl b/collects/net/scribblings/smtp.scrbl similarity index 100% rename from collects/net/doc/smtp.scrbl rename to collects/net/scribblings/smtp.scrbl diff --git a/collects/net/doc/url.scrbl b/collects/net/scribblings/url.scrbl similarity index 100% rename from collects/net/doc/url.scrbl rename to collects/net/scribblings/url.scrbl diff --git a/collects/scribblings/guide/guide.scrbl b/collects/scribblings/guide/guide.scrbl index 5face77e50..db540dde6e 100644 --- a/collects/scribblings/guide/guide.scrbl +++ b/collects/scribblings/guide/guide.scrbl @@ -118,7 +118,7 @@ executable. "top"]} describes tools for using Scheme to access libraries that are normally used by C programs. -@italic{@secref[#:doc '(lib "web-server/doc/web-server.scrbl") +@italic{@secref[#:doc '(lib "web-server/scribblings/web-server.scrbl") "top"]} describes the PLT Scheme web server, which supports servlets implemented in Scheme. diff --git a/collects/web-server/scribblings/configuration.scrbl b/collects/web-server/scribblings/configuration.scrbl new file mode 100644 index 0000000000..80d61d8683 --- /dev/null +++ b/collects/web-server/scribblings/configuration.scrbl @@ -0,0 +1,260 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "configuration" + #:style 'toc]{Configuration} + +There are a number of libraries and utilities useful for +configuring the @web-server . + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@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] + +@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 . +The contracts on this structure influence the valid types of values in +the configuration table S-expression file format described in +@secref["configuration-table.ss"]. + +@defstruct[configuration-table + ([port port-number?] + [max-waiting natural-number/c] + [initial-connection-timeout natural-number/c] + [default-host host-table?] + [virtual-hosts (listof (cons/c string? host-table?))])] + +@defstruct[host-table + ([indices (listof string?)] + [log-format symbol?] + [messages messages?] + [timeouts timeouts?] + [paths paths?])] + +@defstruct[host + ([indices (listof string?)] + [log-format symbol?] + [log-path (or/c false/c path-string?)] + [passwords (or/c false/c path-string?)] + [responders responders?] + [timeouts timeouts?] + [paths paths?])] + +@defstruct[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 (request? . -> . response?)] + [protocol (url? . -> . response?)] + [collect-garbage (-> response?)])] + +@defstruct[messages + ([servlet string?] + [authentication string?] + [servlets-refreshed string?] + [passwords-refreshed string?] + [file-not-found string?] + [protocol string?] + [collect-garbage string?])] + +@defstruct[timeouts + ([default-servlet number?] + [password number?] + [servlet-connection number?] + [file-per-byte number?] + [file-base number?])] + +@defstruct[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?)])] + +@; ------------------------------------------------------------ +@section[#:tag "configuration-table.ss"]{Configuration Table} +@require[(for-label 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] +structures. + +@defthing[default-configuration-table-path path?]{The default configuration table S-expression file.} + +@defproc[(sexpr->configuration-table (sexpr list?)) + configuration-table?]{ + This function converts a @scheme[configuration-table] from an S-expression. +} + +@defproc[(configuration-table->sexpr (ctable configuration-table?)) + list?]{ + This function converts a @scheme[configuration-table] to an S-expression. +} + +@schemeblock[ +`((port ,integer?) + (max-waiting ,integer?) + (initial-connection-timeout ,integer?) + (default-host-table + ,host-table-sexpr?) + (virtual-host-table + (list ,symbol? ,host-table-sexpr?) + ...))] + +where a @scheme[host-table-sexpr] is: + +@; XXX Allowable log-formats? +@; XXX Where the paths are resolved relative to +@schemeblock[ +`(host-table + (default-indices ,string? ...) + (log-format ,symbol?) + (messages + (servlet-message ,path-string?) + (authentication-message ,path-string?) + (servlets-refreshed ,path-string?) + (passwords-refreshed ,path-string?) + (file-not-found-message ,path-string?) + (protocol-message ,path-string?) + (collect-garbage ,path-string?)) + (timeouts + (default-servlet-timeout ,integer?) + (password-connection-timeout ,integer?) + (servlet-connection-timeout ,integer?) + (file-per-byte-connection-timeout ,integer?) + (file-base-connection-timeout ,integer)) + (paths + (configuration-root ,path-string?) + (host-root ,path-string?) + (log-file-path ,path-string?) + (file-root ,path-string?) + (servlet-root ,path-string?) + (mime-types ,path-string?) + (password-authentication ,path-string?)))] + +@defproc[(read-configuration-table (path path-string?)) + configuration-table?]{ +This function reads a @scheme[configuration-table] from @scheme[path]. +} + +@defproc[(write-configuration-table (ctable configuration-table?) (path path-string?)) + 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] + +@filepath{configuration/namespace.ss} provides a function to help create the +@scheme[make-servlet-namespace] procedure needed by the @scheme[make] functions +of @filepath{dispatchers/dispatch-servlets.ss} and @filepath{dispatchers/dispatch-lang.ss}. + +@; XXX Define make-servlet-namespace? +@; XXX Use actual keyword argument syntax + +@defproc[(make-make-servlet-namespace (#:to-be-copied-module-specs to-be-copied-module-specs (listof module-spec?))) + (key-> ([additional-specs (listof module-spec?)]) + namespace?)]{ +This function creates a function that when called will construct a new @scheme[namespace] that +has all the modules from @scheme[to-be-copied-module-specs] and @scheme[additional-specs], as well +as @scheme[mzscheme] and @scheme[(lib "mred.ss" "mred")], provided they are already attached +to the @scheme[(current-namespace)] of the call-site. + +Example: +@schemeblock[ + (make-make-servlet-namespace + #:to-be-copied-module-specs `((lib "database.ss" "my-module"))) + ] +} + +@subsection{Why this is useful} + +A different namespace is needed for each servlet, so that if servlet A and servlet B both use +a stateful module C, they will be isolated from one another. We see the @web-server as +an operating system for servlets, so we inherit the isolation requirement on operating systems. + +However, there are some modules which must be shared. If they were not, then structures cannot +be passed from the @web-server to the servlets, due to a subtlety in the way MzScheme +implements structures. + +Since, on occasion, a user will actually wanted servlets A and B to interact through module C. +A custom @scheme[make-servlet-namespace] can be created, through this procedure, that attaches +module C to all servlet namespaces. Through other means (see @secref["dispatchers"]) different sets +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] + +@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 +turn the paths given in the @scheme[configuration-table] into responders for the associated circumstance. + +@defproc[(file-response (http-code natural-number/c) (short-version string?) (text-file string?) (header header?) ...) + response?]{ + Generates a @scheme[response/full] with the given @scheme[http-code] and @scheme[short-version] +as the corresponding fields; with the content of the @scheme[text-file] as the body; and, with +the @scheme[header]s as, you guessed it, headers. +} + +@defproc[(servlet-loading-responder (url url?) (exn any/c)) + response?]{ + Prints the @scheme[exn] to standard output and responds with a "Servlet didn't load." +message. +} + +@defproc[(gen-servlet-not-found (file path-string?)) + ((url url?) . -> . response?)]{ + Returns a function that generates a standard "Servlet not found." error with content from @scheme[file]. +} + +@defproc[(gen-servlet-responder (file path-string?)) + ((url url?) (exn any/c) . -> . response?)]{ + Prints the @scheme[exn] to standard output and responds with a "Servlet error." message with content from @scheme[file]. +} + +@defproc[(gen-servlets-refreshed (file path-string?)) + (-> response?)]{ + Returns a function that generates a standard "Servlet cache refreshed." message with content from @scheme[file]. +} + +@defproc[(gen-passwords-refreshed (file path-string?)) + (-> response?)]{ + Returns a function that generates a standard "Passwords refreshed." message with content from @scheme[file]. +} + +@defproc[(gen-authentication-responder (file path-string?)) + ((url url?) (header header?) . -> . response?)]{ + Returns a function that generates an authentication failure error with content from @scheme[file] and +@scheme[header] as the HTTP header. +} + +@defproc[(gen-protocol-responder (file path-string?)) + ((url url?) . -> . response?)]{ + Returns a function that generates a "Malformed request" error with content from @scheme[file]. +} + +@defproc[(gen-file-not-found-responder (file path-string?)) + ((req request?) . -> . response?)]{ + Returns a function that generates a standard "File not found" error with content from @scheme[file]. +} + +@defproc[(gen-collect-garbage-responder (file path-string?)) + (-> response?)]{ + Returns a function that generates a standard "Garbage collection run" message with content from @scheme[file]. +} diff --git a/collects/web-server/scribblings/dispatchers.scrbl b/collects/web-server/scribblings/dispatchers.scrbl new file mode 100644 index 0000000000..c7f11dd0a7 --- /dev/null +++ b/collects/web-server/scribblings/dispatchers.scrbl @@ -0,0 +1,376 @@ +#lang scribble/doc +@(require "web-server.ss" + (for-syntax scheme/base)) + +@(define-syntax (a-dispatcher stx) + (syntax-case stx () + [(_ lib-name lib-desc . rest) + ;; This macro plays a standard trick for limiting the scope of + ;; `require'd bindings: it puts the require and the scope of the + ;; require into a macro, which introduces both together + #'(begin + (define-syntax-rule (intro) + ((... ...) + (begin + (require (for-label lib-name)) + (defmodule lib-name + "The " (schememodname lib-name) " module " lib-desc) + . rest))) + (intro))])) + +@title[#:tag "dispatchers" + #:style 'toc]{Dispatchers} + +The @web-server is really just a particular configuration of a +dispatching server. There are a number of dispatchers that are defined +to support the @web-server . Other dispatching servers, or variants +of the @web-server , may find these useful. In particular, if you want +a peculiar processing pipeline for your @web-server installation, this +documentation will be useful. + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@section[#:tag "dispatch.ss"]{General} +@require[(for-label web-server/dispatchers/dispatch)] + +@defmodule[web-server/dispatchers/dispatch] + +@filepath{dispatchers/dispatch.ss} provides a few functions for dispatchers in general. + +@defthing[dispatcher? contract?]{ + Equivalent to @scheme[(connection? request? . -> . void)]. +} + +@defproc[(dispatcher-interface-version? (any any/c)) boolean?]{ + Returns @scheme[#t] if @scheme[any] is @scheme['v1]. Returns @scheme[#f] otherwise. +} + +@defstruct[exn:dispatcher ()]{ + An exception thrown to indicate that a dispatcher does not apply to a particular + request. +} + +@defproc[(next-dispatcher) void]{ + Raises a @scheme[exn:dispatcher] +} + +As the @scheme[dispatcher?] contract suggests, a dispatcher is a function that takes a connection +and request object and does something to them. Mostly likely it will generate +some response and output it on the connection, but it may do something +different. For example, it may apply some test to the request object, perhaps +checking for a valid source IP address, and error if the test is not passed, and call @scheme[next-dispatcher] +otherwise. + +Consider the following example dispatcher, that captures the essence of URL rewriting: +@schemeblock[ + (code:comment "(url? -> url?) dispatcher? -> dispatcher?") + (lambda (rule inner) + (lambda (conn req) + (code:comment "Call the inner dispatcher...") + (inner conn + (code:comment "with a new request object...") + (copy-struct request req + (code:comment "with a new URL!") + [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] + +@filepath{dispatchers/filesystem-map.ss} provides a means of mapping +URLs to paths on the filesystem. + +@defthing[url-path? contract?]{ + This contract is equivalent to @scheme[((url?) . ->* . (path? (listof path-element?)))]. + The returned @scheme[path?] is the path on disk. The list is the list of + path elements that correspond to the path of the URL.} + +@defproc[(make-url->path (base path?)) + url-path?]{ + The @scheme[url-path?] returned by this procedure considers the root + URL to be @scheme[base]. It ensures that @scheme[".."]s in the URL + do not escape the @scheme[base] and removes them silently otherwise.} + +@defproc[(make-url->valid-path (url->path url->path?)) + url->path?]{ + Runs the underlying @scheme[url->path], but only returns if the path + refers to a file that actually exists. If it is does not, then the suffix + elements of the URL are removed until a file is found. If this never occurs, + then an error is thrown. + + This is primarily useful for dispatchers that allow path information after + the name of a service to be used for data, but where the service is represented + by a file. The most prominent example is obviously servlets.} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-sequencer.ss"]{Sequencing} +@a-dispatcher[web-server/dispatchers/dispatch-sequencer + @elem{defines a dispatcher constructor + that invokes a sequence of dispatchers until one applies.}]{ + +@defproc[(make (dispatcher dispatcher?) ...) + dispatcher?]{ + Invokes each @scheme[dispatcher], invoking the next if the first + calls @scheme[next-dispatcher]. If no @scheme[dispatcher] applies, + then it calls @scheme[next-dispatcher] itself. +}} + +@; XXX Kind of timeout that is proportional to bindings +@; ------------------------------------------------------------ +@section[#:tag "dispatch-timeout.ss"]{Timeouts} +@a-dispatcher[web-server/dispatchers/dispatch-timeout + @elem{defines a dispatcher constructor + that changes the timeout on the connection and calls the next + dispatcher.}]{ + +@defproc[(make [new-timeout integer?]) + dispatcher?]{ + Changes the timeout on the connection with @scheme[adjust-connection-timeout!] + called with @scheme[new-timeout]. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-lift.ss"]{Lifting Procedures} +@a-dispatcher[web-server/dispatchers/dispatch-lift + @elem{defines a dispatcher constructor.}]{ + +@defproc[(make (proc (request? . -> . response?))) + dispatcher?]{ + Constructs a dispatcher that calls @scheme[proc] on the request + object, and outputs the response to the connection. +}} + +@; XXX Change filtering to take predicate, rather than regexp +@; ------------------------------------------------------------ +@section[#:tag "dispatch-filter.ss"]{Filtering Requests} +@a-dispatcher[web-server/dispatchers/dispatch-filter + @elem{defines a dispatcher constructor + that calls an underlying dispatcher + with all requests that pass a predicate.}]{ + +@defproc[(make (regex regexp?) (inner dispatcher?)) + dispatcher?]{ + Calls @scheme[inner] if the URL path of the request, converted to + a string, matches @scheme[regex]. Otherwise, calls @scheme[next-dispatcher]. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-pathprocedure.ss"]{Procedure Invocation upon Request} +@a-dispatcher[web-server/dispatchers/dispatch-pathprocedure + @elem{defines a dispatcher constructor + for invoking a particular procedure when a request is given to a particular + URL path.}]{ + +@defproc[(make (path string?) (proc (request? . -> . response?))) + dispatcher?]{ + Checks if the request URL path as a string is equal to @scheme[path] + and if so, calls @scheme[proc] for a response. +} + +This is used in the standard @web-server pipeline to provide +a URL that refreshes the password file, servlet cache, etc.} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-log.ss"]{Logging} +@a-dispatcher[web-server/dispatchers/dispatch-log + @elem{defines a dispatcher constructor + for transparent logging of requests.}]{ + +@defthing[format-req/c contract?]{ + Equivalent to @scheme[(request? . -> . string?)]. +} + +@defthing[paren-format format-req/c]{ + Formats a request by: + @schemeblock[ + (format "~s~n" + (list 'from (request-client-ip req) + 'to (request-host-ip req) + 'for (url->string (request-uri req)) 'at + (date->string (seconds->date (current-seconds)) #t))) + ]} + +@defthing[extended-format format-req/c]{ + Formats a request by: + @schemeblock[ + (format "~s~n" + `((client-ip ,(request-client-ip req)) + (host-ip ,(request-host-ip req)) + (referer ,(let ([R (headers-assq* #"Referer" (request-headers/raw req))]) + (if R + (header-value R) + #f))) + (uri ,(url->string (request-uri req))) + (time ,(current-seconds)))) + ]} + +@defthing[apache-default-format format-req/c]{ + Formats a request like Apache's default. +} + +@defproc[(log-format->format [id symbol?]) + format-req/c]{ + Maps @scheme['parenthesized-default] to @scheme[paren-format], + @scheme['extended] to @scheme[extended-format], and + @scheme['apache-default] to @scheme[apache-default-format]. +} + +@defproc[(make [#:format format format-req/c paren-format] + [#:log-path log-path path-string? "log"]) + dispatcher?]{ + Logs requests to @scheme[log-path] by using @scheme[format] to format the requests. + Then invokes @scheme[next-dispatcher]. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-passwords.ss"]{Password Protection} +@a-dispatcher[web-server/dispatchers/dispatch-passwords + @elem{defines a dispatcher constructor + that performs HTTP Basic authentication filtering.}]{ + +@defproc[(make [#:password-file password-file path-string? "passwords"] + [#:authentication-responder + authentication-responder + ((url url?) (header (cons/c symbol? string?)) . -> . response?) + (gen-authentication-responder "forbidden.html")]) + (values (-> void) + dispatcher?)]{ + The first returned value is a procedure that refreshes the password + file used by the dispatcher. + + The dispatcher that is returned does the following: + Checks if the request contains Basic authentication credentials, and that + they are included in @scheme[password-file]. If they are not, + @scheme[authentication-responder] is called with a @scheme[header] that + requests credentials. If they are, then @scheme[next-dispatcher] is + invoked. + + @; XXX Separate out password-file work + @scheme[password-file] is parsed as: + @schemeblock[(list ([domain : string?] + [path : string-regexp?] + (list [user : symbol?] + [pass : string?]) + ...) + ...)] + For example: + @schemeblock['(("secret stuff" "/secret(/.*)?" (bubba "bbq") (|Billy| "BoB")))] +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-host.ss"]{Virtual Hosts} +@a-dispatcher[web-server/dispatchers/dispatch-host + @elem{defines a dispatcher constructor + that calls a different dispatcher based upon the host requested.}]{ + +@defproc[(make (lookup-dispatcher (symbol? . -> . dispatcher?))) + dispatcher?]{ + Extracts a host from the URL requested, or the Host HTTP header, + calls @scheme[lookup-dispatcher] with the host, and invokes the + returned dispatcher. If no host can be extracted, then @scheme['none] + is used. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-files.ss"]{Serving Files} +@a-dispatcher[web-server/dispatchers/dispatch-files + @elem{allows files to be served. + It defines a dispatcher construction procedure.}]{ + +@defproc[(make [#:url->path url->path url->path?] + [#:path->mime-type path->mime-type (path? . -> . bytes?) (lambda (path) TEXT/HTML-MIME-TYPE)] + [#:indices indices (listof string?) (list "index.html" "index.htm")]) + dispatcher?]{ + Uses @scheme[url->path] to extract a path from the URL in the request + object. If this path does not exist, then the dispatcher does not apply. + If the path is a directory, then the @scheme[indices] are checked in order + for an index file to serve. In that case, or in the case of a path that is + a file already, @scheme[path->mime-type] is consulted for the MIME + Type of the path. The file is then + streamed out the connection object. + + This dispatcher supports HTTP Range GET requests and HEAD requests.}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-servlets.ss"]{Serving Scheme Servlets} +@a-dispatcher[web-server/dispatchers/dispatch-servlets + @elem{defines a dispatcher constructor + that runs servlets written in Scheme.}]{ + +@; XXX Remove config:scripts +@defproc[(make [config:scripts (box/c cache-table?)] + [#:url->path url->path url->path?] + [#:make-servlet-namespace + make-servlet-namespace + make-servlet-namespace? + (make-make-servlet-namespace)] + [#:responders-servlet-loading + responders-servlet-loading + ((url url?) (exn any/c) . -> . response?) + servlet-loading-responder] + [#:responders-servlet + responders-servlet + ((url url?) (exn any/c) . -> . response?) + (gen-servlet-responder "servlet-error.html")] + [#:timeouts-default-servlet + timeouts-default-servlet + integer? + 30]) + (values (-> void) + dispatcher?)]{ + The first returned value is a procedure that refreshes the servlet + code cache. + + The dispatcher does the following: + If the request URL contains a continuation reference, then it is invoked with the + request. Otherwise, @scheme[url->path] is used to resolve the URL to a path. + The path is evaluated as a module, in a namespace constructed by @scheme[make-servlet-namespace]. + If this fails then @scheme[responders-servlet-loading] is used to format a response + with the exception. If it succeeds, then @scheme[start] export of the module is invoked. + If there is an error when a servlet is invoked, then @scheme[responders-servlet] is + used to format a response with the exception. + + Servlets that do not specify timeouts are given timeouts according to @scheme[timeouts-default-servlet]. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-lang.ss"]{Serving Web Language Servlets} +@a-dispatcher[web-server/dispatchers/dispatch-lang + @elem{defines a dispatcher constructor + that runs servlets written in the Web Language.}]{ + +@defproc[(make [#:url->path url->path url->path?] + [#:make-servlet-namespace make-servlet-namespace + make-servlet-namespace? + (make-make-servlet-namespace)] + [#:responders-servlet-loading responders-servlet-loading servlet-loading-responder] + [#:responders-servlet responders-servlet (gen-servlet-responder "servlet-error.html")]) + dispatcher?]{ + If the request URL contains a serialized continuation, then it is invoked with the + request. Otherwise, @scheme[url->path] is used to resolve the URL to a path. + The path is evaluated as a module, in a namespace constructed by @scheme[make-servlet-namespace]. + If this fails then @scheme[responders-servlet-loading] is used to format a response + with the exception. If it succeeds, then @scheme[start] export of the module is invoked. + If there is an error when a servlet is invoked, then @scheme[responders-servlet] is + used to format a response with the exception. +}} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-stat.ss"]{Statistics} +@a-dispatcher[web-server/dispatchers/dispatch-stat + @elem{provides services related to performance + statistics.}]{ + +@defproc[(make-gc-thread [time integer?]) + thread?]{ + Starts a thread that calls @scheme[(collect-garbage)] every @scheme[time] seconds. +} + +@defproc[(make) + dispatcher?]{ + Returns a dispatcher that prints memory usage on every request. +}} diff --git a/collects/web-server/scribblings/dummy-language-servlet.ss b/collects/web-server/scribblings/dummy-language-servlet.ss new file mode 100644 index 0000000000..95ce4bd630 --- /dev/null +++ b/collects/web-server/scribblings/dummy-language-servlet.ss @@ -0,0 +1,6 @@ +#lang scheme/base + +(define start #f) + +(provide (all-defined-out)) + diff --git a/collects/web-server/scribblings/dummy-servlet.ss b/collects/web-server/scribblings/dummy-servlet.ss new file mode 100644 index 0000000000..f4e3347977 --- /dev/null +++ b/collects/web-server/scribblings/dummy-servlet.ss @@ -0,0 +1,9 @@ +#lang scheme/base + +(define interface-version #f) +(define timeout #f) +(define start #f) +(define manager #f) + +(provide (all-defined-out)) + diff --git a/collects/web-server/scribblings/faq.scrbl b/collects/web-server/scribblings/faq.scrbl new file mode 100644 index 0000000000..0f0053cde1 --- /dev/null +++ b/collects/web-server/scribblings/faq.scrbl @@ -0,0 +1,13 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title{Troubleshooting} + +@section{General} + +@subsection{IE ignores my CSS or behaves strange in other ways} + +In quirks mode, IE does not parse your page as XML, in particular it will not recognize many instances of +"empty tag shorthand", e.g. "", whereas the @web-server uses @scheme[(lib "xml.ss" "xml")] +to format XML, which uses empty tag shorthand by default. You can change the default with the @scheme[empty-tag-shorthand] +parameter: @scheme[(empty-tag-shorthand 'never)]. diff --git a/collects/web-server/scribblings/info.ss b/collects/web-server/scribblings/info.ss new file mode 100644 index 0000000000..839b578989 --- /dev/null +++ b/collects/web-server/scribblings/info.ss @@ -0,0 +1,3 @@ +(module info setup/infotab + (define name "Web Server documentation")) + diff --git a/collects/web-server/scribblings/lang.scrbl b/collects/web-server/scribblings/lang.scrbl new file mode 100644 index 0000000000..626110c749 --- /dev/null +++ b/collects/web-server/scribblings/lang.scrbl @@ -0,0 +1,292 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "lang" + #:style 'toc]{Web Language Servlets} + +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. + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@section[#:tag "lang-servlets"]{Definition} +@require[(for-label "dummy-language-servlet.ss")] ; to give a binding context + +@declare-exporting[web-server/scribblings/dummy-language-servlet] + +A @defterm{Web language servlet} is a module written in the +@scheme[(lib "lang.ss" "web-server")] module language. It should provide +the following identifier: + +@defproc[(start [initial-request request?]) + response?]{ + This function is called when this servlet is invoked. + The argument is the HTTP request that initiated the servlet. +} + +@; ------------------------------------------------------------ +@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[(lib "url.ss" "net")], @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. + +@defproc[(send/suspend/url [response-generator (url? . -> . response?)]) + request?]{ + Captures the current continuation. Serializes it and stuffs it into + a URL. Calls @scheme[response-generator] with this URL and delivers + the response to the client. If the URL is invoked + the request is returned to this continuation. +} + +@defproc[(send/suspend/hidden [response-generator (url? xexpr? . -> . response?)]) + request?]{ + Captures the current continuation. Serializes it and generates an INPUT + form that includes the serialization as a hidden form. + Calls @scheme[response-generator] with this URL and form field and delivers + the response to the client. If the URL is invoked with form data containing + the hidden form, + the request is returned to this continuation. + + Note: The continuation is NOT stuffed. +} + +@defproc[(embed-proc/url [k-url url?] + [proc (request? . -> . any/c)]) + url?]{ + Serializes and stuffs @scheme[proc] into @scheme[k-url]. For use with + @scheme[extract-proc/url]. +} + +@defproc[(extract-proc/url [req request?]) + any/c]{ + Inspects the URL of @scheme[req] and attempts to extract the procedure + embedded with @scheme[embed-proc/url]. If successful, it is invoked with + @scheme[req] as an argument. +} + +@; ------------------------------------------------------------ +@section[#:tag "lang/stuff-url.ss"]{Stuff URL} +@require[(for-label 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 +hard-coded behavior, but we hope to make it more flexible in +the future. + +@defproc[(stuff-url [v serializable?] + [u url?]) + url?]{ + Serializes @scheme[v] and computes the MD5 of the serialized + representation. The serialization of @scheme[v] is written to + @filepath{$HOME/.urls/M} where `M' is the MD5. `M' is then + placed in @scheme[u] as a URL param. +} + +@defproc[(stuffed-url? [u url?]) + boolean?]{ + Checks if @scheme[u] appears to be produced by @scheme[stuff-url]. +} + +@defproc[(unstuff-url [u url?]) + serializable?]{ + Extracts the value previously serialized into @scheme[u] by @scheme[stuff-url]. +} + +In the future, we will offer the facilities to: +@itemize[ + @item{Optionally use the content-addressed storage.} + @item{Use different hashing algorithms for the CAS.} + @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[send/suspend/dispatch] and @scheme[redirect/get] as +@schememodname[web-server/servlet/web], except they use +@scheme[embed-proc/url] plus @scheme[extract-proc/url] and +@scheme[send/suspend/url], respectively.} + +@deftogether[( +@defform[(send/suspend/dispatch response-proc-expr)] +@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].} diff --git a/collects/web-server/scribblings/managers.scrbl b/collects/web-server/scribblings/managers.scrbl new file mode 100644 index 0000000000..3c4e45ad39 --- /dev/null +++ b/collects/web-server/scribblings/managers.scrbl @@ -0,0 +1,160 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "managers" + #:style 'toc]{Continuation Managers} + +Since Scheme servlets store their continuations on the server, they take +up memory on the server. Furthermore, garbage collection can not be used +to free this memory, because there are roots outside the system: users' +browsers, bookmarks, brains, and notebooks. Therefore, some other strategy +must be used if memory usage is to be controlled. This functionality is +pluggable through the manager interface. + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@section[#:tag "manager.ss"]{General} +@require[(for-label 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. + +@defstruct[manager ([create-instance ((-> void) . -> . number?)] + [adjust-timeout! (number? number? . -> . void)] + [clear-continuations! (number? . -> . void)] + [continuation-store! (number? any/c expiration-handler? . -> . (list/c number? number?))] + [continuation-lookup (number? number? number? . -> . any/c)])]{ + @scheme[create-instance] is called to initialize a instance, to hold the + continuations of one servlet session. It is passed + a function to call when the instance is expired. It runs the id of the + instance. + + @scheme[adjust-timeout!] is a to-be-deprecated function that takes an + instance-id and a number. It is specific to the timeout-based manager + and will be removed. + + @scheme[clear-continuations!] expires all the continuations of an instance. + + @scheme[continuation-store!] is given an instance-id, a continuation value, + and a function to include in the exception thrown if the continuation is + looked up and has been expired. The two numbers returned are a + continuation-id and a nonce. + + @scheme[continuation-lookup] finds the continuation value associated with + the instance-id, continuation-id, and nonce triple it is given. +} + +@defstruct[(exn:fail:servlet-manager:no-instance exn:fail) + ([expiration-handler expiration-handler?])]{ + This exception should be thrown by a manager when an instance is looked + up that does not exist. +} + +@defstruct[(exn:fail:servlet-manager:no-continuation exn:fail) + ([expiration-handler expiration-handler?])]{ + 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] + +@filepath{managers/none.ss} defines a manager constructor: + +@defproc[(create-none-manager (instance-expiration-handler expiration-handler?)) + manager?]{ + This manager does not actually store any continuation or instance data. + You could use it if you know your servlet does not use the continuation + capturing functions and want the server to not allocate meta-data + structures for each instance. +} + +If you are considering using this manager, also consider using the +Web Language. (See @secref["lang"].) + +@; ------------------------------------------------------------ +@section[#:tag "timeouts.ss"]{Timeouts} +@require[(for-label web-server/managers/timeouts)] + +@defmodule[web-server/managers/timeouts] + +@filepath{managers/timeouts.ss} defines a manager constructor: + +@defproc[(create-timeout-manager [instance-exp-handler expiration-handler?] + [instance-timeout number?] + [continuation-timeout number?]) + manager?]{ + Instances managed by this manager will be expired @scheme[instance-timeout] + seconds after the last time it is accessed. If an expired instance is + looked up, the @scheme[exn:fail:servlet-manager:no-instance] exception + is thrown with @scheme[instance-exp-handler] as the expiration handler. + + Continuations managed by this manager will be expired @scheme[continuation-timeout] + seconds after the last time it is accessed. If an expired continuation is looked + up, the @scheme[exn:fail:servlet-manager:no-continuation] exception + is thrown with @scheme[instance-exp-handler] as the expiration handler, if + no expiration-handler was passed to @scheme[continuation-store!]. + + @scheme[adjust-timeout!] corresponds to @scheme[reset-timer!] on the timer + responsible for the servlet instance. +} + +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] + +@filepath{managers/lru.ss} defines a manager constructor: + +@defproc[(create-LRU-manager + [instance-expiration-handler expiration-handler?] + [check-interval integer?] + [collect-interval integer?] + [collect? (-> boolean?)] + [#:initial-count initial-count integer? 1] + [#:inform-p inform-p (integer? . -> . void) (lambda _ (void))]) + manager?]{ + Instances managed by this manager will be expired if there are no + continuations associated with them, after the instance is unlocked. + If an expired instance is looked up, the + @scheme[exn:fail:servlet-manager:no-instance] exception + is thrown with @scheme[instance-exp-handler] as the expiration handler. + + Continuations managed by this manager are given a "Life Count" of + @scheme[initial-count] initially. If an expired continuation is looked + up, the @scheme[exn:fail:servlet-manager:no-continuation] exception + is thrown with @scheme[instance-exp-handler] as the expiration handler, if + no expiration-handler was passed to @scheme[continuation-store!]. + + Every @scheme[check-interval] seconds @scheme[collect?] is called to determine + if the collection routine should be run. Every @scheme[collect-interval] seconds + the collection routine is run. + + Every time the collection routine runs, the "Life Count" of every + continuation is decremented by @scheme[1]. If a continuation's count + reaches @scheme[0], it is expired. The @scheme[inform-p] function + is called if any continuations are expired, with the number of + continuations expired. +} + +The recommended use of this manager is to pass, as @scheme[collect?], a +function that checks the memory usage of the system, through +@scheme[current-memory-use]. Then, @scheme[collect-interval] should be sufficiently +large compared to @scheme[check-interval]. This way, if the load on the server +spikes---as indicated by memory usage---the server will quickly expire +continuations, until the memory is back under control. If the load +stays low, it will still efficiently expire old continuations. + +With @href-link["http://continue.cs.brown.edu/" "Continue"], we went from needing to restart the server a few times +a week and having many complaints under load, to not having these complaints +and not needing to restart the server for performance reasons. diff --git a/collects/web-server/scribblings/private.scrbl b/collects/web-server/scribblings/private.scrbl new file mode 100644 index 0000000000..c2a4c245f2 --- /dev/null +++ b/collects/web-server/scribblings/private.scrbl @@ -0,0 +1,422 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "private" + #:style 'toc]{Internal} + +The @web-server is a complicated piece of software and as a result, +defines a number of interesting and independently useful sub-components. +Some of these are documented here. + +@local-table-of-contents[] + + +@; ------------------------------------------------------------ +@section[#:tag "timer.ss"]{Timers} +@require[(for-label 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. + +@defstruct[timer ([evt evt?] + [expire-seconds number?] + [action (-> void)])]{ + @scheme[evt] is an @scheme[alarm-evt] that is ready at @scheme[expire-seconds]. + @scheme[action] should be called when this @scheme[evt] is ready. +} + +@defproc[(start-timer-manager [cust custodian?]) + void]{ + Handles the execution and management of timers. Resources are charged to + @scheme[cust]. +} + +@defproc[(start-timer [s number?] + [action (-> void)]) + timer?]{ + Registers a timer that runs @scheme[action] after @scheme[s] seconds. +} + +@defproc[(reset-timer! [t timer?] + [s number?]) + void]{ + Changes @scheme[t] so that it will fire after @scheme[s] seconds. +} + +@defproc[(increment-timer! [t timer?] + [s number?]) + void]{ + Changes @scheme[t] so that it will fire after @scheme[s] seconds from when + it does now. +} + +@defproc[(cancel-timer! [t timer?]) + void]{ + Cancels the firing of @scheme[t] ever and frees resources used by @scheme[t]. +} + + +@; XXX Generalize +@; ------------------------------------------------------------ +@section[#:tag "connection-manager.ss"]{Connection Manager} +@require[(for-label 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 +for doing this. + +@defstruct[connection + ([timer timer?] + [i-port input-port?] [o-port output-port?] [custodian custodian?] + [close? boolean?])]{ + A connection is a pair of ports (@scheme[i-port] and @scheme[o-port]) that is + ready to close after the current job if @scheme[close?] is @scheme[#t]. Resources + associated with the connection should be allocated under @scheme[custodian]. + The connection will last until @scheme[timer] triggers. +} + +@; XXX Don't pass in parent-cust +@defproc[(start-connection-manager [parent-cust custodian?]) + void]{ + Runs the connection manager (now just the timer manager) will @scheme[parent-cust] + as the custodian. +} + +@defproc[(new-connection [timeout number?] + [i-port input-port?] + [o-port output-port?] + [cust custodian?] + [close? boolean?]) + connection?]{ + Constructs a connection with a timer with a trigger of @scheme[timeout] that calls + @scheme[kill-connection!]. +} + +@defproc[(kill-connection! [c connection?]) + void]{ + Closes the ports associated with @scheme[c], kills the timer, and shuts down + the custodian. +} + +@defproc[(adjust-connection-timeout! [c connection?] + [t number?]) + void]{ + Calls @scheme[reset-timer!] with the timer behind @scheme[c] with @scheme[t]. +} + +@; ------------------------------------------------------------ +@section[#:tag "dispatch-server-unit.ss"]{Dispatching Server} +@require[(for-label web-server/private/dispatch-server-unit)] +@require[(for-label web-server/private/dispatch-server-sig)] +@require[(for-label web-server/web-server-sig)] + +The @web-server is just a configuration of a dispatching server. +This dispatching server component is useful on its own. + +@subsection{Dispatching Server Signatures} + +@defmodule[web-server/private/dispatch-server-sig] + +The @schememodname[web-server/private/dispatch-server-sig] library +provides two signatures. + +@defsignature[dispatch-server^ ()]{ + +The @scheme[dispatch-server^] signature is an alias for +@scheme[web-server^]. + + @defproc[(serve) (-> void)]{ + Runs the server and returns a procedure that shuts down the server. + } + + @defproc[(serve-ports [ip input-port?] + [op output-port?]) + void]{ + Serves a single connection represented by the ports @scheme[ip] and + @scheme[op]. + } +} + +@defsignature[dispatch-server-config^ ()]{ + + @defthing[port port?]{Specifies the port to serve on.} + @defthing[listen-ip string?]{Passed to @scheme[tcp-accept].} + @defthing[max-waiting integer?]{Passed to @scheme[tcp-accept].} + @defthing[initial-connection-timeout integer?]{Specifies the initial timeout given to a connection.} + @defproc[(read-request [c connection?] + [p port?] + [port-addresses port-addresses?]) + any/c]{ + Defines the way the server reads requests off connections to be passed + to @scheme[dispatch]. + } + @defthing[dispatch dispatcher?]{How to handle requests.} +} + + +@subsection{Dispatching 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. + +@; XXX Talk about how threads and custodians are used. + +@defthing[dispatch-server\@ (unit/c (tcp^ dispatch-server-config^) + (dispatch-server^))]{ + Runs the dispatching server config in a very basic way, except that it uses + @secref["connection-manager.ss"] to manage connections. +} + +@; ------------------------------------------------------------ +@section[#:tag "closure.ss"]{Serializable Closures} +@require[(for-label web-server/private/closure)] +@require[(for-label web-server/private/define-closure)] + +@defmodule[web-server/private/closure] + +The defunctionalization process of the Web Language (see @secref["lang"]) +requires an explicit representation of closures that is serializable. +@filepath{private/closure.ss} is this representation. It provides: + +@defproc[(make-closure-definition-syntax [tag syntax?] + [fvars (listof identifier?)] + [proc syntax?]) + syntax?]{ + Outputs a syntax object that defines a serializable structure, + with @scheme[tag] as the tag, that represents a closure over + @scheme[fvars], that acts a procedure and when invoked calls + @scheme[proc], which is assumed to be syntax of @scheme[lambda] + or @scheme[case-lambda]. +} + +@defproc[(closure->deserialize-name [c closure?]) + symbol?]{ + Extracts the unique tag of a closure @scheme[c] +} + +These are difficult to use directly, so @filepath{private/define-closure.ss} +defines a helper form: + +@subsection[#:style 'hidden]{Define Closure} +@defmodule[web-server/private/define-closure] + +@defform[(define-closure tag formals (free-vars ...) body)]{ + Defines a closure, constructed with @scheme[make-tag] that accepts + @scheme[freevars ...], that when invoked with @scheme[formals] + executes @scheme[body]. +} + +@; XXX Example + +@; ------------------------------------------------------------ +@section[#:tag "cache-table.ss"]{Cache Table} +@require[(for-label web-server/private/cache-table)] + +@defmodule[web-server/private/cache-table] + +@filepath{private/cache-table.ss} provides a set of caching hash table +functions. + +@defproc[(make-cache-table) + cache-table?]{ + Constructs a cache-table. +} + +@defproc[(cache-table-lookup! [ct cache-table?] + [id symbol?] + [mk (-> any/c)]) + any/c]{ + Looks up @scheme[id] in @scheme[ct]. If it is not present, then @scheme[mk] is + called to construct the value and add it to @scheme[ct]. +} + +@defproc[(cache-table-clear! [ct cache-table?]) + void?]{ + Clears all entries in @scheme[ct]. +} + +@defproc[(cache-table? [v any/c]) + boolean?]{ + 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] + +@filepath{private/mime-types.ss} provides function for dealing with @filepath{mime.types} +files. + +@defproc[(read-mime-types [p path?]) + (hash-table/c symbol? bytes?)]{ + Reads the @filepath{mime.types} file from @scheme[p] and constructs a + hash table mapping extensions to MIME types. +} + +@defproc[(make-path->mime-type [p path?]) + (path? . -> . bytes?)]{ + Uses a @scheme[read-mime-types] with @scheme[p] and constructs a + function from paths to their MIME type. +} + +@; XXX Rename mod-map.ss +@; ------------------------------------------------------------ +@section[#:tag "mod-map.ss"]{Serialization Utilities} +@require[(for-label 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} +compresses the serialized representation. + +@defproc[(compress-serial [sv serialized-value?]) + compressed-serialized-value?]{ + Collapses multiple occurrences of the same module in the module + map of the serialized representation, @scheme[sv]. +} + +@defproc[(decompress-serial [csv compressed-serialized-value?]) + serialized-value?]{ + 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] + +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 +make GET requests to those URLs with more query data. So, it must be encoded +in URL params. @filepath{private/url-param.ss} provides functions for helping +with this process. + +@defproc[(insert-param [u url?] + [k string?] + [v string?]) + url?]{ + Associates @scheme[k] with @scheme[v] in the final URL param of @scheme[u], + overwritting any current binding for @scheme[k]. +} + +@defproc[(extract-param [u url?] + [k string?]) + (or/c string? false/c)]{ + Extracts the string associated with @scheme[k] in the final URL param of + @scheme[u], if there is one, returning @scheme[#f] otherwise. +} + +@; ------------------------------------------------------------ +@section[#:tag "util.ss"]{Miscellaneous Utilities} +@require[(for-label web-server/private/util)] + +@defmodule[web-server/private/util] + +There are a number of other miscellaneous utilities the @web-server +needs. They are provided by @filepath{private/util.ss}. + +@subsection{Contracts} +@defthing[port-number? contract?]{Equivalent to @scheme[(between/c 1 65535)].} +@defthing[path-element? contract?]{Equivalent to @scheme[(or/c string? path? (symbols 'up 'same))].} + +@subsection{Lists} +@defproc[(list-prefix? [l list?] + [r list?]) + boolean?]{ + True if @scheme[l] is a prefix of @scheme[r]. +} + +@subsection{URLs} + +@defproc[(url-replace-path [proc ((listof path/param?) . -> . (listof path/param?))] + [u url?]) + url?]{ + Replaces the URL path of @scheme[u] with @scheme[proc] of the former path. +} + +@; XXX Remove use or take url? +@defproc[(url-path->string [url-path (listof path/param?)]) + string?]{ + Formats @scheme[url-path] as a string with @scheme["/"] as a delimiter + and no params. +} + +@subsection{Paths} +@defproc[(explode-path* [p path?]) + (listof path-element?)]{ + Like @scheme[normalize-path], but does not resolve symlinks. +} + +@defproc[(path-without-base [base path?] + [p path?]) + (listof path-element?)]{ + Returns, as a list, the portion of @scheme[p] after @scheme[base], + assuming @scheme[base] is a prefix of @scheme[p]. +} + +@defproc[(directory-part [p path?]) + path?]{ + Returns the directory part of @scheme[p], returning @scheme[(current-directory)] + if it is relative. +} + +@defproc[(build-path-unless-absolute [base path-string?] + [p path-string?]) + path?]{ + Prepends @scheme[base] to @scheme[p], unless @scheme[p] is absolute. +} + +@defproc[(strip-prefix-ups [p (listof path-element?)]) + (listof path-element?)]{ + Removes all the prefix @scheme[".."]s from @scheme[p]. +} + +@subsection{Exceptions} + +@defproc[(pretty-print-invalid-xexpr [exn exn:invalid-xexpr?] + [v any/c]) + void]{ + Prints @scheme[v] as if it were almost an X-expression highlighting the error + according to @scheme[exn]. +} + +@; XXX Remove +@defproc[(network-error [s symbol?] + [fmt string?] + [v any/c] ...) + void]{ + Like @scheme[error], but throws a @scheme[exn:fail:network]. +} + +@defproc[(exn->string [exn (or/c exn? any/c)]) + string?]{ + Formats @scheme[exn] with @scheme[(error-display-handler)] as a string. +} + +@subsection{Strings} + +@defproc[(lowercase-symbol! [sb (or/c string? bytes?)]) + symbol?]{ + Returns @scheme[sb] as a lowercase symbol. +} + +@defproc[(read/string [s string?]) + serializable?]{ + @scheme[read]s a value from @scheme[s] and returns it. +} + +@defproc[(write/string [v serializable?]) + string?]{ + @scheme[write]s @scheme[v] to a string and returns it. +} diff --git a/collects/web-server/scribblings/running.scrbl b/collects/web-server/scribblings/running.scrbl new file mode 100644 index 0000000000..262f88f318 --- /dev/null +++ b/collects/web-server/scribblings/running.scrbl @@ -0,0 +1,80 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "run.ss" + #:style 'toc]{Running the Web Server} + +There are a number of ways to run the Web Server. The two primary ways +are through a command-line tool or through a function call. + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@section[#:tag "command-line-tools"]{Command-line Tools} + +One command-line utility is provided with the @|web-server|: + +@commandline{plt-web-server [-f -p -a ]} + +The optional file-name argument specifies the path to a +@scheme[configuration-table] S-expression (see +@secref["configuration-table.ss"].) If this is not provided, the +default configuration shipped with the server is used. The optional +port and ip-address arguments override the corresponding portions of +the @scheme[configuration-table]. + +The @scheme[configuration-table] is given to @scheme[configuration-table->web-config\@] +and used to construct a @scheme[web-config^] unit, +and is linked with the @scheme[web-server\@] unit. The resulting unit is invoked, and +the server runs until the process is killed. + +To run the web server with MrEd, use + +@commandline{mred -l- web-server/gui [-f -p -a ]} + +@; ------------------------------------------------------------ +@section[#:tag "web-server.ss"]{Functional} +@require[(for-label 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 +dispatcher. See @filepath{run.ss} for an example of such a script. + +@defproc[(serve [#:dispatch dispatch dispatcher?] + [#:tcp\@ tcp\@ tcp-unit^ raw:tcp\@] + [#:port port integer? 80] + [#:listen-ip listen-ip (or/c string? false/c) #f] + [#:max-waiting max-waiting integer? 40] + [#:initial-connection-timeout initial-connection-timeout integer? 60]) + (-> void)]{ + Constructs an appropriate @scheme[dispatch-config^], invokes the @scheme[dispatch-server\@], + and calls its @scheme[serve] function. +} + +@defproc[(serve/ports [#:dispatch dispatch dispatcher?] + [#:tcp\@ tcp\@ tcp-unit^ raw:tcp\@] + [#:ports ports (listof integer?) (list 80)] + [#:listen-ip listen-ip (or/c string? false/c) #f] + [#:max-waiting max-waiting integer? 40] + [#:initial-connection-timeout initial-connection-timeout integer? 60]) + (-> void)]{ + Calls @scheme[serve] multiple times, once for each @scheme[port], and returns + a function that shuts down all of the server instances. +} + +@defproc[(serve/ips+ports [#:dispatch dispatch dispatcher?] + [#:tcp\@ tcp\@ tcp-unit^ raw:tcp\@] + [#:ips+ports ips+ports (listof (cons/c (or/c string? false/c) (listof integer?))) (list (cons #f (list 80)))] + [#:max-waiting max-waiting integer? 40] + [#:initial-connection-timeout initial-connection-timeout integer? 60]) + (-> void)]{ + Calls @scheme[serve/ports] multiple times, once for each @scheme[ip], and returns + a function that shuts down all of the server instances. +} + +@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. +} diff --git a/collects/web-server/scribblings/servlet-env.scrbl b/collects/web-server/scribblings/servlet-env.scrbl new file mode 100644 index 0000000000..40f3d853ca --- /dev/null +++ b/collects/web-server/scribblings/servlet-env.scrbl @@ -0,0 +1,31 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "servlet-env.ss" + #:style 'toc]{Environment} +@require[(for-label web-server/servlet-env)] + +@defmodule[web-server/servlet-env] + +The @web-server provides a means of running Scheme servlets +from within DrScheme, or any other REPL. + +@filepath{servlet-env.ss} provides the servlet API from @filepath{servlet.ss} +as well as the following: + +@defthing[send-url (parameter/c ([url string?] [separate-window? boolean?] . -> . void))]{ + Should open @scheme[url]. In another window if @scheme[separate-window?] is true. + By default this is from @scheme[(lib "sendurl.ss" "net")]. +} + +@defform*[[(on-web servlet-expr) + (on-web port servlet-expr)]]{ + + The first form expands to @scheme[(on-web 8000 servlet-expr)]. + + Constructs a small servlet, where the body of the @scheme[start] procedure is + @scheme[servlet-expr], runs the @web-server on port @scheme[port], and calls + @scheme[send-url] with a URL for the constructed servlet. The call blocks until the + servlet finishes its computation, i.e. @scheme[servlet-expr] is evaluated, and + returns its result. @scheme[servlet-expr] may use the entire Scheme servlet API. +} diff --git a/collects/web-server/scribblings/servlet.scrbl b/collects/web-server/scribblings/servlet.scrbl new file mode 100644 index 0000000000..ceefac877c --- /dev/null +++ b/collects/web-server/scribblings/servlet.scrbl @@ -0,0 +1,429 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "servlet" + #:style 'toc]{Scheme Servlets} + +The @web-server allows servlets to be written in Scheme. It +provides the supporting API, described below, for the construction +of these servlets. This API is provided by @filepath{servlet.ss}. + +@local-table-of-contents[] + +@; ------------------------------------------------------------ +@section[#:tag "module-servlets"]{Definition} +@require[(for-label "dummy-servlet.ss")] ; to give a binding context + +@declare-exporting[web-server/scribblings/dummy-servlet] + +A @defterm{servlet} is a module that provides the following: + +@defthing[interface-version (one-of/c 'v1 'v2)]{ + 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. +} + +@; ------------------------------------------------------------ +@section[#:tag "servlet-structs.ss"]{Contracts} +@require[(for-label web-server/servlet/servlet-structs)] + +@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?].} + +@defthing[response-generator? contract?]{Equivalent to @scheme[(k-url? . -> . response?)].} + +@defthing[url-transform? contract?]{Equivalent to @scheme[(k-url? . -> . k-url?)].} + +@defthing[expiration-handler? contract?]{Equivalent to @scheme[(or/c false/c (request? . -> . response?))].} + +@defthing[embed/url? contract?]{Equivalent to @scheme[(((request? . -> . any/c)) (expiration-handler?) . opt-> . string?)].} + +@; ------------------------------------------------------------ +@section[#:tag "request-structs.ss"]{HTTP Requests} +@require[(for-label web-server/private/request-structs)] + +@defmodule[web-server/private/request-structs] + +@; XXX Create http sub-directory +@; XXX Have this include read-request and write-response +@filepath{private/request-structs.ss} provides a number of structures and functions +related to HTTP request data structures. + +@defstruct[header ([field bytes?] + [value bytes?])]{ + Represents a header of @scheme[field] to @scheme[value]. +} + +@defproc[(headers-assq [id bytes?] [heads (listof header?)]) + (or/c false/c header?)]{ + Returns the header with a field equal to @scheme[id] from @scheme[heads] or @scheme[#f]. +} + +@defproc[(headers-assq* [id bytes?] [heads (listof header?)]) + (or/c false/c header?)]{ + Returns the header with a field case-insensitively equal to @scheme[id] from @scheme[heads] or @scheme[#f]. +} + +@defstruct[binding ([id bytes?])]{Represents a binding of @scheme[id].} + +@defstruct[(binding:form binding) ([value bytes?])]{ + Represents a form binding of @scheme[id] to @scheme[value]. +} + +@defstruct[(binding:file binding) ([filename bytes?] + [content bytes?])]{ + Represents the uploading of the file @scheme[filename] with the id @scheme[id] + and the content @scheme[content]. +} + +@defproc[(bindings-assq [binds (listof binding?)]) + (or/c false/c binding?)]{ + Returns the binding with an id equal to @scheme[id] from @scheme[binds] or @scheme[#f]. +} + +@defstruct[request ([method symbol?] + [uri url?] + [headers/raw (listof header?)] + [bindings/raw (listof binding?)] + [post-data/raw (or/c false/c bytes?)] + [host-ip string?] + [host-port number?] + [client-ip string?])]{ + An HTTP @scheme[method] request to @scheme[uri] from @scheme[client-ip] + to the server at @scheme[host-ip]:@scheme[host-port] with @scheme[headers/raw] + headers, @scheme[bindings/raw] GET and POST queries and @scheme[post-data/raw] + POST data. +} + +@; ------------------------------------------------------------ +@section[#:tag "bindings.ss"]{Request Bindings} +@require[(for-label web-server/servlet/bindings)] + +@defmodule[web-server/servlet/bindings] + +@filepath{servlet/bindings.ss} provides a number of helper functions +for accessing request bindings. + +@defproc[(request-bindings [req request?]) + (listof (or/c (cons/c symbol? string?) + (cons/c symbol? bytes?)))]{ + Translates the @scheme[request-bindings/raw] of @scheme[req] by + interpreting @scheme[bytes?] as @scheme[string?]s, except in the case + of @scheme[binding:file] bindings, which are left as is. Ids are then + translated into lowercase symbols. +} + +@defproc[(request-headers [req request?]) + (listof (cons/c symbol? string?))]{ + Translates the @scheme[request-headers/raw] of @scheme[req] by + interpreting @scheme[bytes?] as @scheme[string?]s. Ids are then + translated into lowercase symbols. +} + +@defproc[(extract-binding/single [id symbol?] + [binds (listof (cons/c symbol? string?))]) + string?]{ + Returns the single binding associated with @scheme[id] in the a-list @scheme[binds] + if there is exactly one binding. Otherwise raises @scheme[exn:fail]. +} + +@defproc[(extract-bindings [id symbol?] + [binds (listof (cons/c symbol? string?))]) + (listof string?)]{ + Returns a list of all the bindings of @scheme[id] in the a-list @scheme[binds]. +} + +@defproc[(exists-binding? [id symbol?] + [binds (listof (cons/c symbol? string))]) + boolean?]{ + Returns @scheme[#t] if @scheme[binds] contains a binding for @scheme[id]. + Otherwise, @scheme[#f]. +} + +These functions, while convenient, could introduce subtle bugs into your +application. Examples: that they are case-insensitive could introduce +a bug; if the data submitted is not in UTF-8 format, then the conversion +to a string will fail; if an attacked submits a form field as if it were +a file, when it is not, then the @scheme[request-bindings] will hold a +@scheme[bytes?] object and your program will error; and, for file uploads +you lose the filename. + +@; ------------------------------------------------------------ +@section[#:tag "response-structs.ss"]{HTTP Responses} +@require[(for-label web-server/private/response-structs)] + +@defmodule[web-server/private/response-structs] + +@filepath{private/response-structs.ss} provides structures and functions related to +HTTP responses. + +@; XXX Only use bytes +@defstruct[response/basic + ([code number?] + [message string?] + [seconds number?] + [mime bytes?] + [headers (listof header?)])]{ + A basic HTTP response containing no body. @scheme[code] is the response code, + @scheme[message] the message, @scheme[seconds] the generation time, @scheme[mime] + the MIME type of the file, and @scheme[extras] are the extra headers, in addition + to those produced by the server. +} + +@; XXX Rename string? option +@defstruct[(response/full response/basic) + ([body (listof (or/c string? bytes?))])]{ + As with @scheme[response/basic], except with @scheme[body] as the response + body. +} + +@defstruct[(response/incremental response/basic) + ([generator ((() (listof (or/c bytes? string?)) . ->* . any) . -> . any)])]{ + As with @scheme[response/basic], except with @scheme[generator] as a function that is + called to generate the response body, by being given an @scheme[output-response] function + that outputs the content it is called with. +} + +@defproc[(response? [v any/c]) + boolean?]{ + Checks if @scheme[v] is a valid response. A response is either: + @itemize[ + @item{A @scheme[response/basic] structure.} + @item{A value matching the contract @scheme[(cons/c (or/c bytes? string?) (listof (or/c bytes? string?)))].} + @item{A value matching @scheme[xexpr?].} + ] +} + +@defthing[TEXT/HTML-MIME-TYPE bytes?]{Equivalent to @scheme[#"text/html; charset=utf-8"].} + +@warning{If you include a Content-Length header in a response that is inaccurate, there WILL be an error in +transmission that the server will not catch.} + +@; ------------------------------------------------------------ +@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. +} + +@defthing[current-servlet-continuation-expiration-handler parameter?]{ + Holds the @scheme[expiration-handler?] to be used when a continuation + captured in this context is expired, then looked up. +} + +@defproc[(send/suspend [make-response response-generator?] + [exp expiration-handler? (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]. +} + +@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. +} + +@; XXX Move +@defproc[(adjust-timeout! [t number?]) + void?]{ + Calls the servlet's manager's @scheme[adjust-timeout!] function. +} + +@defproc[(clear-continuation-table!) + void?]{ + Calls the servlet's manager's @scheme[clear-continuation-table!] function. +} + +@defproc[(send/forward [make-response response-generator?] + [exp expiration-handler? (current-servlet-continuation-expiration-handler)]) + request?]{ + Calls @scheme[clear-continuation-table!], then @scheme[send/suspend]. +} + +@defproc[(send/finish [response response?]) + void?]{ + Calls @scheme[clear-continuation-table!], then @scheme[send/back]. +} + +@defproc[(send/suspend/dispatch [make-response (embed/url? . -> . 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]. +} + +@defproc[(redirect/get) + request?]{ + Calls @scheme[send/suspend] with @scheme[redirect-to]. +} + +@defproc[(redirect/get/forget) + request?]{ + Calls @scheme[send/forward] with @scheme[redirect-to]. +} + +@; XXX Remove +@defproc[(embed-ids [ids (list/c number? number? number?)] + [u url?]) + string?]{ + Creates a @scheme[continuation-url?]. +} + +@; XXX Remove +@defthing[current-url-transform parameter?]{ + Holds a @scheme[url-transform?] function that is called by + @scheme[send/suspend] to transform the URLs it generates. +} + +@; ------------------------------------------------------------ +@section[#:tag "helpers.ss"]{Helpers} +@require[(for-label web-server/servlet/helpers)] + +@defmodule[web-server/servlet/helpers] + +@filepath{servlet/helpers.ss} provides functions built on +@filepath{servlet/web.ss} that are useful in many servlets. + +@; XXX Move into http/response.ss +@defproc[(redirect-to [uri string?] + [perm/temp redirection-status? temporarily] + [#:headers headers (listof header?) (list)]) + response?]{ + Generates an HTTP response that redirects the browser to @scheme[uri], + while including the @scheme[headers] in the response. +} + +@defproc[(redirection-status? [v any/c]) + boolean?]{ + Determines if @scheme[v] is one of the following values. +} + +@defthing[permanently redirection-status?]{A @scheme[redirection-status?] for permanent redirections.} + +@defthing[temporarily redirection-status?]{A @scheme[redirection-status?] for temporary redirections.} + +@defthing[see-other redirection-status?]{A @scheme[redirection-status?] for "see-other" redirections.} + +@defproc[(with-errors-to-browser [send/finish-or-back (response? . -> . void?)] + [thunk (-> any)]) + any]{ + Calls @scheme[thunk] with an exception handler that generates an HTML error page + and calls @scheme[send/finish-or-back]. +} + +@; XXX Depreciate +@; ------------------------------------------------------------ +@section[#:tag "servlet-url.ss"]{Servlet URLs} +@require[(for-label web-server/servlet/servlet-url)] + +@defmodule[web-server/servlet/servlet-url] + +@filepath{servlet/servlet-url.ss} provides functions that might be useful to you. +They may eventually provided by another module. + +@defproc[(request->servlet-url (req request?)) + servlet-url?]{Generates a value to be passed to the next function.} + +@defproc[(servlet-url->url-string/no-continuation [su servlet-url?]) + string?]{ + Returns a URL string without the continuation information in the URL + that went into @scheme[su] +} + +@; XXX Support Digest +@; ------------------------------------------------------------ +@section[#:tag "basic-auth.ss"]{Basic Authentication} +@require[(for-label web-server/servlet/basic-auth)] + +@defmodule[web-server/servlet/basic-auth] + +@filepath{servlet/basic-auth.ss} provides a function for helping with +implementation of HTTP Basic Authentication. + +@defproc[(extract-user-pass [heads (listof header?)]) + (or/c false/c (cons/c bytes? bytes?))]{ + Returns a pair of the username and password from the authentication + header in @scheme[heads] if they are present, or @scheme[#f] +} + +@; ------------------------------------------------------------ +@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\""]. + +@; XXX Document with-frame and with-frame-after? + +@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. +} + +@include-section["servlet-env.scrbl"] diff --git a/collects/web-server/scribblings/web-config-unit.scrbl b/collects/web-server/scribblings/web-config-unit.scrbl new file mode 100644 index 0000000000..d69f043f81 --- /dev/null +++ b/collects/web-server/scribblings/web-config-unit.scrbl @@ -0,0 +1,68 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "web-config-unit.ss"]{Web Config Unit} +@require[(for-label web-server/web-config-unit)] +@require[(for-label web-server/web-config-sig)] + +The @web-server offers a unit-based approach to configuring the server. + +@section{Configuration Signature} + +@defmodule[web-server/web-config-sig] + +@defsignature[web-config^ ()]{ + +@signature-desc{ +Provides contains the following identifiers. +} + +@defthing[max-waiting integer?]{ + Passed to @scheme[tcp-accept]. +} + +@defthing[virtual-hosts (listof (cons/c string? host-table?))]{ + Contains the configuration of individual virtual hosts. +} + +@defthing[scripts (box/c (cache-table? path? servlet?))]{ + Contains initially loaded servlets. +} + +@defthing[initial-connection-timeout integer?]{ + Specifies the initial timeout given to a connection. +} + +@defthing[port port-number?]{ + Specifies the port to serve HTTP on. +} + +@defthing[listen-ip string?]{ + Passed to @scheme[tcp-accept]. +} + +@defthing[make-servlet-namespace make-servlet-namespace?]{ + Passed to @scheme[servlets:make]. +} +} + +@section{Configuration Units} + +@defmodule[web-server/web-config-unit] + +@defproc[(configuration-table->web-config\@ [path path?] + [#:port port (or/c false/c port-number?) #f] + [#:listen-ip listen-ip (or/c false/c string?) #f] + [#:make-servlet-namespace make-servlet-namespace make-servlet-namespace? (make-make-servlet-namespace)]) + (unit? web-config^)]{ + Reads the S-expression at @scheme[path] and calls @scheme[configuration-table-sexpr->web-config\@] appropriately. +} + +@defproc[(configuration-table-sexpr->web-config\@ [sexpr list?] + [#:web-server-root web-server-root path? (directory-part default-configuration-table-path)] + [#:port port (or/c false/c port-number?) #f] + [#:listen-ip listen-ip (or/c false/c string?) #f] + [#:make-servlet-namespace make-servlet-namespace make-servlet-namespace? (make-make-servlet-namespace)]) + (unit? web-config^)]{ + Parses @scheme[sexpr] as a configuration-table and constructs a @scheme[web-config^] unit. +} diff --git a/collects/web-server/scribblings/web-server-unit.scrbl b/collects/web-server/scribblings/web-server-unit.scrbl new file mode 100644 index 0000000000..11a2d7e322 --- /dev/null +++ b/collects/web-server/scribblings/web-server-unit.scrbl @@ -0,0 +1,52 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "web-server-unit.ss"]{Web Server Unit} +@require[(for-label web-server/web-server-sig)] +@require[(for-label web-server/web-server-unit)] + +The @web-server offers a unit-based approach to running the server. + +@section{Signature} + +@defmodule[web-server/web-server-sig] + +@defsignature[web-server^ ()]{ + + @defproc[(serve) (-> void)]{ + Runs the server and returns a procedure that shuts down the server. + } + + @defproc[(serve-ports [ip input-port?] + [op output-port?]) + void]{ + Serves a single connection represented by the ports @scheme[ip] and + @scheme[op]. + } +} + +@section{Unit} + +@defmodule[web-server/web-server-unit] + +@defthing[web-server\@ (unit/c (web-config^ tcp^) + (web-server^))]{ + +Uses the @scheme[web-config^] to construct a @scheme[dispatcher?] +function that sets up one virtual host dispatcher, for each virtual +host in the @scheme[web-config^], that sequences the following +operations: + +@itemize[ + @item{Logs the incoming request with the given format to the given file} + @item{Performs HTTP Basic Authentication with the given password file} + @item{Allows the @scheme["/conf/refresh-passwords"] URL to refresh the password file.} + @item{Allows the @scheme["/conf/collect-garbage"] URL to call the garbage collector.} + @item{Allows the @scheme["/conf/refresh-servlets"] URL to refresh the servlets cache.} + @item{Execute servlets under the @scheme["/servlets/"] URL in the given servlet root directory.} + @item{Serves files under the @scheme["/"] URL in the given htdocs directory.} +] + +Using this @scheme[dispatcher?], it loads a dispatching server that provides @scheme[serve] +and @scheme[serve-ports] functions that operate as expected. +} diff --git a/collects/web-server/scribblings/web-server.scrbl b/collects/web-server/scribblings/web-server.scrbl new file mode 100644 index 0000000000..748609e460 --- /dev/null +++ b/collects/web-server/scribblings/web-server.scrbl @@ -0,0 +1,38 @@ +#lang scribble/doc +@require["web-server.ss"] + +@title[#:tag "web-server-ref"]{@bold{Web Server}: Reference Manual} +@author{Jay McCarthy (jay@"@"plt-scheme.org)} + +The @web-server collection provides libraries that can be used to +develop Web applications in Scheme. + +@table-of-contents[] + +@include-section["running.scrbl"] + +@include-section["servlet.scrbl"] +@include-section["lang.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["faq.scrbl"] + +@; ------------------------------------------------------------ +@section[#:tag "ack"]{Acknowledgements} + +We thank Matthew Flatt for his superlative work on MzScheme. +We thank the previous maintainers of the @web-server : Paul T. Graunke, Mike Burns, and Greg Pettyjohn +Numerous people have +provided invaluable feedback on the server, including Eli Barzilay, Ryan Culpepper, Robby +Findler, Dan Licata, Matt Jadud, Jacob Matthews, Matthias Radestock, Andrey Skylar, +Michael Sperber, Dave Tucker, Anton van Straaten, and Noel Welsh. We also thank the +many other PLT Scheme users who have exercised the server and offered critiques. + +@index-section[] diff --git a/collects/web-server/scribblings/web-server.ss b/collects/web-server/scribblings/web-server.ss new file mode 100644 index 0000000000..249f60e65b --- /dev/null +++ b/collects/web-server/scribblings/web-server.ss @@ -0,0 +1,31 @@ +#lang scheme/base +(require (lib "manual.ss" "scribble") + (lib "eval.ss" "scribble") + (for-label scheme/base + scheme/contract + scheme/unit)) + +(define web-server "Web Server") + +; XXX Format better +(define (author x) + (elem (hspace 4) + (bold x))) + +; XXX Format better +(define (warning . x) + (apply elem "Warning:" x)) + +; XXX Actually display link +(define (href-link url label) + (elem label " (" url ")")) + +(provide (all-from-out (lib "manual.ss" "scribble")) + (all-from-out (lib "eval.ss" "scribble")) + (for-label (all-from-out scheme/base + scheme/contract + scheme/unit)) + web-server + author + warning + href-link) \ No newline at end of file