This library provides utilities for handling cookies as specified in RFC 6265 [RFC6265].
#\@ or #\?
parentheses, brackets, or curly braces
commas, colons, or semicolons
equals, greater-than, or less-than signs
slashes or backslashes
double-quotes, except at the beginning and end if the entire value is double-quoted
a serializable cookie structure definition
functions to convert a cookie structure to a string, or a value for the HTTP “Set-Cookie” response header
functions that allow reading an HTTP “Cookie” header generated by a user agent
name : (and/c string? cookie-name?) value : (and/c string? cookie-value?) expires : (or/c date? #f) max-age : (or/c (and/c integer? positive?) #f) domain : (or/c domain-value? #f) path : (or/c path/extension-value? #f) secure? : boolean? http-only? : boolean? extension : (or/c path/extension-value? #f)
(make-cookie name value [ #:expires exp-date #:max-age max-age #:domain domain #:path path #:secure? secure? #:http-only? http-only? #:extension extension]) → cookie? name : cookie-name? value : cookie-value? exp-date : (or/c date? #f) = #f max-age : (or/c (and/c integer? positive?) #f) = #f domain : (or/c domain-value? #f) = #f path : (or/c path/extension-value? #f) = #f secure? : boolean? = #f http-only? : boolean? = #f extension : (or/c path/extension-value? #f) = #f
Both exp-date and max-age are for specifying a time at which the user agent should remove the cookie from its cookie store. exp-date is for specifying this expiration time as a date; max-age is for specifying it as a number of seconds in the future. If both exp-date and max-age are given, an RFC6265-compliant user agent will disregard the exp-date and use the max-age.
domain indicates that the recipient should send the cookie back to the server only if the hostname in the request URI is either domain itself, or a host within domain.
path indicates that the recipient should send the cookie back to the server only if path is a prefix of the request URI’s path.
secure, when #t, sets a flag telling the recipient that the cookie may only be sent if the request URI’s scheme specifies a “secure” protocol (presumably HTTPS).
(clear-cookie-header name [ #:domain domain #:path path]) → bytes? name : cookie-name? domain : (or/c domain-value? #f) = #f path : (or/c path/extension-value? #f) = #f
> (clear-cookie-header "rememberUser" #:path "/main")
#"rememberUser=; Expires=Thu, 01 Jan 2015 00:00:00 GMT; Path=/main"
header : bytes? (cookie-header->alist header decode) → (listof (cons/c X X)) header : bytes? decode : (-> bytes? X)
If a key in the header has no value, then #"", or (decode #"") if decode is present, is used as the value.
> (cookie-header->alist #"SID=31d4d96e407aad42; lang=en-US")
'((#"SID" . #"31d4d96e407aad42") (#"lang" . #"en-US"))
> (cookie-header->alist #"SID=31d4d96e407aad42; lang=en-US" bytes->string/utf-8)
'(("SID" . "31d4d96e407aad42") ("lang" . "en-US"))
> (cookie-header->alist #"seenIntro=; logins=3" (compose (lambda (s) (or (string->number s) s)) bytes->string/utf-8))
'(("seenIntro" . "") ("logins" . 3))
> (cookie->string (make-cookie "usesRacket" "true"))
> (cookie->string (make-cookie "favColor" "teal" #:max-age 86400 #:domain "example.com" #:secure? #t))
"favColor=teal; Max-Age=86400; Domain=example.com; Secure"
name : cookie-name? value : cookie-value? domain : domain-value? path : path/extension-value? expiration-time : (and/c integer? positive?) creation-time : (and/c integer? positive?) access-time : (and/c integer? positive?) persistent? : boolean? host-only? : boolean? secure-only? : boolean? http-only? : boolean?
All times are represented as the number of seconds since midnight UTC, January 1, 1970, like the values produced by current-seconds.
It’s unlikely a client will need to construct a ua-cookie instance directly (except perhaps for testing); extract-cookies produces struct instances for all the cookies received in a server’s response.
cookie : ua-cookie? current-time : integer? = (current-seconds)
(extract-and-save-cookies! headers url [ decode]) → void? headers : (or/c (listof (cons/c bytes? bytes?)) (listof bytes?)) url : url? decode : (-> bytes? string?) = bytes->string/utf-8
The given headers may be provided either as an alist mapping header names to header values, or as a raw list of bytes such as the second return value produced by http-conn-recv! in net/http-client. Here is an example of each:
> (require net/url)
> (define site-url (string->url "http://test.example.com/apps/main"))
> (extract-and-save-cookies! '((#"X-Test-Header" . #"isThisACookie=no") (#"Set-Cookie" . #"a=b; Max-Age=2000; Path=/") (#"Set-Cookie" . #"user=bob; Max-Age=86400; Path=/apps")) site-url) > (cookie-header site-url)
> (extract-and-save-cookies! '(#"X-Ignore-This: thisIsStillNotACookie=yes" #"Set-Cookie: p=q; Max-Age=2000; Path=/" #"Set-Cookie: usersMom=alice; Max-Age=86400; Path=/apps") site-url) > (cookie-header site-url)
#"usersMom=alice; user=bob; p=q; a=b"
url : url? encode : (-> string? bytes?) = string->bytes/utf-8 ok? : (-> ua-cookie? boolean?) = (lambda (x) #t)
Cookies with the “Secure” flag will be included in this header iff (url-scheme url) is "https", unless you remove them manually using the ok? parameter.
(send a-cookie-jar save-cookie! c [ via-http?]) → void? c : ua-cookie? via-http? : boolean? = #tSaves c to the jar, and removes any expired cookies from the jar as well.
via-http? should be #t if the cookie was received via an HTTP API; it is for properly ignoring the cookie if the cookie’s http-only? flag is set, or if the cookie is attempting to replace an “HTTP only” cookie already present in the jar.
(send a-cookie-jar save-cookies! cs [ via-http?]) → void? cs : (listof ua-cookie?) via-http? : boolean? = #tSaves each cookie in cs to the jar, and removes any expired cookies from the jar. See the note immediately above, for explanation of the via-http? flag.
(send a-cookie-jar cookies-matching url [ secure?]) → (listof ua-cookie?) url : url? secure? : boolean? = (equal? (url-scheme url) "https")Produces all cookies in the jar that should be sent in the “Cookie” header for a request made to url. secure? specifies whether the cookies will be sent via a secure protocol. (If not, cookies with the “Secure” flag set should not be returned by this method.)This method should produce its cookies in the order expected according to RFC6265:
Cookies with longer paths are listed before cookies with shorter paths.
Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times.If there are multiple cookies in the jar with the same name and different domains or paths, the RFC does not specify which to send. The default list-cookie-jar% class’s implementation of this method produces all cookies that match the domain and path of the given URL, in the order specified above.
(current-cookie-jar jar) → void? jar : (is-a?/c cookie-jar<%>)
= (new list-cookie-jar%)
set-cookie-bytes : bytes? url : url? decode : (-> bytes? string?) = bytes->string/utf-8
The decode function is used to convert the cookie’s textual fields (name, value, domain, and path) to strings.
The server-side library is based on the original net/cookie library by Francisco Solsona <email@example.com>. Many of the cookie-construction tests for this library are adapted from the net/cookie tests.
Roman Klochkov <firstname.lastname@example.org> wrote the first client-side cookie library on which this user-agent library is based. In particular, this library relies on his code for parsing dates and other cookie components.
|[RFC1034]||P. Mockapetris, “Domain Names - Concepts and Facilities,” RFC, 1987. http://tools.ietf.org/html/rfc1034.html|
|[RFC1123]||R. Braden (editor), “Requirements for Internet Hosts - Application and Support,” RFC, 1989. http://tools.ietf.org/html/rfc1123.html|
|[RFC6265]||A. Barth, “HTTP State Management Mechanism,” RFC, 2011. http://tools.ietf.org/html/rfc6265.html|