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: rename cookie_header / cookie_attributes (drop module-prefix dup)

The merlint redundant-prefix check flagged [Cookie.cookie_header] and the
internal [Cookie.cookie_attributes] type. Rename to:

- type [cookie_attributes] -> [attributes] (file-local).
- val [cookie_header] -> [request_header] (build the HTTP "Cookie:"
request header).
- val [of_cookie_header] -> [of_request_header] (parse the same).

[set_cookie_header] / [of_set_cookie_header] keep their names — the
"Set-Cookie" prefix is the canonical HTTP header name and merlint
already accepts it.

ocaml-requests is the only downstream caller and is updated in step.

93 cookie tests pass; merlint clean on ocaml-cookie.

+19 -18
+3 -3
README.md
··· 55 55 56 56 (* Parse a Cookie request header *) 57 57 let parse_cookies = 58 - Cookie.of_cookie_header ~now ~domain:"example.com" ~path:"/" 58 + Cookie.of_request_header ~now ~domain:"example.com" ~path:"/" 59 59 "session=abc123; theme=dark" 60 60 ``` 61 61 62 62 ### Serializing Headers 63 63 64 64 ```ocaml 65 - let render_request (cookies : Cookie.t list) = Cookie.cookie_header cookies 65 + let render_request (cookies : Cookie.t list) = Cookie.request_header cookies 66 66 let render_response (cookie : Cookie.t) = Cookie.set_cookie_header cookie 67 67 ``` 68 68 ··· 85 85 Cookie_jar.cookies jar ~clock ~domain:"example.com" ~path:"/api" 86 86 ~is_secure:true 87 87 in 88 - Cookie.cookie_header matching 88 + Cookie.request_header matching 89 89 ``` 90 90 91 91 ### Delta Tracking
+3 -3
lib/core/cookie.ml
··· 591 591 592 592 (** {1 Cookie Parsing} *) 593 593 594 - type cookie_attributes = { 594 + type attributes = { 595 595 mutable domain : string option; 596 596 mutable path : string option; 597 597 mutable secure : bool; ··· 921 921 in 922 922 Ok (cookie, cookie_name))) 923 923 924 - let of_cookie_header ~now ~domain ~path header_value = 924 + let of_request_header ~now ~domain ~path header_value = 925 925 Log.debug (fun m -> 926 926 let names = 927 927 String.split_on_char ';' header_value ··· 964 964 965 965 @see <https://datatracker.ietf.org/doc/html/rfc6265#section-4.2> 966 966 RFC 6265 Section 4.2 - The Cookie Header *) 967 - let cookie_header cookies = 967 + let request_header cookies = 968 968 cookies 969 969 |> List.map (fun c -> Fmt.str "%s=%s" (name c) (value c)) 970 970 |> String.concat "; "
+7 -6
lib/core/cookie.mli
··· 544 544 RFC 6265 Section 5.3 - Storage Model (public suffix check) 545 545 @see <https://publicsuffix.org/list/> Public Suffix List. *) 546 546 547 - val of_cookie_header : 547 + val of_request_header : 548 548 now:(unit -> Ptime.t) -> 549 549 domain:string -> 550 550 path:string -> 551 551 string -> 552 552 (t list, string) result 553 - (** [of_cookie_header ~now ~domain ~path s] parses a Cookie request header 553 + (** [of_request_header ~now ~domain ~path s] parses a Cookie request header 554 554 containing semicolon-separated name=value pairs. 555 555 556 556 Parses a Cookie header following ··· 577 577 let now () = Ptime.epoch 578 578 579 579 let cookies = 580 - Cookie.of_cookie_header ~now ~domain:"example.com" ~path:"/" 580 + Cookie.of_request_header ~now ~domain:"example.com" ~path:"/" 581 581 "session=abc; theme=dark" 582 582 |> Result.get_ok 583 583 ··· 588 588 @see <https://datatracker.ietf.org/doc/html/rfc6265#section-4.2> 589 589 RFC 6265 Section 4.2 - The Cookie Header. *) 590 590 591 - val cookie_header : t list -> string 592 - (** [cookie_header cookies] creates a Cookie header value from cookies. 591 + val request_header : t list -> string 592 + (** [request_header cookies] creates a Cookie header value from cookies. 593 593 594 594 Formats a list of cookies into a Cookie header value suitable for HTTP 595 595 requests per ··· 599 599 - Only includes cookie names and values, not attributes 600 600 - Cookies should already be filtered for the target domain/path 601 601 602 - Example: [cookie_header cookies] might return ["session=abc123; theme=dark"] 602 + Example: [request_header cookies] might return 603 + ["session=abc123; theme=dark"] 603 604 604 605 @see <https://datatracker.ietf.org/doc/html/rfc6265#section-4.2> 605 606 RFC 6265 Section 4.2 - The Cookie Header. *)
+6 -6
test/test_cookie.ml
··· 1795 1795 Eio_main.run @@ fun env -> 1796 1796 let clock = Eio.Stdenv.clock env in 1797 1797 let result = 1798 - of_cookie_header 1798 + of_request_header 1799 1799 ~now:(fun () -> 1800 1800 Ptime.of_float_s (Eio.Time.now clock) 1801 1801 |> Option.value ~default:Ptime.epoch) ··· 1817 1817 let clock = Eio.Stdenv.clock env in 1818 1818 1819 1819 match 1820 - of_cookie_header 1820 + of_request_header 1821 1821 ~now:(fun () -> 1822 1822 Ptime.of_float_s (Eio.Time.now clock) 1823 1823 |> Option.value ~default:Ptime.epoch) ··· 1848 1848 1849 1849 let test input expected_count description = 1850 1850 let result = 1851 - of_cookie_header 1851 + of_request_header 1852 1852 ~now:(fun () -> 1853 1853 Ptime.of_float_s (Eio.Time.now clock) 1854 1854 |> Option.value ~default:Ptime.epoch) ··· 1872 1872 1873 1873 (* Invalid cookie (empty name) should cause entire parse to fail *) 1874 1874 let result = 1875 - of_cookie_header 1875 + of_request_header 1876 1876 ~now:(fun () -> 1877 1877 Ptime.of_float_s (Eio.Time.now clock) 1878 1878 |> Option.value ~default:Ptime.epoch) ··· 2076 2076 2077 2077 (* Cookies from Cookie header should have host_only=true *) 2078 2078 let result = 2079 - of_cookie_header 2079 + of_request_header 2080 2080 ~now:(fun () -> 2081 2081 Ptime.of_float_s (Eio.Time.now clock) 2082 2082 |> Option.value ~default:Ptime.epoch) ··· 2885 2885 2886 2886 (* Duplicate cookie names should be rejected *) 2887 2887 let result = 2888 - of_cookie_header 2888 + of_request_header 2889 2889 ~now:(fun () -> 2890 2890 Ptime.of_float_s (Eio.Time.now clock) 2891 2891 |> Option.value ~default:Ptime.epoch)