Cookie parsing, validation, and jar management following RFC 6265.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-cookie: rewrite README examples and fix odoc @see placement

Three problems collapsed into one fix:

- README ocaml blocks referenced unbound names ([cookies], [clock],
[jar], [path]) so mdx couldn't compile them. Wrap each snippet as a
function that takes its inputs explicitly.
- Validation block used trailing comments to claim [Ok ...] / [Error
...] results without checking. Replace with [assert] so mdx verifies
the behaviour.
- [cookie.mli] and [cookie_jar.mli] had a stray [@see <RFC 6265>] tag
followed by a [{2 ...}] section heading; odoc rejects headings inside
[@see]. Drop the redundant tag (RFC 6265 is linked elsewhere in the
same docstring).

Add [fmt] to the mdx libraries for [Fmt.pr].

+29 -56
+28 -49
README.md
··· 46 46 ### Parsing Headers 47 47 48 48 ```ocaml 49 + let now () = Ptime_clock.now () 50 + 49 51 (* Parse a Set-Cookie response header *) 50 - let cookie = 51 - Cookie.of_set_cookie_header 52 - ~now:(fun () -> Ptime_clock.now ()) 53 - ~domain:"example.com" 54 - ~path:"/" 52 + let parse_set_cookie = 53 + Cookie.of_set_cookie_header ~now ~domain:"example.com" ~path:"/" 55 54 "session=abc123; Secure; HttpOnly; SameSite=Strict" 56 55 57 56 (* Parse a Cookie request header *) 58 - let cookies = 59 - Cookie.of_cookie_header 60 - ~now:(fun () -> Ptime_clock.now ()) 61 - ~domain:"example.com" 62 - ~path:"/" 57 + let parse_cookies = 58 + Cookie.of_cookie_header ~now ~domain:"example.com" ~path:"/" 63 59 "session=abc123; theme=dark" 64 60 ``` 65 61 66 62 ### Serializing Headers 67 63 68 64 ```ocaml 69 - (* Generate a Cookie request header from a list of cookies *) 70 - let header = Cookie.cookie_header cookies 71 - (* "session=abc123; theme=dark" *) 72 - 73 - (* Generate a Set-Cookie response header *) 74 - let header = Cookie.set_cookie_header cookie 65 + let render_request (cookies : Cookie.t list) = Cookie.cookie_header cookies 66 + let render_response (cookie : Cookie.t) = Cookie.set_cookie_header cookie 75 67 ``` 76 68 77 69 ### Creating Cookies 78 70 79 71 ```ocaml 80 - let cookie = 81 - Cookie.v 82 - ~domain:"example.com" 83 - ~path:"/" 84 - ~name:"session" 85 - ~value:"abc123" 86 - ~secure:true 87 - ~http_only:true 88 - ~same_site:`Strict 89 - ~creation_time:(Ptime_clock.now ()) 90 - ~last_access:(Ptime_clock.now ()) 91 - () 72 + let session_cookie ~now = 73 + Cookie.v ~domain:"example.com" ~path:"/" ~name:"session" ~value:"abc123" 74 + ~secure:true ~http_only:true ~same_site:`Strict ~creation_time:(now ()) 75 + ~last_access:(now ()) () 92 76 ``` 93 77 94 78 ### Cookie Jar 95 79 96 80 ```ocaml 97 - let jar = Cookie_jar.v () 98 - let () = Cookie_jar.add_cookie jar cookie 99 - 100 - let matching = 101 - Cookie_jar.cookies jar 102 - ~clock 103 - ~domain:"example.com" 104 - ~path:"/api" 105 - ~is_secure:true 106 - 107 - let header = Cookie.cookie_header matching 81 + let api_cookies ~clock (cookie : Cookie.t) = 82 + let jar = Cookie_jar.v () in 83 + Cookie_jar.add_cookie jar cookie; 84 + let matching = 85 + Cookie_jar.cookies jar ~clock ~domain:"example.com" ~path:"/api" 86 + ~is_secure:true 87 + in 88 + Cookie.cookie_header matching 108 89 ``` 109 90 110 91 ### Delta Tracking 111 92 112 93 ```ocaml 113 - let new_cookies = Cookie_jar.delta jar 114 - let () = 115 - List.iter 116 - (fun c -> print_endline (Cookie.set_cookie_header c)) 117 - new_cookies 94 + let log_pending (jar : Cookie_jar.t) = 95 + Cookie_jar.delta jar 96 + |> List.iter (fun c -> Fmt.pr "%s@." (Cookie.set_cookie_header c)) 118 97 ``` 119 98 120 99 ### Persistence ··· 122 101 Cookies are persisted in Mozilla format: 123 102 124 103 ```ocaml 125 - let () = Cookie_jar.save path jar 126 - let jar = Cookie_jar.load ~clock path 104 + let save_jar ~path (jar : Cookie_jar.t) = Cookie_jar.save path jar 105 + let load_jar ~clock ~path = Cookie_jar.load ~clock path 127 106 ``` 128 107 129 108 ## Validation ··· 131 110 The `Cookie.Validate` module enforces RFC 6265 server requirements: 132 111 133 112 ```ocaml 134 - Cookie.Validate.cookie_name "session" (* Ok "session" *) 135 - Cookie.Validate.cookie_value "abc;123" (* Error "..." *) 136 - Cookie.Validate.domain_value "example.com" (* Ok "example.com" *) 113 + let () = assert (Cookie.Validate.cookie_name "session" = Ok "session") 114 + let () = assert (Result.is_error (Cookie.Validate.cookie_value "abc;123")) 115 + let () = assert (Cookie.Validate.domain_value "example.com" = Ok "example.com") 137 116 ``` 138 117 139 118 ## Licence
+1 -1
dune
··· 4 4 5 5 (mdx 6 6 (files README.md) 7 - (libraries nox-cookie nox-cookie.jar ptime.clock.os)) 7 + (libraries nox-cookie nox-cookie.jar ptime.clock.os fmt))
-3
lib/core/cookie.mli
··· 53 53 - IP addresses require exact match only 54 54 - Path matching requires exact match or prefix with "/" separator 55 55 56 - @see <https://datatracker.ietf.org/doc/html/rfc6265> 57 - RFC 6265 - HTTP State Management Mechanism 58 - 59 56 {2 Standards and References} 60 57 61 58 This library implements and references the following IETF specifications:
-3
lib/jar/cookie_jar.mli
··· 18 18 - Delta tracking for Set-Cookie headers 19 19 - Mozilla format persistence for cross-tool compatibility 20 20 21 - @see <https://datatracker.ietf.org/doc/html/rfc6265> 22 - RFC 6265 - HTTP State Management Mechanism 23 - 24 21 {2 Standards and References} 25 22 26 23 This cookie jar implements the storage model from: