(index ("make-request" 0) ("update-request" 1056) ("request-uri" 1401) ("request-port" 1401) ("request-method" 1401) ("request-major" 1401) ("request-minor" 1401) ("request-headers" 1401) ("write-request" 1976) ("finish-request-body" 2492) ("read-request" 2940) ("request-parsers" 3834) ("http-0.9-request-parser" 4307) ("http-1.x-request-parser" 4307) ("request-unparsers" 4567) ("http-0.9-request-unparser" 5149) ("http-1.0-request-unparser" 5149) ("http-1.x-request-unparser" 5149) ("make-response" 5614) ("update-response" 6470) ("response-port" 6828) ("response-code" 6828) ("response-reason" 6828) ("response-class" 6828) ("response-major" 6828) ("response-minor" 6828) ("response-headers" 6828) ("response-status" 6828) ("response-port-set!" 8242) ("response-code-set!" 8242) ("response-reason-set!" 8242) ("response-major-set!" 8242) ("response-minor-set!" 8242) ("response-headers-set!" 8242) ("response-status-set!" 8242) ("http-status-codes" 9073) ("write-response" 12615) ("finish-response-body" 13023) ("read-response" 13479) ("response-parsers" 13972) ("http-0.9-response-parser" 14495) ("http-1.0-response-parser" 14495) ("http-1.x-response-parser" 14495) ("response-unparsers" 14852) ("http-0.9-response-unparser" 15461) ("http-1.0-response-unparser" 15461) ("http-1.x-response-unparser" 15461) ("headers" 15834) ("headers->list" 16903) ("header-values" 17070) ("header-value" 17417) ("header-params" 17753) ("header-param" 18063) ("header-contents" 18418) ("get-value" 18418) ("get-params" 18418) ("get-param" 18418) ("header-parsers" 20831) ("header-unparsers" 20831) ("header-parse-error-handler" 21934) ("replace-header-contents" 22961) ("replace-header-contents!" 22961) ("update-header-contents" 22961) ("update-header-contents!" 22961) ("single-headers" 24228) ("http-name->symbol" 24535) ("symbol->http-name" 24535) ("remove-header" 25001) ("remove-header!" 25001) ("authorization-param-subparsers" 25228) ("basic-auth-param-subparser" 25987) ("digest-auth-param-subparser" 26401) ("authorization-param-subunparsers" 26827) ("basic-auth-param-subunparser" 27316) ("digest-auth-param-subunparser" 27585) ("http-line-limit" 28311) ("http-header-limit" 28903) ("keep-alive?" 29426) ("request-has-message-body?" 29929) ("read-urlencoded-request-data" 30528) ("http-urlencoded-request-data-limit" 31454) ("response-has-message-body-for-request?" 31645) ("safe?" 32385) ("safe-methods" 33156) ("idempotent?" 33333) ("idempotent-methods" 34231) ("etag=?" 34437) ("etag=-weakly?" 34715) ("etag-matches?" 34963) ("etag-matches-weakly?" 35265))
(def (sig (procedure "(make-request #!key uri port (method 'GET) (major 1) (minor 1) (headers (headers '())))" (id make-request))) (p "Create a request object (a " (int-link "defstruct") "-type record). The client will generally write requests, while the server will read them.") (p "The URI defines the entity to retrieve on the server, which should be a " (int-link "uri-common") "-type URI object. The PORT is the scheme I/O port where the request is written to or read from.  The METHOD is a symbol that defines the HTTP method to use (case sensitive). MAJOR and MINOR identify the major and minor version of HTTP to use. Currently, 0.9, 1.0 and 1.1 are supported.  HTTP/0.9 support is disabled by default for security reasons (HTTP/0.9 has nothing to identify it as HTTP, which means it cannot be distinguished from any completely different service. This can cause HTML interpretation of, say, SMTP or FTP responses which might contain attacker-supplied data).") (p "HEADERS must be a headers object.  See below for more information about headers."))
(def (sig (procedure "(update-request old-request #!key uri port method major minor headers)" (id update-request))) (p "Like " (tt "make-request") ", except this takes an " (tt "old-request") " object as a template for values which are missing from the parameter list, thereby providing a way to do a purely functional update of that object."))
(def (sig (procedure "(request-uri REQUEST) => URI" (id request-uri)) (procedure "(request-port REQUEST) => PORT" (id request-port)) (procedure "(request-method REQUEST) => SYMBOL" (id request-method)) (procedure "(request-major REQUEST) => NUMBER" (id request-major)) (procedure "(request-minor REQUEST) => NUMBER" (id request-minor)) (procedure "(request-headers REQUEST) => HEADERS" (id request-headers))) (p "An existing request can be picked apart with these accessors.  The " (tt "uri") " may be " (tt "#f") " in case of \"*\" (in an options request, for instance)."))
(def (sig (procedure "(write-request REQUEST) => REQUEST" (id write-request))) (p "Write a request line with headers to the server.  In case it is a request type that has any body data, this should be written to the the request's port. Beware that this port can be modified by write-request, so be sure to write to the port as it is returned by the write-request procedure!") (p "You'll need to remember to call " (tt "finish-request-body") " after you're done with the request if you have request data to write."))
(def (sig (procedure "(finish-request-body REQUEST) => REQUEST" (id finish-request-body))) (p "Finalize the request body.  You " (i "must") " call this after writing a request body (but don't call it if there's no request body).  This is required for chunked requests to have a proper trailer, otherwise the client may keep waiting for more data.  In a pipeline of a keep-alive request it may cause other issues as well, if you don't call this."))
(def (sig (procedure "(read-request PORT) => REQUEST" (id read-request))) (p "Reads a request object from the given input-port.  An optional request body can be read from the request-port after calling this procedure.") (p "If an end of file is returned before anything can be read (when the connection was closed by the remote end before it sent the request), " (tt "#f") " is returned.  In case of an invalid HTTP request line, an exception of type (exn http unknown-protocol-line) is raised.") (p "NOTE: Currently, " (tt "CONNECT") "-type requests which have an \"authority\" (hostname) between the method and the protocol version are not recognised and will result in an unrecognised protol line error.  This is a limitation of intarweb.") (p "Requests with an asterisk (like " (tt "OPTIONS * HTTP/1.1") ") will cause " (tt "#f") " to appear in the request object's " (tt "uri") " slot."))
(def (sig (parameter "(request-parsers [LIST])" (id request-parsers))) (p "Requests are parsed using parse procedures, which can be customized by overriding this parameter.") (p "LIST is a list of procedures which accept a request line string and produce a request object, or " (tt "#f") " if the request is not of the type handled by that procedure.") (p "The predefined request parsers are:") (ul (li (tt "http-0.9-request-parser")) (li (tt "http-1.x-request-parser"))))
(def (sig (procedure "(http-0.9-request-parser STRING) => REQUEST" (id http-0.9-request-parser)) (procedure "(http-1.x-request-parser STRING) => REQUEST" (id http-1.x-request-parser))) (p "Predefined request parsers for use with " (tt "request-parsers") "."))
(def (sig (parameter "(request-unparsers [LIST])" (id request-unparsers))) (p "Requests are written using unparse procedures, which can be customized by overriding this parameter.") (p "LIST is list of procedures which accept a request object and write to the request's output port and return the new, possibly updated request object. If the request object is not unparsed by this handler, it returns " (tt "#f") ".") (p "The predefined request unparsers are:") (ul (li (tt "http-0.9-request-unparser")) (li (tt "http-1.0-request-unparser")) (li (tt "http-1.x-request-unparser"))))
(def (sig (procedure "(http-0.9-request-unparser REQUEST) => REQUEST" (id http-0.9-request-unparser)) (procedure "(http-1.0-request-unparser REQUEST) => REQUEST" (id http-1.0-request-unparser)) (procedure "(http-1.x-request-unparser REQUEST) => REQUEST" (id http-1.x-request-unparser))) (p "Predefined request unparsers for use with " (tt "request-unparsers") ". They return the request, and as a side effect they write the request to the request object's port."))
(def (sig (procedure "(make-response #!key port status (code 200) (reason \"OK\") (major 1) (minor 1) (headers (headers '())))" (id make-response))) (p "Create a response, a " (int-link "defstruct") "-type record.  A server will usually write a response with " (tt "write-response") "; a client will read it with " (tt "read-response") ".") (p "You can either supply a status symbol or a code and/or reason to set the response status.  If you do, the code will be set to match that symbol and the reason is set to the default reason belonging to that code, as provided by the HTTP standard(s).  The allowed symbols are generally just Schemified versions of the default reason.") (p "Only the code and reason are actual fields in the object; the status is a virtual field.") (p "See " (tt "http-status-codes") " for a list of all known default statuses."))
(def (sig (procedure "(update-response old-response #!key port status code reason major minor headers)" (id update-response))) (p "Like " (tt "make-response") ", except this takes an " (tt "old-response") " object as a template for values which are missing from the parameter list, thereby providing a way to do a purely functional update of that object."))
(def (sig (procedure "(response-port RESPONSE) => PORT" (id response-port)) (procedure "(response-code RESPONSE) => NUMBER" (id response-code)) (procedure "(response-reason RESPONSE) => STRING" (id response-reason)) (procedure "(response-class RESPONSE-OR-CODE) => NUMBER" (id response-class)) (procedure "(response-major RESPONSE) => NUMBER" (id response-major)) (procedure "(response-minor RESPONSE) => NUMBER" (id response-minor)) (procedure "(response-headers RESPONSE) => HEADERS" (id response-headers)) (procedure "(response-status RESPONSE-OR-CODE) => SYMBOL" (id response-status))) (p "An existing response can be picked apart using these accessors.") (p "The PORT, MAJOR, MINOR and HEADERS are the same as for requests. CODE and REASON are an integer status code and the short message that belongs to it, as defined in the spec (examples include: 200 OK, 301 Moved Permanently, etc).  CLASS is the major class of the response code (100, 200, 300, 400 or 500).  " (tt "response-class") " can be called either on a response object or directly on a response code number.") (p (tt "response-status") " attempts to fetch the symbolic status from the response object based on its response code.  If no matching symbol can be found in the " (tt "http-status-codes") " parameter, an exception is thrown. " (tt "response-status") " can also be called on a response object or directly on a response code number."))
(def (sig (procedure "(response-port-set! RESPONSE PORT)" (id response-port-set!)) (procedure "(response-code-set! RESPONSE NUMBER)" (id response-code-set!)) (procedure "(response-reason-set! RESPONSE STRING)" (id response-reason-set!)) (procedure "(response-major-set! RESPONSE NUMBER)" (id response-major-set!)) (procedure "(response-minor-set! RESPONSE NUMBER)" (id response-minor-set!)) (procedure "(response-headers-set! RESPONSE HEADERS)" (id response-headers-set!)) (procedure "(response-status-set! RESPONSE SYMBOL)" (id response-status-set!))) (p "These procedures mutate an existing response object and set the corresponding slot. " (tt "response-status-set!") " will attempt to look up the code and reason in " (tt "http-status-codes") " and set both slots. If the symbolic status is unknown, an exception is thrown."))
(def (sig (parameter "(http-status-codes [ALIST])" (id http-status-codes))) (p "This is an alist mapping symbolic status indicators to HTTP codes and reason strings.") (p "These can be used to make your code a bit more expressive and to reduce duplication of hardcoded strings; instead of using a numeric \"magic number\" HTTP code plus the same human-readable string everywhere the same code occurs, you can instead use a descriptive symbol.") (p "The default value of this mapping is as follows:") (highlight scheme "    ((continue . (100 . \"Continue\"))\n     (switching-protocols . (101 . \"Switching Protocols\"))\n     (processing . (102 . \"Processing\"))\n     (ok . (200 . \"OK\"))\n     (created . (201 . \"Created\"))\n     (accepted . (202 . \"Accepted\"))\n     (non-authoritative-information . (203 . \"Non-Authoritative Information\"))\n     (no-content . (204 . \"No Content\"))\n     (reset-content . (205 . \"Reset Content\"))\n     (partial-content . (206 . \"Partial Content\"))\n     (multi-status . (207 . \"Multi-Status\"))\n     (already-reported . (208 . \"Already Reported\"))\n     (im-used . (226 . \"IM Used\"))\n     (multiple-choices . (300 . \"Multiple Choices\"))\n     (moved-permanently . (301 . \"Moved Permanently\"))\n     (found . (302 . \"Found\"))\n     (see-other . (303 . \"See Other\"))\n     (not-modified . (304 . \"Not Modified\"))\n     (use-proxy . (305 . \"Use Proxy\"))\n     (temporary-redirect . (307 . \"Temporary Redirect\"))\n     (bad-request . (400 . \"Bad Request\"))\n     (unauthorized . (401 . \"Unauthorized\"))\n     (payment-required . (402 . \"Payment Required\"))\n     (forbidden . (403 . \"Forbidden\"))\n     (not-found . (404 . \"Not Found\"))\n     (method-not-allowed . (405 . \"Method Not Allowed\"))\n     (not-acceptable . (406 . \"Not Acceptable\"))\n     (proxy-authentication-required . (407 . \"Proxy Authentication Required\"))\n     (request-time-out . (408 . \"Request Time-out\"))\n     (conflict . (409 . \"Conflict\"))\n     (gone . (410 . \"Gone\"))\n     (length-required . (411 . \"Length Required\"))\n     (precondition-failed . (412 . \"Precondition Failed\"))\n     (request-entity-too-large . (413 . \"Request Entity Too Large\"))\n     (request-uri-too-large . (414 . \"Request-URI Too Large\"))\n     (unsupported-media-type . (415 . \"Unsupported Media Type\"))\n     (requested-range-not-satisfiable . (416 . \"Requested Range Not Satisfiable\"))\n     (expectation-failed . (417 . \"Expectation Failed\"))\n     (unprocessable-entity . (422 . \"Unprocessable Entity\"))\n     (locked . (423 . \"Locked\"))\n     (failed-dependency . (424 . \"Failed Dependency\"))\n     (upgrade-required . (426 . \"Upgrade Required\"))\n     (precondition-required . (428 . \"Precondition Required\"))\n     (too-many-requests . (429 . \"Too Many Requests\"))\n     (request-header-fields-too-large . (431 . \"Request Header Fields Too Large\"))\n     (internal-server-error . (500 . \"Internal Server Error\"))\n     (not-implemented . (501 . \"Not Implemented\"))\n     (bad-gateway . (502 . \"Bad Gateway\"))\n     (service-unavailable . (503 . \"Service Unavailable\"))\n     (gateway-time-out . (504 . \"Gateway Time-out\"))\n     (http-version-not-supported . (505 . \"HTTP Version Not Supported\"))\n     (insufficient-storage . (507 . \"Insufficient Storage\"))\n     (loop-detected . (508 . \"Loop Detected\"))\n     (not-extended . (510 . \"Not Extended\"))\n     (network-authentication-required . (511 . \"Network Authentication Required\")))"))
(def (sig (procedure "(write-response RESPONSE) => RESPONSE" (id write-response))) (p "Write the response object RESPONSE to the " (tt "response-port") ".") (p "If there is a response body, this must be written to the response-port after sending the response headers.  You'll need to remember to call " (tt "finish-response-body") " after you're done with the response if you have response data to write."))
(def (sig (procedure "(finish-response-body RESPONSE) => RESPONSE" (id finish-response-body))) (p "Finalize the response body.  You " (i "must") " call this after writing a response body (but don't call it if there's no response body).  This is required for chunked responses to have a proper trailer, otherwise the client may keep waiting for more data.  In a pipeline of a keep-alive request it may cause other issues as well, if you don't call this."))
(def (sig (procedure "(read-response PORT) => RESPONSE" (id read-response))) (p "Reads a response object from the port. An optional response body can be read from the response-port after calling this procedure.") (p "If an end of file is returned before anything can be read (when the connection was closed by the remote end before it sent the response), " (tt "#f") " is returned.  In case of an invalid HTTP response line, an exception of type (exn http unknown-protocol-line) is raised."))
(def (sig (parameter "(response-parsers [LIST])" (id response-parsers))) (p "Responses are parsed using parse procedures, which can be customized by overriding this parameter.") (p "LIST is a list one of procedures which accept a response line string and produce a response object, or " (tt "#f") " if the response is not of the type handled by that procedure.") (p "The predefined response parsers are:") (ul (li (tt "http-0.9-response-parser")) (li (tt "http-1.0-response-parser")) (li (tt "http-1.x-response-parser"))))
(def (sig (procedure "(http-0.9-response-parser REQUEST) => REQUEST" (id http-0.9-response-parser)) (procedure "(http-1.0-response-parser REQUEST) => REQUEST" (id http-1.0-response-parser)) (procedure "(http-1.x-response-parser REQUEST) => REQUEST" (id http-1.x-response-parser))) (p "Predefined response parsers for use with " (tt "response-parser") "."))
(def (sig (parameter "(response-unparsers [LIST])" (id response-unparsers))) (p "Responses are written using unparse procedures, which can be customized by overriding this parameter.") (p "LIST is a list of procedures which accept a response object and write to the response's output port and return the new, possibly updated response object. If the response object is not unparsed by this handler, it returns " (tt "#f") ".") (p "The predefined response unparsers are the following:") (ul (li (tt "http-0.9-response-unparser")) (li (tt "http-1.0-response-unparser")) (li (tt "http-1.x-response-unparser"))))
(def (sig (procedure "(http-0.9-response-unparser REQUEST) => REQUEST" (id http-0.9-response-unparser)) (procedure "(http-1.0-response-unparser REQUEST) => REQUEST" (id http-1.0-response-unparser)) (procedure "(http-1.x-response-unparser REQUEST) => REQUEST" (id http-1.x-response-unparser))) (p "Predefined response unparsers for use with " (tt "response-unparser") "."))
(def (sig (procedure "(headers ALIST [HEADERS]) => HEADERS" (id headers))) (p "This creates a header object based on an input list.") (p "Requests and responses contain HTTP headers wrapped in a special header-object to ensure they are properly normalized.") (p "The input list has header names (symbols) as keys, and lists of values as values:") (highlight scheme "(headers `((host (\"example.com\" . 8080))\n           (accept #(text/html ((q . 0.5)))\n                   #(text/xml ((q . 0.1)))))\n          old-headers)") (p "This adds the named headers to the existing headers in " (tt "old-headers") ". The host header is a pair of hostname/port. The accept header is a list of allowed mime-type symbols.") (p "As can be seen here, optional parameters or \"attributes\" can be added to a header value by wrapping the value in a vector of length 2. The first entry in the vector is the header value, the second is an alist of attribute name/value pairs, or the symbol " (tt "raw") ", in which case the header value will be kept as-is when writing the response."))
(def (sig (procedure "(headers->list HEADERS) => ALIST" (id headers->list))) (p "This converts a header object back to a list.  See " (tt "headers") " for details."))
(def (sig (procedure "(header-values NAME HEADERS) => LIST" (id header-values))) (p "Obtain the value of header NAME in the HEADERS object.") (p "The NAME of the header is a symbol; this procedure will return all the values of the header (for example, the Accept header will have several values that indicate the set of acceptable mime-types)."))
(def (sig (procedure "(header-value NAME HEADERS [DEFAULT]) => value" (id header-value))) (p "If you know in advance that a header has only one value, you can use " (tt "header-value") " instead of " (tt "header-values") ".  This will return the first value in the list, or the provided default if there is no value for that header."))
(def (sig (procedure "(header-params NAME HEADERS) => ALIST" (id header-params))) (p "This will return all the params for a given header, assuming there is only one header.  An empty list is returned if the header does not exist.") (p "If the header is a \"raw\" one, the symbol " (tt "raw") " is returned."))
(def (sig (procedure "(header-param PARAM NAME HEADERS [DEFAULT]) => value" (id header-param))) (p "This will return a specific parameter for the header, or " (tt "DEFAULT") " if the parameter isn't present or the header does not exist.  This also assumes there's only one header.") (p "If the header is a raw one, " (tt "DEFAULT") " will be returned."))
(def (sig (procedure "(header-contents NAME HEADERS) => LIST" (id header-contents)) (procedure "(get-value VECTOR) => value" (id get-value)) (procedure "(get-params VECTOR) => ALIST" (id get-params)) (procedure "(get-param PARAM VECTOR [DEFAULT]) => value" (id get-param))) (p "Procedures such as " (tt "header-values") " are just shortcuts; these are the underlying procedures to query the raw contents of a header.") (p "Header contents are lists of 2-element vectors; the first value containing the value for the header and the second value containing an alist with \"parameters\" for that header value. Parameters are attribute/value pairs that define further specialization of a header's value. For example, the " (tt "accept") " header consists of a list of mime-types, which optionally can have a quality parameter that defines the preference for that mime-type.  All parameter names are downcased symbols, just like header names.") (p "Here's a few examples on how to retrieve info from headers:") (highlight scheme ";; This would be returned by a server and retrieved via (response-headers r):\n(define example-headers\n  (headers '((accept #(text/html ((q . 0.1)))\n                     #(text/xml ((q . 0.5)))\n                     text/plain)\n             (allow HEAD GET)\n\t     (content-type #(text/html ((charset . utf-8))))\n             (max-forwards 2))))\n\n;;; Basic procedures\n(define c (header-contents 'accept example-headers))\nc ; => (#(text/html ((q . 0.5))) #(text/xml ((q . 0.1))) #(text/plain ()))\n\n(get-value (car c))\n; => text/html\n(get-params (car c))\n; => ((q . 0.5))\n(get-param 'q (car c))\n; => 0.5\n\n;;; Simplified helpers\n(header-values 'accept example-headers)\n; => (text/html text/xml text/plain)\n(header-values 'max-forwards example-headers)\n; => (2)\n(header-values 'nonexistent-header example-headers)\n; => ()\n\n;; This assumes there's only one value (returns the first)\n(header-value 'max-forwards example-headers)\n; => 2\n(header-value 'nonexistent-header example-headers)\n; => #f\n(header-value 'nonexistent-header example-headers 'not-here)\n; => not-here\n;; Tricky:\n(header-value 'accept example-headers)\n; => text/html\n\n;; This is tricky: this just returns the first, which is not the preferred\n(header-params 'accept example-headers)\n; => ((q . 0.1))\n;; Quick access\n(header-param 'charset 'content-type example-headers)\n; => utf-8"))
(def (sig (parameter "(header-parsers [ALIST])" (id header-parsers)) (parameter "(header-unparsers [ALIST])" (id header-unparsers))) (p "The parsers and unparsers used to read and write header values can be customized with these parameters.") (p "These (un)parsers are indexed with as key the header name (a symbol) and the value being a procedure.") (p "A header parser accepts the contents of the header (a string, without the leading header name and colon) and returns a " (i "list of vectors") " which represents the values of the header.  For headers that are supposed to only have a single value, the last value in the list will be stored as the value (as determined by " (tt "single-headers") ").") (p "A header unparser accepts one argument: the header's contents (a vector).  It should return a list of strings, each of which represents one line's worth of header contents (without the header name).  For each entry, a header line will automatically be printed with the header name preceding it.") (p "The parser driver will call " (tt "update-header-contents!") " with the parser's result."))
(def (sig (parameter "(header-parse-error-handler [HANDLER])" (id header-parse-error-handler))) (p "When there is an error parsing a given header, this parameter's procedure will be invoked.") (p (tt "HANDLER") " is a procedure accepting four values: the header name, the header contents, the current headers and the exception object.  The procedure must return the new headers.  Defaults to a procedure that simply returns the current headers.  When an error occurs while parsing the header line itself (for example when a colon is missing between the header name and contents), the error will not be caught.") (p "In such a case, Servers should return a 400 Bad Request error and clients should error out.  The reason that malformed error lines are ignored is that there are several servers and clients that send headers content values that are slightly off, even though the rest of the request is OK.  In the interest of the \"robustness principle\", it's best to simply ignore these headers with \"bad\" content values."))
(def (sig (procedure "(replace-header-contents NAME CONTENTS HEADERS) => HEADERS" (id replace-header-contents)) (procedure "(replace-header-contents! NAME CONTENTS HEADERS) => HEADERS" (id replace-header-contents!)) (procedure "(update-header-contents NAME CONTENTS HEADERS) => HEADERS" (id update-header-contents)) (procedure "(update-header-contents! NAME CONTENTS HEADERS) => HEADERS" (id update-header-contents!))) (p "The " (tt "replace") " procedures replace any existing contents of the named header with new ones, the " (tt "update") " procedures add these contents to the existing header. The procedures with a name ending in bang are linear update variants of the ones without the bang. The header contents have to be normalized to be a 2-element vector, with the first element being the actual value and the second element being an alist (possibly empty) of parameters/attributes for that value.") (p "The update procedures append the value to the existing header if it is a multi-header, and act as a simple replace in the case of a single-header.") (p "If you attempt to add a header that's not a proper 2-element vector, or if you try to combine raw and non-raw header values, this will raise an exception of type " (tt "(exn http header-value)") "."))
(def (sig (parameter "(single-headers [LIST])" (id single-headers))) (p "Whether a header is allowed once or multiple times in a request or response is determined by this parameter.") (p "The value is a list of symbols that define header-names which are allowed to occur only once in a request/response."))
(def (sig (procedure "(http-name->symbol STRING) => SYMBOL" (id http-name->symbol)) (procedure "(symbol->http-name SYMBOL) => STRING" (id symbol->http-name))) (p "These procedures convert strings containing the name of a header or attribute (parameter name) to symbols representing the same. The symbols are completely downcased.  When converting this symbol back to a string, the initial letters of all the words in the header name or attribute are capitalized."))
(def (sig (procedure "(remove-header name headers) => headers" (id remove-header)) (procedure "(remove-header! name headers) => headers" (id remove-header!))) (p "These two procedures remove all headers with the given name."))
(def (sig (parameter "(authorization-param-subparsers [ALIST])" (id authorization-param-subparsers))) (p "This is an alist of subtypes for the " (tt "authorization") " header parser. A subparser of this kind accepts the string containing the header and an integer position in the string.  It should parse from that position onwards, and return the parsed contents as an alist of header parameters.  Usually, these are actually pseudo-parameters; they don't necessarily have to appear in parameter syntax in the header.  The unparser should be configured to expect the same parameters and combine them back into a string, though.") (p "This parameter defaults to:") (highlight scheme "`((basic . ,basic-auth-subparser)\n  (digest . ,digest-auth-subparser))"))
(def (sig (procedure "(basic-auth-param-subparser STR POS)" (id basic-auth-param-subparser))) (p "Parses " (tt "STR") " at " (tt "POS") " by extracting the username and password components from a base64-encoded string.  These are returned in its first value as an alist with keys " (tt "username") " and " (tt "password") ".  Its second return value is the position after which the next header value may begin."))
(def (sig (procedure "(digest-auth-param-subparser STR POS)" (id digest-auth-param-subparser))) (p "Parses " (tt "STR") " at " (tt "POS") " by reading the various components from a parameter list.  These are returned in its first return value as an alist with keys " (tt "nc") ", " (tt "uri") ", " (tt "qop") " and " (tt "algorithm") ".  Its second return value is the position after which the next header value may begin."))
(def (sig (parameter "(authorization-param-subunparsers [ALIST])" (id authorization-param-subunparsers))) (p "This is an alist of subtypes for the " (tt "authorization") " header unparser.  An unparser of this kind accepts an alist containing the parameters that it needs to unparse and should return a string containing the raw unparsed parameters only.") (p "This parameter defaults to:") (highlight scheme "`((basic . ,basic-auth-subunparser)\n  (digest . ,digest-auth-subunparser))"))
(def (sig (procedure "(basic-auth-param-subunparser PARAMS)" (id basic-auth-param-subunparser))) (p "This unparses the " (tt "PARAMS") " alist into a base64-encoded string for basic authentication.  It expects " (tt "username") " and " (tt "password") " parameters."))
(def (sig (procedure "(digest-auth-param-subunparser PARAMS)" (id digest-auth-param-subunparser))) (p "This unparses the " (tt "PARAMS") " alist into a string for digest authentication. It expects " (tt "username") ", " (tt "uri") ", " (tt "realm") ", " (tt "nonce") ", " (tt "cnonce") ", " (tt "qop") ", " (tt "nc") ", " (tt "response") ", " (tt "opaque") " and " (tt "algorithm") " parameters.  The " (tt "response") " parameter should be pre-encoded in the way digest auth expects (this is not done here because the MD5 sum of the contents may be required, which is not available to the parsers).") (p "TODO: This will probably change in the future; the md5 can be passed and all the hard stuff can be done in intarweb."))
(def (sig (parameter "(http-line-limit [length])" (id http-line-limit))) (p "The maximum length of any line that's read by intarweb as part of the request/response cycle.  This includes the request and response lines as well as the headers.  If this is exceeded, an exception of type " (tt "(exn http line-limit-exceeded)") " is raised.") (p "You can set this to " (tt "#f") " to disable this check. However, this will open up a resource consumption vulnerability (attackers can cause your application to blow up by letting it use all available memory).") (p "Defaults to " (tt "4096") "."))
(def (sig (parameter "(http-header-limit [count])" (id http-header-limit))) (p "The maximum number of headers that are allowed to be sent, as part of a request or response. If this is exceeded, an exception of type " (tt "(exn http header-limit-exceeded)") " is raised.") (p "You can set this to " (tt "#f") " to disable this check. However, this will open up a resource consumption vulnerability (attackers can cause your application to blow up by letting it use all available memory).") (p "Defaults to " (tt "64") "."))
(def (sig (procedure "(keep-alive? request-or-response)" (id keep-alive?))) (p "Returns " (tt "#t") " when the given request or response object belongs to a connection that should be kept alive, " (tt "#f") " if not.  Remember that both parties must agree on whether the connection is to be kept alive or not; HTTP/1.1 defaults to keep alive unless a " (tt "Connection: close") " header is sent, HTTP/1.0 defaults to closing the connection, unless a " (tt "Connection: Keep-Alive") " header is sent."))
(def (sig (parameter "(request-has-message-body? [predicate])" (id request-has-message-body?))) (p "This parameter holds a predicate which accepts a request object and returns " (tt "#t") " when the request will have a message body.  By default in HTTP/1.1, this is the case for all requests that have a " (tt "content-length") " or " (tt "transfer-coding") " header.  In HTTP/1.0, it is assumed to be true unless there's a " (tt "Connection: Keep-Alive") " without a " (tt "Content-Length") " header.") (p "The parameter is useful for servers to determine whether to read a request body or not."))
(def (sig (procedure "(read-urlencoded-request-data request [max-length])" (id read-urlencoded-request-data))) (p "Convenience procedure to read URLencoded request data (regular POST data; " (i "not") " multipart data!) from the given " (tt "request") " object.  It will return an alist, as would be returned by " (tt "form-urldecode") " from the " (int-link "uri-common") " egg.") (p "You have to take care of checking the request type whether there really will be request data yourself (it can optionally use " (tt "request-has-message-body?") " for this, but it's probably advisable to check the request type anyway).") (p "This will read at most " (tt "max-length") " bytes.  If not specified, " (tt "max-length") " defaults to the current value of " (tt "http-urlencoded-request-data-limit") ".  If this maximum is exceeded, an exception of type " (tt "(exn http urlencoded-request-data-limit-exceeded)") " is raised."))
(def (sig (parameter "(http-urlencoded-request-data-limit [length])" (id http-urlencoded-request-data-limit))) (p "Set the default limit for request body data.  Defaults to 4194304 (4MB)."))
(def (sig (parameter "(response-has-message-body-for-request? [predicate])" (id response-has-message-body-for-request?))) (p "This parameter holds a predicate which accepts two arguments: a response object and a request object.  It returns " (tt "#t") " when the response will have a message body for the given request.  By default in HTTP/1.1, this is " (b "not") " the case for responses with a response-code of 204 and 304 or in the 1xx class, nor for " (tt "HEAD") " requests.  All other responses will have a message body.") (p "The parameter is useful for deciding in clients whether a message body will follow (otherwise, trying to read will probably result in an error or in case of HTTP pipelining in a synchronisation problem)"))
(def (sig (procedure "(safe? request-or-method)" (id safe?))) (p "Returns " (tt "#t") " when the given request object or symbol (method) is a " (i "safe") " method.  A method is defined to be safe when a request of this method will have no side-effects on the server.  In practice this means that you can send this request from anywhere at any time and cause no damage.") (p (b "Important") ": Quite a lot of software does not abide by these rules!  This is not necessarily a reason to treat all methods as unsafe, however.  In the words of the standard \"the user did not request the side-effects, so therefore cannot be held accountable for them\".  If a safe method produces side-effects, that's the server-side script developer's fault and he should fix his code."))
(def (sig (parameter "(safe-methods [symbols])" (id safe-methods))) (p "A list of methods which are to be considered safe.  Defaults to " (tt "'(GET HEAD OPTIONS TRACE)") "."))
(def (sig (procedure "(idempotent? request-or-method)" (id idempotent?))) (p "Returns " (tt "#t") " when the given request object or symbol (method) is a " (i "idempotent") " method.  A method is defined to be idempotent when a series of identical requests of this method in succession causes the exact same side-effect as just one such request.  In practice this means that you can safely retry such a request when an error occurs, for example.") (p (b "Important") ": Just as with the " (i "safe") " methods, there is no guarantee that methods that " (i "should be") " idempotent really are idempotent in any given web application.  Furthermore, a sequence of requests which each are individually idempotent is not necessarily idempotent as a whole.  This means that you cannot replay requests starting anywhere in the chain.  To be on the safe side, only retry the last request in the chain."))
(def (sig (parameter "(idempotent-methods [symbols])" (id idempotent-methods))) (p "A list of methods which are to be considered idempotent.  Defaults to " (tt "'(GET HEAD PUT DELETE OPTIONS TRACE)") "."))
(def (sig (procedure "(etag=? a b)" (id etag=?))) (p "Do the etag values " (tt "a") " and " (tt "b") " strongly match?  That is, their " (tt "car") " and " (tt "cdr") " must be equal, and neither can have a " (tt "car") " of " (tt "weak") " (both must be " (tt "strong") ")."))
(def (sig (procedure "(etag=-weakly? a b)" (id etag=-weakly?))) (p "Do the etag values " (tt "a") " and " (tt "b") " weakly match?  That is, their " (tt "car") " and " (tt "cdr") " must be equal.  A " (tt "car") " of " (tt "weak") " is allowed."))
(def (sig (procedure "(etag-matches? etag matches)" (id etag-matches?))) (p "Does the " (tt "etag") " strongly match any of the etags in the list " (tt "matches") "?  " (tt "matches") " is a plain list of etag values, but it can also contain the special symbol " (tt "*") ", which matches any etag."))
(def (sig (procedure "(etag-matches-weakly? etag matches)" (id etag-matches-weakly?))) (p "Does the " (tt "etag") " weakly match any of the etags in the list " (tt "matches") "?  " (tt "matches") " is a plain list of etag values, but it can also contain the special symbol " (tt "*") ", which matches any etag."))
