4 HTTP: Hypertext Transfer Protocol

▼ |  | Web Applications in Racket

1 | Running Web Servlets
2 | Stateful Servlets
3 | Stateless Servlets
4 | HTTP: Hypertext Transfer Protocol
5 | URL-Based Dispatch
6 | Formlets: Functional Form Abstraction
7 | Templates: Separation of View
8 | Page: Short-hand for Common Patterns
9 | Testing Servlets
10 | Troubleshooting and Tips
| Index

► | 4 | HTTP: Hypertext Transfer Protocol

4.1 | Requests
4.2 | Bindings
4.3 | Responses
4.4 | Placing Cookies
4.5 | Authenticated Cookies
4.6 | Extracting Cookies
4.7 | Redirect
4.8 | Basic Authentication
4.9 | Digest Authentication
4.10 | X-expression Support
4.11 | Empty Responses
4.12 | JSON Support

On this page:

4.1`` Requests
header
headers-assq
headers-assq*
binding
binding: form
binding: file
binding: file/ port-in
binding: file/ port?
make-binding: file/ port
bindings-assq
bindings-assq-all
request
request-bindings/ raw
4.2`` Bindings
request-bindings
request-headers
extract-binding/ single
extract-bindings
exists-binding?
4.3`` Responses
response
response-code/ c
response/ full
response/ output
TEXT/ HTML-MIME-TYPE
APPLICATION/ JSON-MIME-TYPE
4.4`` Placing Cookies
make-cookie
cookie->header
4.5`` Authenticated Cookies
make-id-cookie
request-id-cookie
valid-id-cookie?
logout-id-cookie
make-secret-salt/ file
4.6`` Extracting Cookies
client-cookie
request-cookies
4.7`` Redirect
redirect-to
redirection-status?
temporarily
temporarily/ same-method
see-other
permanently
4.8`` Basic Authentication
make-basic-auth-header
request->basic-credentials
4.9`` Digest Authentication
make-digest-auth-header
request->digest-credentials
username*realm->password/ c
username*realm->digest-HA1/ c
password->digest-HA1
make-check-digest-credentials
4.10`` X-expression Support
response/ xexpr
4.11`` Empty Responses
response/ empty
4.12`` JSON Support
response/ jsexpr

top contents ← prev up next →

### 4`` HTTP: Hypertext Transfer Protocol🔗ℹ

(require web-server/http) | package: web-server-lib

The Web Server implements many HTTP libraries that are provided by this module.

#### 4.1`` Requests🔗ℹ

(require web-server/http/request-structs)
| package: web-server-lib

