(*---------------------------------------------------------------------------*
  INTERFACE  cf_uri.mli

  Copyright (c) 2003-2006, James H. Woodyatt
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *---------------------------------------------------------------------------*)

(** Operations with Universal Resource Identifier (URI).

    This module implements types for constructing and deconstructing Universal
    Resource Identifiers (URI), as well as convenience functions for
    manipulating their components, and also functions for parsing and emitting
    them as strings.
*)

(** {6 Types} *)

(** The sum type of "host" components of hierarchical URI's. *)
type host =
    | H_hostname of string
    | H_ip4_addr of Cf_ip4_addr.opaque Cf_ip4_addr.t

(** The type of "server" components of hierarchical URI's. *)
type server = {
    srv_user: string option;    (** An optional user name. *)
    srv_host: host;             (** The hostname or IPv4 address. *)
    srv_port: int option;       (** An optional port number. *)
}

(** The type of "authority" components of hierarchical URI's. *)
type authority =
    | A_server of server option     (** Server-based naming authority. *)
    | A_reg_name of string          (** Registry-based naming authority. *)

(** The type of path segments in hierarchical URI's. *)
type segment = {
    seg_name: string;               (** Segment name. *)
    seg_params: string list;        (** Segment parameters list. *)
}

(** The type of network paths in hierarchical URI's. *)
type net_path = {
    net_authority: authority;       (** Naming authority. *)
    net_path: segment list;         (** List of path segments. *)
}

(** The type of hierarchical URI network paths. *)
type net = [ `Net of net_path ]

(** The type of hierarchical URI absolute paths. *)
type abs = [ `Abs of segment * segment list ]

(** The type of hierarchical URI relative paths. *)
type rel = [ `Rel of segment list ]

(** The sum type of hierarchical URI paths. *)
type path = [ net | abs | rel ]

(** The type of absolute hierarchical URI paths with optional query parts. *)
type abs_special_hier = {
    abs_hier_path: [ net | abs ];       (** Path. *)
    abs_hier_query: string option;      (** Query part. *)
}

(** The sum type of absolute URI parts. *)
type abs_special =
    | S_hier of abs_special_hier        (** Hierarchical URI part. *)
    | S_opaque of string                (** Opaque URI part. *)

(** The type of absolute URI. *)
type absolute = {
    abs_scheme: string;             (** URI scheme name. *)
    abs_special: abs_special;       (** Absolute URI part. *)
}

(** The type of relative URI. *)
type relative = {
    rel_path: path;                 (** Path. *)
    rel_query: string option;       (** Query part. *)
}

(** The type of URI. *)
type t = A of absolute | R of relative

(** The type of URI references. *)
type reference = {
    ref_uri: t;                     (** URI *)
    ref_fragment: string option;    (** Optional fragment suffix. *)
}

(** The exception raised when a relative URI has no defined reference to an
    absolute URI for a given base, i.e. too many ".." segments.
*)
exception Rel_undefined

(** {6 Functions} *)

(** Use [escape ?allow s] to obtain a new string by replacing all the
    unreserved and "mark" characters in the string [s] with the equivalent URI
    escape sequence.  The optional [allow] function, if specified, can be used
    to prevent the escape of characters for which the function returns [true].
*)
val escape: ?allow:(char -> bool) -> string -> string

(** Use [unescape s] to obtain a new string by replacing all the URI escape
    sequences in the string [s] with the actual character they denote.
*)
val unescape: string -> string

(** Use [refer_to_base ~base ~rel] to compose an absolute URI by directing the
    relative URI [rel] from the base absolute URI [base].  Raises
    [Invalid_argument] if the base URI is opaque, and raises [Rel_undefined]
    if the URI cannot be referred, i.e. too many ".." segments.
*)
val refer_to_base: base:absolute -> rel:relative -> absolute

(** Use [message_to_uri m] to create a URI by parsing the contents of the
    message [m].  Raises [Invalid_argument] if the message does not contain a
    valid URI.
*)
val message_to_uri: Cf_message.t -> t

(** Use [message_to_absolute_uri ~base m] to create an absolute URI by parsing
    the contents of the message [m] and using [base] as the absolute URI for
    reference in parsing relative URI.  Raises [Invalid_argument] if the
    message does not contain a valid URI, or the base URI is opaque.  Raises
    [Rel_undefined] if the message contains a relative URI that cannot be
    referred by the base URI.
*)
val message_to_absolute_uri: base:absolute -> Cf_message.t -> absolute

(** Use [message_to_uri_reference m] to create a URI reference by parsing the
    contents of the message [m].  Raises [Invalid_argument] if the message does
    not contain a valid URI reference.
*)
val message_to_uri_reference: Cf_message.t -> reference

(** Use [message_to_absolute_uri_reference ~base m] to create a URI reference
    to an absolute URI by parsing the contents of the message [m] and using
    [base] as the absolute URI for reference parsing relative URI.  Raises
    [Invalid_argument] if the message does not contain a valid URI, or the base
    URI is opaque.  Raises [Rel_undefined] if the message contains a relative
    URI that cannot be referred by the base URI.
*)
val message_to_absolute_uri_reference:
    base:absolute -> Cf_message.t -> reference

(** Use [emit_host pp host] to print the host part of a URI [host] with the
    formatter [pp].  Reserved characters in the host name are escaped in the
    output.
*)
val emit_host: Format.formatter -> host -> unit

(** Use [emit_server pp server] to print the server part of a URI [server] with
    the formatter [pp].  Reserved characters in the host name or user name are
    escaped in the output.
*)
val emit_server: Format.formatter -> server -> unit

(** Use [emit_authority pp auth] to print the name authority part of a URI
    [authority] with the formatter [pp].  Reserved characters are escaped
    appropriately.
*)
val emit_authority: Format.formatter -> authority -> unit

(** Use [emit_path pp path] to print the path component of a URI [path] with
    the formatter [pp].  Reserved characters in the path segments or path
    segment parameter lists are escaped in the output.
*)
val emit_path: Format.formatter -> [< path ] -> unit

(** Use [emit_abs_special pp abs] to print the absolute URI specialization
    [abs] with the formatter [pp].  All reserved characters are escaped
    appropriately in the output.
*)
val emit_abs_special: Format.formatter -> abs_special -> unit

(** Use [emit_uri pp uri] to print the URI [uri] with the formatter [pp].  All
    reserved characters are escaped appropriately in the output.
*)
val emit_uri: Format.formatter -> t -> unit

(** Use [emit_uri_reference pp uriref] to print the URI reference [uriref] with
    the formatter [pp].  All reserved characters are escaped appropriately in
    the output.
*)
val emit_uri_reference: Format.formatter -> reference -> unit

(** Use [message_of_uri uri] to produce a message containing the formatted URI
    string produced by emitting [uri] into a string.
*)
val message_of_uri: t -> Cf_message.t

(** Use [message_of_uri_reference uriref] to produce a message containing the
    formatted URI reference string produced by emitting [uriref] into a string.
*)
val message_of_uri_reference: reference -> Cf_message.t

(*--- End of File [ cf_uri.mli ] ---*)
