-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdomain_name.mli
249 lines (182 loc) · 10.1 KB
/
domain_name.mli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
(* (c) 2017 Hannes Mehnert, all rights reserved *)
type 'a t
(** The type of a domain name, a sequence of labels separated by dots. Each
label may contain any bytes. The length of each label may not exceed 63
characters. The total length of a domain name is limited to 253 (its byte
representation is 255), but other protocols (such as SMTP) may apply even
smaller limits. A domain name label is case preserving, comparison is done
in a case insensitive manner. Every [t] is a fully qualified domain name,
its last label is the [root] label. The specification of domain names
originates from {{:https://tools.ietf.org/html/rfc1035}RFC 1035}.
The invariants on the length of domain names are preserved throughout the
module - no [t] will exist which violates these.
Phantom types are used for further name restrictions, {!host} checks for
host names ([`host t]): only letters, digits, and hyphen allowed, hyphen not
first character of a label, the last label must contain at least on letter.
{!service} checks for a service name ([`service t]): its first label is a
service name: 1-15 characters, no double-hyphen, hyphen not first or last
charactes, only letters, digits and hyphen allowed, and the second label is a
protocol ([_tcp] or [_udp] or [_sctp]).
When a [t] is constructed (either from a string, etc.), it is a [`raw t].
Subsequent modifications, such as adding or removing labels, appending, of
any kind of name also result in a [`raw t], which needs to be checked for
[`host t] (using {!host}) or [`service t] (using {!service}) if desired.
Constructing a [t] (via {!of_string}, {!of_string_exn}, {!of_strings} etc.)
does not require a trailing dot.
{e %%VERSION%% - {{:%%PKG_HOMEPAGE%% }homepage}} *)
(** {2 Constructor} *)
val root : [ `raw ] t
(** [root] is the root domain ("."), the empty label. *)
(** {2 String representation} *)
val of_string : string -> ([ `raw ] t, [> `Msg of string ]) result
(** [of_string name] is either [t], the domain name, or an error if the provided
[name] is not a valid domain name. A trailing dot is not requred. *)
val of_string_exn : string -> [ `raw ] t
(** [of_string_exn name] is [t], the domain name. A trailing dot is not
required.
@raise Invalid_argument if [name] is not a valid domain name. *)
val to_string : ?trailing:bool -> 'a t -> string
(** [to_string ~trailing t] is [String.concat ~sep:"." (to_strings t)], a
human-readable representation of [t]. If [trailing] is provided and
[true] (defaults to [false]), the resulting string will contain a trailing
dot. *)
(** {2 Predicates and basic operations} *)
val canonical : 'a t -> 'a t
(** [canonical t] is [t'], the canonical domain name, as specified in RFC 4034
(and 2535): all characters are lowercase. *)
val host : 'a t -> ([ `host ] t, [> `Msg of string ]) result
(** [host t] is a [`host t] if [t] is a hostname: the contents of the domain
name is limited: each label may start with a digit or letter, followed by
digits, letters, or hyphens. *)
val host_exn : 'a t -> [ `host ] t
(** [host_exn t] is a [`host t] if [t] is a hostname: the contents of the domain
name is limited: each label may start with a digit or letter, followed by
digits, letters, or hyphens.
@raise Invalid_argument if [t] is not a hostname. *)
val service : 'a t -> ([ `service ] t, [> `Msg of string ]) result
(** [service t] is [`service t] if [t] contains a service name, the following
conditions have to be met:
The first label is a service name (or port number); an underscore preceding
1-15 characters from the set [- a-z A-Z 0-9].
The service name may not contain a hyphen ([-]) following another hyphen;
no hyphen at the beginning or end.
The second label is the protocol, one of [_tcp], [_udp], or [_sctp].
The remaining labels must form a valid hostname.
This function can be used to validate RR's of the types SRV (RFC 2782)
and TLSA (RFC 7671). *)
val service_exn : 'a t -> [ `service ] t
(** [service_exn t] is [`service t] if [t] is a service name (see {!service}).
@raise Invalid_argument if [t] is not a service names. *)
val raw : 'a t -> [ `raw ] t
(** [raw t] is the [`raw t]. *)
val count_labels : 'a t -> int
(** [count_labels name] returns the amount of labels in [name]. *)
val is_subdomain : subdomain:'a t -> domain:'b t -> bool
(** [is_subdomain ~subdomain ~domain] is [true] if [subdomain] contains any
labels prepended to [domain]: [foo.bar.com] is a subdomain of [bar.com] and
of [com], [sub ~subdomain:x ~domain:root] is true for all [x]. *)
val get_label : ?rev:bool -> 'a t -> int -> (string, [> `Msg of string ]) result
(** [get_label ~rev name idx] retrieves the label at index [idx] from [name]. If
[idx] is out of bounds, an Error is returned. If [rev] is provided and [true]
(defaults to [false]), [idx] is from the end instead of the beginning. *)
val get_label_exn : ?rev:bool -> 'a t -> int -> string
(** [get_label_exn ~rev name idx] is the label at index [idx] in [name].
@raise Invalid_argument if [idx] is out of bounds in [name]. *)
val find_label : ?rev:bool -> 'a t -> (string -> bool) -> int option
(** [find_label ~rev name p] returns the first position where [p lbl] is [true]
in [name], if it exists, otherwise [None]. If [rev] is provided and [true]
(defaults to [false]), the [name] is traversed from the end instead of the
beginning. *)
val find_label_exn : ?rev:bool -> 'a t -> (string -> bool) -> int
(** [find_label_exn ~rev name p], see {!find_label}.
@raise Invalid_argument if [p] does not return [true] in [name]. *)
(** {2 Label addition and removal} *)
val prepend_label : 'a t -> string -> ([ `raw ] t, [> `Msg of string ]) result
(** [prepend_label name pre] is either [t], the new domain name, or an error. *)
val prepend_label_exn : 'a t -> string -> [ `raw ] t
(** [prepend_label_exn name pre] is [t], the new domain name.
@raise Invalid_argument if [pre] is not a valid domain name. *)
val drop_label : ?rev:bool -> ?amount:int -> 'a t ->
([ `raw ] t, [> `Msg of string ]) result
(** [drop_label ~rev ~amount t] is either [t], a domain name with [amount]
(defaults to [1]) labels dropped from the beginning - if [rev] is provided
and [true] (defaults to [false]) labels are dropped from the end.
[drop_label (of_string_exn "foo.com") = Ok (of_string_exn "com")],
[drop_label ~rev:true (of_string_exn "foo.com") = Ok (of_string_exn "foo")].
*)
val drop_label_exn : ?rev:bool -> ?amount:int -> 'a t -> [ `raw ] t
(** [drop_label_exn ~rev ~amount t], see {!drop_label}. Instead of a [result],
the value is returned directly.
@raise Invalid_argument if there are not sufficient labels. *)
val append : 'a t -> 'b t -> ([ `raw ] t, [> `Msg of string ]) result
(** [append pre post] is [pre ^ "." ^ post]. *)
val append_exn : 'a t -> 'b t -> [ `raw ] t
(** [append_exn pre post] is [pre ^ "." ^ post].
@raise Invalid_argument if the result would violate length restrictions. *)
(** {2 Comparison} *)
val equal : ?case_sensitive:bool -> 'a t -> 'b t -> bool
(** [equal ~case_sensitive t t'] is [true] if all labels of [t] and [t'] are
equal. If [case_sensitive] is provided and [true], the cases of the labels
are respected (defaults to [false]). *)
val compare : 'a t -> 'b t -> int
(** [compare t t'] compares the domain names [t] and [t'] using a case
insensitive string comparison. This conforms to the canonical DNS name
order, as described in RFC 4034, Section 6.1. *)
val equal_label : ?case_sensitive:bool -> string -> string -> bool
(** [equal_label ~case_sensitive a b] is [true] if [a] and [b] are equal
ignoring casing. If [case_sensitive] is provided and [true] (defaults to
[false]), the casing is respected. *)
val compare_label : string -> string -> int
(** [compare_label t t'] compares the labels [t] and [t'] using a case
insensitive string comparison. *)
(** {2 Collections} *)
module Host_map : sig
include Map.S with type key = [ `host ] t
(** [find key t] is [Some a] where a is the binding of [key] in [t]. [None] if
the [key] is not present. *)
val find : key -> 'a t -> 'a option
end
(** The module of a host name map *)
module Host_set : Set.S with type elt = [ `host ] t
(** The module of a host name set *)
module Service_map : sig
include Map.S with type key = [ `service ] t
(** [find key t] is [Some a] where a is the binding of [key] in [t]. [None] if
the [key] is not present. *)
val find : key -> 'a t -> 'a option
end
(** The module of a service name map *)
module Service_set : Set.S with type elt = [ `service ] t
(** The module of a service name set *)
module Map : sig
include Map.S with type key = [ `raw ] t
(** [find key t] is [Some a] where a is the binding of [key] in [t]. [None] if
the [key] is not present. *)
val find : key -> 'a t -> 'a option
end
(** The module of a domain name map *)
module Set : Set.S with type elt = [ `raw ] t
(** The module of a domain name set *)
(** {2 String list representation} *)
val of_strings : string list -> ([ `raw ] t, [> `Msg of string ]) result
(** [of_strings labels] is either [t], a domain name, or an error if
the provided [labels] violate domain name constraints. A trailing empty
label is not required. *)
val of_strings_exn : string list -> [ `raw ] t
(** [of_strings_exn labels] is [t], a domain name. A trailing empty
label is not required.
@raise Invalid_argument if [labels] are not a valid domain name. *)
val to_strings : ?trailing:bool -> 'a t -> string list
(** [to_strings ~trailing t] is the list of labels of [t]. If [trailing] is
provided and [true] (defaults to [false]), the resulting list will contain
a trailing empty label. *)
(** {2 Pretty printer} *)
val pp : Format.formatter -> 'a t -> unit
(** [pp ppf t] pretty prints the domain name [t] on [ppf]. *)
(**/**)
(* exposing internal structure, used by udns (but could as well use Obj.magic *)
val of_array : string array -> [ `raw ] t
(** [of_array a] is [t], a domain name from [a], an array containing a reversed
domain name. *)
val to_array : 'a t -> string array
(** [to_array t] is [a], an array containing the reversed domain name of [t]. *)