> > struct
> > (struct |  | header (field value)
> #:extra-constructor-name make-header)
> field : bytes?
> value : bytes?

Represents a header of field to value.

> procedure (headers-assq id heads) → (or/c false/c header?)
> id : bytes?
> heads : (listof header?)

Returns the header with a field equal to id from heads or #f.

> procedure (headers-assq* id heads) → (or/c false/c header?)
> id : bytes?
> heads : (listof header?)

Returns the header with a field case-insensitively equal to id from heads or #f.
You almost always want to use this, rather than headers-assq because Web browsers may send headers with arbitrary casing.

> > struct
> > (struct |  | binding (id)
> #:extra-constructor-name make-binding)
> id : bytes?

Represents a binding of id.

> > struct
> > (struct |  | binding:form binding (value)
> #:extra-constructor-name make-binding:form)
> value : bytes?

Represents a form binding of id to value.

> > struct
> > (struct |  | binding:file binding (filename headers content)
> #:extra-constructor-name make-binding:file)
> filename : bytes?
> headers : (listof header?)
> content : bytes?

Represents the uploading of the file filename with the id id and the content content, where headers are the additional headers from the MIME envelope the file was in. For example, the #"Content-Type" header may be included by some browsers.
See also binding:file/port-in, an alternative interface to file uploads that can be significantly more memory efficient.

Changed in version 1.6 of package web-server-lib: Extended to support a port-based representation: see binding:file/port-in.

> procedure (binding:file/port-in binding) → input-port?
> binding : binding:file/port?
> procedure (binding:file/port? v) → boolean?
> v : any/c
> > procedure
> > (make-binding:file/port |  | id |  |  |  |
> > |  | filename |  |  |  |
> > |  | headers |  |  |  |
> > |  | content-in) |  | → |  | binding:file/port?
> id : bytes?
> filename : bytes?
> headers : (listof header?)
> content-in : input-port?

The web server can avoid storing uploaded files in memory. In particular, a safety limits value can instruct this library to offload files to disk if they are larger than some threshold. Even for file uploads that are not written to disk, the web server initially places the content in an input port, rather than a byte-string, so that storage need not be retained after the content has been read.
The port-based interface is exposed to programmers, and it can be significantly more memory efficient than the byte-string–based interface. However, the port-based interface is stateful: programmers who use it take responsibility for managing the state of the input port. Read on for details.
To maintain compatability, the port-based interface uses a private, opaque subtype of binding:file. Instances of this extended type are recognized by the predicate binding:file/port? and are created using make-binding:file/port, which is like make-binding:file, but takes the file content as an input port rather than a byte string. Only binding:file instances recognized by binding:file/port? support binding:file/port-in. The web server uses make-binding:file/port when reading request structures, which is the primary way most programs encounter binding:file instances: however, deserialized instances (see below) and instances constructed manually using make-binding:file do not support the port-based API.

It is important to be aware of how binding:file-content works with port-based instances. The first time binding:file-content is called on a port-based instance v, it consumes the port’s remaining content as with (port->bytes (binding:file/port-in v)), memoizes the result for future calls to binding:file-content, and closes the input port. This behavior means that:

- A given byte of input may be either stored in the binding:file-content field or read directly by from the input port, but never both; and

- If the input port has already been closed directly when binding:file-content is called for the first time, binding:file-content will raise an exception.

Accessing the binding:file-content field indirectly, such as by using match, has the same behavior as calling binding:file-content directly. In particular, calling serialize on a binding:file instance implicitly uses binding:file-content, and deserialized instances are effectively constructed using make-binding:file.

Added in version 1.6 of package web-server-lib.

> procedure (bindings-assq id binds) → (or/c false/c binding?)
> id : bytes?
> binds : (listof binding?)

Returns the binding with an id equal to id from binds or #f.

> procedure (bindings-assq-all id binds) → (listof binding?)
> id : bytes?
> binds : (listof binding?)

Like bindings-assq, but returns a list of all bindings matching id.

> > struct
> > (struct |  | request | ( | method
> > |  |  |  | uri
> > |  |  |  | headers/raw
> > |  |  |  | bindings/raw-promise
> > |  |  |  | post-data/raw
> > |  |  |  | host-ip
> > |  |  |  | host-port
> > |  |  |  | client-ip)
> #:extra-constructor-name make-request)
> method : bytes?
> uri : url?
> headers/raw : (listof header?)
> bindings/raw-promise : (promise/c (listof binding?))
> post-data/raw : (or/c #f bytes?)
> host-ip : string?
> host-port : number?
> client-ip : string?

An HTTP method request to uri from client-ip to the server at host-ip:host-port with headers/raw headers, bindings/raw GET and POST queries and post-data/raw POST data.
You are unlikely to need to construct a request struct.

Changed in version 1.6 of package web-server-lib: Fixed to answer #f to serializable?, as all request instances contain non-serializable pieces.

> procedure (request-bindings/raw r) → (listof binding?)
> r : request?

Forces (request-bindings/raw-promise r).

Here is an example typical of what you will find in many applications:

> (define (get-number req)
> (match
> (bindings-assq
> #"number"
> (request-bindings/raw req))
> [(? binding:form? b)
> (string->number
> (bytes->string/utf-8
> (binding:form-value b)))]
> [_
> (get-number (request-number))]))

#### 4.2`` Bindings🔗ℹ

(require web-server/http/bindings) | package: web-server-lib

These functions, while convenient, could introduce subtle errors into your application. Examples: that they are case-insensitive could introduce an error; if the data submitted is not in UTF-8 format, then the conversion to a string will fail; if an attacker submits a form field as if it were a file, when it is not, then the request-bindings will hold a bytes? object and your program will error; and, for file uploads you lose the filename. Therefore, we recommend against their use, but they are provided for compatibility with old code.

> procedure (request-bindings req)
> | → |  |
> (listof (or/c (cons/c symbol? string?)
> (cons/c symbol? bytes?)))
> req : request?

Translates the request-bindings/raw of req by interpreting bytes? as string?s, except in the case of binding:file bindings, whose contents are returned as bytes. Ids are then translated into lowercase symbols.

> procedure (request-headers req) → (listof (cons/c symbol? string?))
> req : request?

Translates the request-headers/raw of req by interpreting bytes? as string?s. Ids are then translated into lowercase symbols.

> procedure (extract-binding/single id binds) → string?
> id : symbol?
> binds : (listof (cons/c symbol? string?))

Returns the single binding associated with id in the a-list binds if there is exactly one binding. Otherwise raises exn:fail.

> procedure (extract-bindings id binds) → (listof string?)
> id : symbol?
> binds : (listof (cons/c symbol? string?))

Returns a list of all the bindings of id in the a-list binds.

> procedure (exists-binding? id binds) → boolean?
> id : symbol?
> binds : (listof (cons/c symbol? string))

Returns #t if binds contains a binding for id. Otherwise, #f.

Here is an example typical of what you will find in many applications:

> (define (get-number req)
> (string->number
> (extract-binding/single
> 'number
> (request-bindings req))))

#### 4.3`` Responses🔗ℹ

(require web-server/http/response-structs)
| package: web-server-lib

> struct (struct response (code message seconds mime headers output))
> code : response-code/c
> message : bytes?
> seconds : real?
> mime : (or/c #f bytes?)
> headers : (listof header?)
> output : (output-port? . -> . any)
> value response-code/c : flat-contract? = (integer-in 100 999)

An HTTP response where output produces the body by writing to the output port. code is the response code, message the message, seconds the generation time, mime the MIME type of the file, and headers are the headers.
If headers does not include Date, Last-Modified, or Server headers, then the server will automatically add them, where Date is based on current-seconds, Last-Modified is based on seconds, and Server is Racket.
If headers does not include Content-Type and mime is not #f, then mime is added as a Content-Type header.
The server will always replace your Connection header if it needs to ensure the connection will be closed. (Typically with an HTTP/1.0 client.)
The server will always put headers it generates before those in the response structure and guarantees that the headers supplied appear in the output in the order given. (This is relevant if multiple occurrences of the same header have a different interpretation by the client, such as with Set-Cookie.)

Examples:

> (response
> 301 #"OK"
> (current-seconds) TEXT/HTML-MIME-TYPE
> empty
> (λ (op) (write-bytes #"<html><body>Hello, World!</body></html>" op)))
> (response
> 301 #"Moved Permanently"
> (current-seconds) TEXT/HTML-MIME-TYPE
> (list (make-header #"Location"
> #"http://racket-lang.org/download"))
> (λ (op) (write-bytes #"Moved" op)))
> (response
> 304 #"Not Modified"
> (current-seconds) #f
> (list (make-header #"Location"
> #"http://racket-lang.org/download"))
> void)

Changed in version 1.2 of package web-server-lib: Contract on output weakened to allow any as the result (instead of demanding void?).
Changed in version 1.3: Added response-code/c and made the contracts on code and seconds stronger (rather than accepting number?).

> > procedure
> > (response/full |  | code |  |  |  |
> > |  | message |  |  |  |
> > |  | seconds |  |  |  |
> > |  | mime |  |  |  |
> > |  | headers |  |  |  |
> > |  | body) |  | → |  | response?
> code : response-code/c
> message : (or/c #f bytes?)
> seconds : real?
> mime : (or/c #f bytes?)
> headers : (listof header?)
> body : (listof bytes?)

A constructor for responses where body is the response body.

Example:

> (response/full
> 301 #"Moved Permanently"
> (current-seconds) TEXT/HTML-MIME-TYPE
> (list (make-header #"Location"
> #"http://racket-lang.org/download"))
> (list #"<html><body><p>"
> #"Please go to <a href=\""
> #"http://racket-lang.org/download"
> #"\">here</a> instead."
> #"</p></body></html>"))

If message is not supplied or is #f, a status message will be inferred based on code. Status messages will be inferred based on RFCs 7231 (“Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content”) and 7235 (“Hypertext Transfer Protocol (HTTP/1.1): Authentication”). These are the following:

Code |  | Message
100 |  | Continue
101 |  | Switching Protocols
200 |  | OK
201 |  | Created
202 |  | Accepted
203 |  | Non-Authoritative Information
204 |  | No Content
205 |  | Reset Content
206 |  | Partial Content
300 |  | Multiple Choices
301 |  | Moved Permanently
302 |  | Found
303 |  | See Other
305 |  | Use Proxy
307 |  | Temporary Redirect
308 |  | Permanent Redirect
400 |  | Bad Request
401 |  | Unauthorized
402 |  | Payment Required
403 |  | Forbidden
404 |  | Not Found
405 |  | Method Not Allowed
406 |  | Not Acceptable
407 |  | Proxy Authentication Required
408 |  | Request Timeout
409 |  | Conflict
410 |  | Gone
411 |  | Length Required
413 |  | Payload Too Large
414 |  | URI Too Long
415 |  | Unsupported Media Type
417 |  | Expectation Failed
426 |  | Upgrade Required
500 |  | Internal Server Error
501 |  | Not Implemented
502 |  | Bad Gateway
503 |  | Service Unavailable
504 |  | Gateway Timeout
505 |  | HTTP Version Not Supported

Changed in version 1.3 of package web-server-lib: Updated contracts on code and seconds as with response.

Changed in version 1.4 of package web-server-lib: Contract on message relaxed to allow both #f and a bytes?, with a default of #f. Previously, bytes? was required, and had a default of #"Okay".

> > procedure
> > (response/output |  | output |  |  |  |
> > | [ | #:code code |  |  |  |
> > |  | #:message message |  |  |  |
> > |  | #:seconds seconds |  |  |  |
> > |  | #:mime-type mime-type |  |  |  |
> > |  | #:headers headers]) |  | → |  | response?
> output : (-> output-port? any)
> code : number? = 200
> message : (or/c false/c bytes?) = #f
> seconds : number? = (current-seconds)
> mime-type : (or/c bytes? #f) = TEXT/HTML-MIME-TYPE
> headers : (listof header?) = '()

Equivalent to

> (response code message seconds mime-type headers output)

, with the understanding that if message is missing, it will be inferred from code using the association between status codes and messages found in RFCs 7231 and 7235. See the documentation for response/full for the table of built-in status codes.

Changed in version 1.2 of package web-server-lib: Contract on output weakened to allow any as the result (instead of demanding void?).
Changed in version 1.3: Updated contracts on code and seconds as with response.
Changed in version 1.4: Contract on message relaxed to allow both #f and a bytes?, with a default of #f. Previously, bytes? was required, and had a default of #"Okay".

> value TEXT/HTML-MIME-TYPE : bytes?

Equivalent to #"text/html; charset=utf-8".

> value APPLICATION/JSON-MIME-TYPE : bytes?

Equivalent to #"application/json; 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.

#### 4.4`` Placing Cookies🔗ℹ

(require web-server/http/cookie) | package: web-server-lib

This module provides functions to create cookies and responses that set them.

> > procedure
> > (make-cookie |  | name |  |  |  |
> > |  | value |  |  |  |
> > | [ | #:comment comment |  |  |  |
> > |  | #:domain domain |  |  |  |
> > |  | #:max-age max-age |  |  |  |
> > |  | #:path path |  |  |  |
> > |  | #:expires expires |  |  |  |
> > |  | #:secure? secure? |  |  |  |
> > |  | #:http-only? http-only? |  |  |  |
> > |  | #:extension extension]) |  | → |  | cookie?
> name : cookie-name?
> value : cookie-value?
> comment : any/c = #f
> domain : (or/c domain-value? #f) = #f
> max-age : (or/c (and/c integer? positive?) #f) = #f
> path : (or/c path/extension-value? #f) = #f
> expires : (or/c date? string? #f) = #f
> secure? : any/c = #f
> http-only? : any/c = #f
> extension : (or/c path/extension-value? #f) = #f

Constructs a cookie with the appropriate fields.
This is a wrapper around make-cookie from net/cookies/server for backwards compatibility. The comment argument is ignored. If expires is given as a string, it should match RFC 7231, Section 7.1.1.2, in which case it will be converted to a date? value. If conversion fails, an exn:fail:contract? is raised.

Changed in version 1.3 of package web-server-lib: Added support for RFC 6265 via net/cookies/server. Enforce stronger contracts on string-valued arguments. Allow expires to be a date? and allow secure to be any/c (rather than boolean?). Forbid 0 for max-age. Support http-only? and extension arguments. Ignore comment.

> procedure (cookie->header c) → header?
> c : cookie?

Constructs a header that sets the cookie.

Examples:

> (define time-cookie
> (make-cookie "time" (number->string (current-seconds))))
> (define id-cookie
> (make-cookie "id" "joseph" #:secure? #t))
> (redirect-to
> "http://localhost/logged-in"
> see-other
> #:headers
> (map cookie->header
> (list time-cookie id-cookie)))
> (send/suspend
> (lambda (k-url)
> (response/xexpr
> #:cookies (list time-cookie id-cookie)
> `(html (head (title "Cookie Example"))
> (body (h1 "You're cookie'd!"))))))

#### 4.5`` Authenticated Cookies🔗ℹ

(require web-server/http/id-cookie)
| package: web-server-lib

Cookies are useful for storing information of user’s browsers and particularly useful for storing identifying information for authentication, sessions, etc. However, there are inherent difficulties when using cookies as authenticators, because cookie data is fully controlled by the user, and thus cannot be trusted.
This module provides functions for creating and verifying authenticated cookies that are intrinsically timestamped. It is based on the algorithm proposed by the MIT Cookie Eaters: if you store the data data at time authored-seconds, then the user will receive digest&authored-seconds&data, where digest is an HMAC-SHA1 digest of authored-seconds and data, using an arbitrary secret key. When you receive a cookie, it will reverify this digest and check that the cookie’s authored-seconds is not after a timeout period, and only then return the cookie data to the program.
The interface represents the secret key as a byte string. For security, this should be created using cryptographic-quality randomness. A convenient purely Racket-based option is make-secret-salt/file, which is implemented using crypto-random-bytes. You can also generate random bytes using something like OpenSSL or /dev/random: this FAQ lists a few options.

> > procedure
> > (make-id-cookie |  | name |  |  |  |
> > |  | value |  |  |  |
> > |  | #:key secret-salt |  |  |  |
> > | [ | #:path path |  |  |  |
> > |  | #:expires expires |  |  |  |
> > |  | #:max-age max-age |  |  |  |
> > |  | #:domain domain |  |  |  |
> > |  | #:secure? secure? |  |  |  |
> > |  | #:http-only? http-only? |  |  |  |
> > |  | #:extension extension]) |  | → |  | cookie?
> name : cookie-name?
> value : cookie-value?
> secret-salt : bytes?
> path : (or/c path/extension-value? #f) = #f
> expires : (or/c date? #f) = #f
> max-age : (or/c (and/c integer? positive?) #f) = #f
> domain : (or/c domain-value? #f) = #f
> secure? : any/c = #f
> http-only? : any/c = #f
> extension : (or/c path/extension-value? #f) = #f
> (make-id-cookie |  | name |  |  |  |
> |  | secret-salt |  |  |  |
> |  | value |  |  |  |
> | [ | #:path path |  |  |  |
> |  | #:expires expires |  |  |  |
> |  | #:max-age max-age |  |  |  |
> |  | #:domain domain |  |  |  |
> |  | #:secure? secure? |  |  |  |
> |  | #:http-only? http-only? |  |  |  |
> |  | #:extension extension]) |  | → |  | cookie?
> name : cookie-name?
> secret-salt : bytes?
> value : cookie-value?
> path : (or/c path/extension-value? #f) = #f
> expires : (or/c date? #f) = #f
> max-age : (or/c (and/c integer? positive?) #f) = #f
> domain : (or/c domain-value? #f) = #f
> secure? : any/c = #f
> http-only? : any/c = #t
> extension : (or/c path/extension-value? #f) = #f

Generates an authenticated cookie named name containing value, signed with secret-salt.
The calling conventions allow secret-salt to be given either as a keyword argument (mirroring the style of make-cookie) or a by-position argument (for compatibility with older versions of this library).
The other arguments are passed to make-cookie; however, note that the default value for http-only? is #t. Users will also likely want to set secure? to #t when using HTTPS.

Changed in version 1.3 of package web-server-lib: Added support for RFC 6265 as with make-cookie, including adding the optional arguments expires, max-age, domain, secure, extension, and http-only? (which is #true by default). Allowed secret-salt to be given with the keyword #:key instead of by position.
Changed in version 1.6: Changed to accept any cookie-name? or cookie-value? (rather than only strings) for the name and value arguments, respectively, for consistency with make-cookie. Fixed a bug that had incorrectly truncated cookie signatures: note that previous versions of this library will not recognize cookies created by the fixed make-id-cookie as validly signed, and vice versa.

> > procedure
> > (request-id-cookie |  | request |
> > |  | #:name name |
> > |  | #:key secret-salt |
> > | [ | #:timeout timeout |
> > |  | #:shelf-life shelf-life]) |
> → (or/c #f (and/c string? cookie-value?))
> request : request?
> name : cookie-name?
> secret-salt : bytes?
> timeout : real? = +inf.0
> shelf-life : real? = +inf.0
> (request-id-cookie |  | name |
> |  | secret-salt |
> |  | request |
> | [ | #:timeout timeout |
> |  | #:shelf-life shelf-life]) |
> → (or/c #f (and/c string? cookie-value?))
> name : cookie-name?
> secret-salt : bytes?
> request : request?
> timeout : real? = +inf.0
> shelf-life : real? = +inf.0

Extracts the first authenticated cookie named name that was previously signed with secret-salt from request, with the allowable age of the cookie is controlled by shelf-life and timeout as with valid-id-cookie?.
If no valid cookie is available, returns #f.

Changed in version 1.3 of package web-server-lib: Added shelf-life argument and support for giving name and secret-salt by keyword instead of by position. Added support for RFC 6265 as with make-cookie.
Changed in version 1.6: Changed name argument to accept any cookie-name? as with make-id-cookie. Corrected the documented contract for the timeout argument. Fixed a bug that had incorrectly truncated cookie signatures: note that the fixed request-id-cookie will reject cookies created by previous versions of this library, and vice versa.

> > procedure
> > (valid-id-cookie? |  | cookie |
> > |  | #:name name |
> > |  | #:key secret-salt |
> > | [ | #:timeout timeout |
> > |  | #:shelf-life shelf-life]) |
> → (or/c #f (and/c string? cookie-value?))
> cookie : any/c
> name : cookie-name?
> secret-salt : bytes?
> timeout : real? = +inf.0
> shelf-life : real? = +inf.0

Recognizes authenticated cookies named name that were previously signed with secret-salt. Values satisfying either cookie? or client-cookie? can be recognized.
The shelf-life specifies the maximum age of the cookie in seconds. Cookies created more than shelf-life seconds ago will not be considered valid. The default value, +inf.0, permits all properly named and signed cookies.
Counterintuitively, the timeout argument requires that the cookie have been created before a certain moment in time: in other words, it requires that the cookie be older than a certain age. This is not usually what you want to restrict. Specifically, valid-id-cookie? tests that (<= authored timeout), where authored is the value returned by (current-seconds) when the cookie was created. The default value, +inf.0, permits all properly named and signed cookies.

Added in version 1.3 of package web-server-lib.
Changed in version 1.6: Changed name argument to accept any cookie-name? as with make-id-cookie. Corrected the documented contract for the timeout argument. Fixed a bug that had incorrectly truncated cookie signatures: note that the fixed valid-id-cookie? will reject cookies created by previous versions of this library, and vice versa.

> > procedure
> > (logout-id-cookie |  | name |  |  |  |
> > | [ | #:path path |  |  |  |
> > |  | #:domain domain]) |  | → |  | cookie?
> name : cookie-name?
> path : (or/c #f string?) = #f
> domain : (or/c domain-value? #f) = #f

Generates a cookie named name that is not validly authenticated and expires in the past.
This will cause non-malicious browsers to overwrite a previously set cookie. If you use authenticated cookies for login information, you could send this to cause a “logout.” However, malicious browsers do not need to respect such an overwrite. Therefore, this is not an effective way to implement timeouts or protect users on public (i.e. possibly compromised) computers. The only way to securely logout on the compromised computer is to have server-side state keeping track of which cookies (sessions, etc.) are invalid. Depending on your application, it may be better to track live sessions or dead sessions, or never set cookies to begin with and just use (stateful) continuations, which you can revoke with send/finish.

Changed in version 1.3 of package web-server-lib: Added support for RFC 6265 as with make-cookie, including adding the domain argument.
Changed in version 1.6: Fixed to accept any cookie-name? for the name argument, as was previously documented.

> procedure (make-secret-salt/file secret-salt-path) → bytes?
> secret-salt-path : path-string?

Extracts the bytes from secret-salt-path. If secret-salt-path does not exist, then it is created and initialized with 128 cryptographic-quality random bytes from crypto-random-bytes.

Changed in version 1.3 of package web-server-lib: Changed to use cryptographic-quality randomness to initialize secret-salt-path.

#### 4.6`` Extracting Cookies🔗ℹ

(require web-server/http/cookie-parse)
| package: web-server-lib

> > struct
> > (struct |  | client-cookie (name value domain path)
> #:extra-constructor-name make-client-cookie)
> name : (and/c string? cookie-name?)
> value : (and/c string? cookie-value?)
> domain : (or/c #f domain-value?)
> path : (or/c #f path/extension-value?)

While server cookies are represented with cookie?s, cookies that come from the client are represented with a client-cookie structure.

> procedure (request-cookies req) → (listof client-cookie?)
> req : request?

Extracts the cookies from req’s headers.

Changed in version 1.3 of package web-server-lib: Added support for RFC 6265 via net/cookies/common.

Examples:

> (define (start req)
> (define cookies (request-cookies req))
> (define id-cookie
> (findf (lambda (c)
> (string=? "id" (client-cookie-name c)))
> cookies))
> (if id-cookie
> (hello (client-cookie-value id-cookie))
> (redirect-to
> (url->string (request-uri req))
> see-other
> #:headers
> (list
> (cookie->header (make-cookie "id" "joseph"))))))
> (define (hello who)
> (response/xexpr
> `(html (head (title "Hello!"))
> (body
> (h1 "Hello "
> ,who)))))

#### 4.7`` Redirect🔗ℹ

(require web-server/http/redirect) | package: web-server-lib

> procedure (redirect-to uri [status #:headers headers]) → response?
> uri : non-empty-string?
> status : redirection-status? = temporarily
> headers : (listof header?) = '()
> procedure (redirection-status? v) → boolean?
> v : any/c
> value temporarily : redirection-status?
> value temporarily/same-method : redirection-status?
> value see-other : redirection-status?
> value permanently : redirection-status?

The function redirect-to generates an HTTP response that redirects the browser to uri, while including the headers in the response. The status argument is a redirection status value, which determines the specific type of HTTP redirect to be used.
The default redirection status, temporarily, is preserved for backwards compatibility: new code should usually use either temporarily/same-method or see-other, instead. The temporarily redirection status corresponds to 302 Found. Unfortunately, browsers have not implemented this status consistently for methods other than GET and (in practice, with all but some very old browsers) POST.
The temporarily/same-method redirection status uses 307 Temporary Redirect. This redirects the browser to uri using the same HTTP method as the original request.
The see-other redirection status corresponds to 303 See Other. It is most often used to implement the Post-Redirect-Get pattern: as a response to a request using POST or another HTTP method with side-effects, it causes the browser to perform a GET or HEAD request for uri, which gives a response to the original POST request. This prevents the Back and Refresh buttons from duplicating effects, such as making a purchase or adding items to a database. The web server provides redirect/get for added convenience with Post-Redirect-Get.

The permanently redirection status uses the HTTP status 301 Moved Permanently. It is like temporarily, except that, as the name suggests, it signifies that the move is permanent and that search engines, for example, should use uri instead of the URI of the original request. Unfortunately, permanently is also like temporarily in that browsers have implemented it inconsistently for methods other than GET and HEAD: in particular, RFC 7231 permits that, “for historical reasons, a user agent may change the request method from POST to GET for the subsequent request. When it is important to ensure that the request to uri use the same method, there are some possible alternatives:

- RFC 7231 suggests using 307 Temporary Redirect, i.e. temporarily/same-method. This has the disadvantage that search engines and others won’t update references to the old URI.

- RFC 7538 specifies a new HTTP status, 308 Permanent Redirect, which forbids changing the request method, analogously to 307 Temporary Redirect. However, the RFC also highlights some important deployment considerations for this status. In particular, older browsers—including, as of this writing, some that remain in relatively common use—do not understand this status and will fall back to the semantics of 300 Multiple Choices, which is often undesirable.

- The application can note the method of the original request and use permanently for GET and HEAD requests or one of the other alternatives for other methods.

Example: (redirect-to "http://www.add-three-numbers.com" permanently)

Changed in version 1.3 of package web-server-lib: Added temporarily/same-method.

#### 4.8`` Basic Authentication🔗ℹ

(require web-server/http/basic-auth)
| package: web-server-lib

An implementation of HTTP Basic Authentication.

> procedure (make-basic-auth-header realm) → header?
> realm : string?

Returns a header that instructs the Web browser to request a username and password from the client using Basic authentication with realm as the realm.

> procedure (request->basic-credentials req)
> → (or/c false/c (cons/c bytes? bytes?))
> req : request?

Returns a pair of the username and password from the authentication header in req if they are present, or #f.

Example:

> #lang web-server/insta
> (define (start req)
> (match (request->basic-credentials req)
> [(cons user pass)
> (response/xexpr
> `(html (head (title "Basic Auth Test"))
> (body (h1 "User: " ,(bytes->string/utf-8 user))
> (h1 "Pass: " ,(bytes->string/utf-8 pass)))))]
> [else
> (response
> 401 #"Unauthorized" (current-seconds) TEXT/HTML-MIME-TYPE
> (list
> (make-basic-auth-header
> (format "Basic Auth Test: ~a" (gensym))))
> void)]))

#### 4.9`` Digest Authentication🔗ℹ

(require web-server/http/digest-auth)
| package: web-server-lib

An implementation of HTTP Digest Authentication.

> > procedure
> > (make-digest-auth-header |  | realm |  |  |  |
> > |  | private-key |  |  |  |
> > |  | opaque) |  | → |  | header?
> realm : string?
> private-key : string?
> opaque : string?

Returns a header that instructs the Web browser to request a username and password from the client using Digest authentication with realm as the realm, private-key as the server’s contribution to the nonce, and opaque as the opaque data passed through the client.

> procedure (request->digest-credentials req)
> → (or/c false/c (listof (cons/c symbol? string?)))
> req : request?

Returns the Digest credentials from req (if they appear) as an association list.

> value username*realm->password/c : contract?

Used to look up the password for a user is a realm.
Equivalent to (-> string? string? string?).

> value username*realm->digest-HA1/c : contract?

Used to compute the user’s secret hash.
Equivalent to (-> string? string? bytes?).

> procedure (password->digest-HA1 lookup-password)
> → username*realm->digest-HA1/c
> lookup-password : username*realm->password/c

Uses lookup-password to find the password, then computes the secret hash of it.

> procedure (make-check-digest-credentials lookup-HA1)
> → (string? (listof (cons/c symbol? string?)) . -> . boolean?)
> lookup-HA1 : username*realm->digest-HA1/c

Constructs a function that checks whether particular Digest credentials (the second argument of the returned function) are correct given the HTTP method provided as the first argument and the secret hash computed by lookup-HA1.
This is will result in an exception if the Digest credentials are missing portions.

Example:

> #lang web-server/insta
> (require racket/pretty)
> (define private-key "private-key")
> (define opaque "opaque")
> (define (start req)
> (match (request->digest-credentials req)
> [#f
> (response
> 401 #"Unauthorized" (current-seconds) TEXT/HTML-MIME-TYPE
> (list (make-digest-auth-header
> (format "Digest Auth Test: ~a" (gensym))
> private-key opaque))
> void)]
> [alist
> (define check
> (make-check-digest-credentials
> (password->digest-HA1 (lambda (username realm) "pass"))))
> (define pass?
> (check "GET" alist))
> (response/xexpr
> `(html (head (title "Digest Auth Test"))
> (body
> (h1 ,(if pass? "Pass!" "No Pass!"))
> (pre ,(pretty-format alist)))))]))

#### 4.10`` X-expression Support🔗ℹ

(require web-server/http/xexpr) | package: web-server-lib

> > procedure
> > (response/xexpr |  | xexpr |  |  |  |
> > | [ | #:code code |  |  |  |
> > |  | #:message message |  |  |  |
> > |  | #:seconds seconds |  |  |  |
> > |  | #:mime-type mime-type |  |  |  |
> > |  | #:headers headers |  |  |  |
> > |  | #:cookies cookies |  |  |  |
> > |  | #:preamble preamble]) |  | → |  | response?
> xexpr : xexpr/c
> code : response-code/c = 200
> message : (or/c #f bytes?) = #f
> seconds : real? = (current-seconds)
> mime-type : (or/c #f bytes?) = TEXT/HTML-MIME-TYPE
> headers : (listof header?) = empty
> cookies : (listof cookie?) = empty
> preamble : bytes? = #""

Equivalent to

> (response/full
> code message seconds mime-type
> (append headers (map cookie->header cookies))
> (list preamble (string->bytes/utf-8 (xexpr->string xexpr))))

This is a viable function to pass to set-any->response!.

See the documentation for response/full to see how #f is handled for message.

Changed in version 1.3 of package web-server-lib: Updated contracts on code and seconds as with response.
Changed in version 1.4: Contract on message relaxed to allow both #f and bytes?, with a default of #f. Previously, bytes? was required, and had a default of #"Okay".

#### 4.11`` Empty Responses🔗ℹ

(require web-server/http/empty) | package: web-server-lib

> > procedure
> > (response/empty | [ | #:code code |  |  |  |
> > |  | #:message message |  |  |  |
> > |  | #:cookies cookies |  |  |  |
> > |  | #:seconds seconds |  |  |  |
> > |  | #:headers headers]) |  | → |  | response?
> code : number? = 204
> message : (or/c false/c bytes?) = #f
> cookies : (listof cookie?) = '()
> seconds : number? = (current-seconds)
> headers : (listof header?) = '()

Generates a response with an empty body. The usual Content-Type header will be absent, unless passed in via headers. Equivalent to

> (response code message seconds #f headers (λ (o) (write-bytes #"" o)))

, with the understanding that if message is missing (or #f), it will be inferred from code using the association between status codes and messages found in RFCs 7231 and 7235. See the documentation for response/full for the table of built-in status codes.

Added in version 1.6 of package web-server-lib.
Changed in version 1.7: Make default response code 204 rather than 200.
Changed in version 1.7: Ensure a Content-Length header is present in the response, with value 0.

#### 4.12`` JSON Support🔗ℹ

(require web-server/http/json) | package: web-server-lib

JSON is a widely used data format for the web. Racket’s JSON library meets the web server with response/jsexpr, which is for JSON what response/xexpr is for XML.

> > procedure
> > (response/jsexpr |  | jsexpr |  |  |  |
> > | [ | #:code code |  |  |  |
> > |  | #:message message |  |  |  |
> > |  | #:seconds seconds |  |  |  |
> > |  | #:mime-type mime-type |  |  |  |
> > |  | #:headers headers |  |  |  |
> > |  | #:cookies cookies]) |  | → |  | response?
> jsexpr : jsexpr?
> code : response-code/c = 200
> message : (or/c #f bytes?) = #f
> seconds : real? = (current-seconds)
> mime-type : (or/c #f bytes?) = APPLICATION/JSON-MIME-TYPE
> headers : (listof header?) = empty
> cookies : (listof cookie?) = empty

Equivalent to

> (response/full
> code message seconds mime-type
> (append headers (map cookie->header cookies))
> (list (jsexpr->bytes jsexpr)))

See the documentation for response/full to see how message, if #f, is turned into a bytes?.

Added in version 1.5 of package web-server-lib.

top contents ← prev up next →