My agentic slop goes here. Not intended for anyone else!
1(** HTTP request body construction
2
3 This module provides various ways to construct HTTP request bodies,
4 including strings, files, streams, forms, and multipart data.
5
6 {2 Examples}
7
8 {[
9 (* Simple text body *)
10 let body = Body.text "Hello, World!"
11
12 (* JSON body *)
13 let body = Body.json {|{"name": "Alice", "age": 30}|}
14
15 (* Form data *)
16 let body = Body.form [
17 ("username", "alice");
18 ("password", "secret")
19 ]
20
21 (* File upload *)
22 let body = Body.of_file ~mime:Mime.pdf (Eio.Path.(fs / "document.pdf"))
23
24 (* Multipart form with file *)
25 let body = Body.multipart [
26 { name = "field"; filename = None;
27 content_type = Mime.text_plain;
28 content = `String "value" };
29 { name = "file"; filename = Some "photo.jpg";
30 content_type = Mime.jpeg;
31 content = `File (Eio.Path.(fs / "photo.jpg")) }
32 ]
33 ]}
34*)
35
36(** Log source for body operations *)
37val src : Logs.Src.t
38
39type t
40(** Abstract body type representing HTTP request body content. *)
41
42(** {1 Basic Constructors} *)
43
44val empty : t
45(** [empty] creates an empty body (no content). *)
46
47val of_string : Mime.t -> string -> t
48(** [of_string mime content] creates a body from a string with the specified MIME type.
49 Example: [of_string Mime.json {|{"key": "value"}|}] *)
50
51val of_stream : ?length:int64 -> Mime.t -> Eio.Flow.source_ty Eio.Resource.t -> t
52(** [of_stream ?length mime stream] creates a streaming body. If [length] is provided,
53 it will be used for the Content-Length header, otherwise chunked encoding is used. *)
54
55val of_file : ?mime:Mime.t -> _ Eio.Path.t -> t
56(** [of_file ?mime path] creates a body from a file. The MIME type is inferred from
57 the file extension if not provided. *)
58
59(** {1 Convenience Constructors} *)
60
61val json : Jsont.json -> t
62(** [json value] creates a JSON body from a Jsont.json value.
63 The value is encoded to a JSON string with Content-Type: application/json.
64
65 Example:
66 {[
67 let body = Body.json (Jsont.Object ([
68 ("status", Jsont.String "success");
69 ("count", Jsont.Number 42.);
70 ("items", Jsont.Array ([Jsont.String "first"; Jsont.String "second"], Jsont.Meta.none))
71 ], Jsont.Meta.none))
72 ]}
73*)
74
75val json_stream : Jsont.json -> t
76(** [json_stream json_value] creates a streaming JSON body from a Jsont.json value.
77 The JSON value will be encoded to a minified JSON string and streamed.
78
79 Example:
80 {[
81 let large_data = Jsont.Object ([
82 ("users", Jsont.Array ([...], Jsont.Meta.none))
83 ], Jsont.Meta.none) in
84 let body = Body.json_stream large_data
85 ]}
86*)
87
88val text : string -> t
89(** [text str] creates a plain text body with Content-Type: text/plain. *)
90
91val form : (string * string) list -> t
92(** [form fields] creates a URL-encoded form body with Content-Type: application/x-www-form-urlencoded.
93 Example: [form [("username", "alice"); ("password", "secret")]] *)
94
95(** {1 Multipart Support} *)
96
97type 'a part = {
98 name : string; (** Form field name *)
99 filename : string option; (** Optional filename for file uploads *)
100 content_type : Mime.t; (** MIME type of this part *)
101 content : [
102 | `String of string (** String content *)
103 | `Stream of Eio.Flow.source_ty Eio.Resource.t (** Streaming content *)
104 | `File of 'a Eio.Path.t (** File content *)
105 ];
106}
107(** A single part in a multipart body. *)
108
109val multipart : _ part list -> t
110(** [multipart parts] creates a multipart/form-data body from a list of parts.
111 This is commonly used for file uploads and complex form submissions.
112
113 Example:
114 {[
115 let body = Body.multipart [
116 { name = "username"; filename = None;
117 content_type = Mime.text_plain;
118 content = `String "alice" };
119 { name = "avatar"; filename = Some "photo.jpg";
120 content_type = Mime.jpeg;
121 content = `File (Eio.Path.(fs / "photo.jpg")) }
122 ]
123 ]}
124*)
125
126(** {1 Properties} *)
127
128val content_type : t -> Mime.t option
129(** [content_type body] returns the MIME type of the body, if set. *)
130
131val content_length : t -> int64 option
132(** [content_length body] returns the content length in bytes, if known.
133 Returns [None] for streaming bodies without a predetermined length. *)
134
135(** {1 Private API} *)
136
137(** Internal functions exposed for use by other modules in the library.
138 These are not part of the public API and may change between versions. *)
139module Private : sig
140 val to_cohttp_body : sw:Eio.Switch.t -> t -> Cohttp_eio.Body.t option
141 (** [to_cohttp_body ~sw body] converts the body to cohttp-eio format.
142 Uses the switch to manage resources like file handles.
143 This function is used internally by the Client module. *)
144
145 val to_string : t -> string
146 (** [to_string body] converts the body to a string for HTTP/1.1 requests.
147 Only works for materialized bodies (String type).
148 Raises Failure for streaming/file/multipart bodies. *)
149end