racket/collects/web-server/scribblings/private.scrbl
Jay McCarthy d5312fbe3b Non empty strings in redirect-to
svn: r14023
2009-03-09 17:08:37 +00:00

501 lines
15 KiB
Racket

#lang scribble/doc
@(require "web-server.ss")
@title[#:tag "private" #:style 'toc]{Internal}
@(require (for-label scheme/tcp
web-server/dispatchers/dispatch
net/url
scheme/serialize
xml
net/tcp-sig))
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)
void]{
Handles the execution and management of timers.
}
@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].
}
}
@; ------------------------------------------------------------
@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.
}
@defproc[(start-connection-manager)
void]{
Runs the connection manager (now just the timer manager).
}
@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)
(for-label web-server/private/dispatch-server-sig)
(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-number?]{Specifies the port to serve on.}
@defthing[listen-ip (or/c string? false/c)]{Passed to @scheme[tcp-listen].}
@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-number?]
[port-addresses
(input-port? . -> . (values string? string?))])
(values any/c boolean?)]{
Defines the way the server reads requests off connections to be passed
to @scheme[dispatch].
}
@defthing[dispatch (-> connection? any/c void)]{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.
@defthing[dispatch-server@ (unit/c (import tcp^ dispatch-server-config^)
(export dispatch-server^))]{
Runs the dispatching server config in a very basic way, except that it uses
@secref["connection-manager.ss"] to manage connections.
}
}
@subsection{Threads and Custodians}
The dispatching server runs in a dedicated thread. Every time a connection is initiated, a new thread is started to handle it.
Connection threads are created inside a dedicated custodian that is a child of the server's custodian. When the server is used to
provide servlets, each servlet also receives a new custodian that is a child of the server's custodian @bold{not} the connection
custodian.
@; ------------------------------------------------------------
@section[#:tag "closure.ss"]{Serializable Closures}
@(require (for-label web-server/private/closure)
(for-label web-server/private/define-closure))
@defmodule[web-server/private/closure]{
The defunctionalization process of the Web Language (see @secref["stateless-servlets"])
requires an explicit representation of closures that is serializable.
@filepath{private/closure.ss} is this representation. It provides:
@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 closure that returns
@scheme[freevars ...], that when invoked with @scheme[formals]
executes @scheme[body].
}
Here is an example:
@schememod[
scheme
(require scheme/serialize)
(define-closure foo (a b) (x y)
(+ (- a b)
(* x y)))
(define f12 (make-foo (lambda () (values 1 2))))
(serialize f12)
#,(schemeresult '((1) 1 (('page . foo:deserialize-info)) 0 () () (0 1 2)))
(f12 6 7)
#,(schemeresult 1)
(f12 9 1)
#,(schemeresult 10)
(define f45 (make-foo (lambda () (values 4 5))))
(serialize f45)
#,(schemeresult '((1) 1 (('page . foo:deserialize-info)) 0 () () (0 4 5)))
(f45 1 2)
#,(schemeresult 19)
(f45 8 8)
#,(schemeresult 20)
]
}
@; ------------------------------------------------------------
@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-string?])
(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-string?])
(path? . -> . bytes?)]{
Uses a @scheme[read-mime-types] with @scheme[p] and constructs a
function from paths to their MIME type.
}
}
@; ------------------------------------------------------------
@section[#:tag "mod-map.ss"]{Serialization Utilities}
@(require (for-label web-server/private/mod-map))
@defmodule[web-server/private/mod-map]{
The @schememodname[scheme/serialize] library provides the
functionality of serializing values. @filepath{private/mod-map.ss}
compresses the serialized representation.
@defproc[(compress-serial [sv list?])
list?]{
Collapses multiple occurrences of the same module in the module
map of the serialized representation, @scheme[sv].
}
@defproc[(decompress-serial [csv list?])
list?]{
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 "gzip.ss"]{GZip}
@(require (for-label web-server/private/gzip
file/gzip
file/gunzip))
@defmodule[web-server/private/gzip]{
The @web-server provides a thin wrapper around @schememodname[file/gzip] and @schememodname[file/gunzip].
@defproc[(gzip/bytes [ib bytes?])
bytes?]{
GZips @scheme[ib] and returns the result.
}
@defproc[(gunzip/bytes [ib bytes?])
bytes?]{
GUnzips @scheme[ib] and returns the result.
}
}
@; ------------------------------------------------------------
@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[non-empty-string/c contract?]{Contract for non-empty strings.}
@defthing[port-number? contract?]{Equivalent to @scheme[(between/c 1 65535)].}
@defthing[path-element? contract?]{Equivalent to @scheme[(or/c path-string? (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.
}
@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-string?])
(listof path-element?)]{
Like @scheme[normalize-path], but does not resolve symlinks.
}
@defproc[(path-without-base [base path-string?]
[p path-string?])
(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-string?])
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[(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.
}
@subsection{Bytes}
@defproc[(bytes-ci=? [b1 bytes?] [b2 bytes?]) boolean?]{
Compares two bytes case insensitively.
}
@defproc[(read/bytes [b bytes?])
serializable?]{
@scheme[read]s a value from @scheme[b] and returns it.
}
@defproc[(write/bytes [v serializable?])
bytes?]{
@scheme[write]s @scheme[v] to a bytes and returns it.
}