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

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 🔗

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:

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?

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 🔗

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 🔗

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".

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

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 🔗

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 🔗

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 🔗

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 🔗

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 usedo 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 🔗

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 🔗

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.

Used to look up the password for a user is a realm.

Equivalent to (-> string? string? string?).

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.