1-----------------------------------------------------------------------
2--  util-http-clients -- HTTP Clients
3--  Copyright (C) 2011, 2012, 2015 Stephane Carrez
4--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
5--
6--  Licensed under the Apache License, Version 2.0 (the "License");
7--  you may not use this file except in compliance with the License.
8--  You may obtain a copy of the License at
9--
10--      http://www.apache.org/licenses/LICENSE-2.0
11--
12--  Unless required by applicable law or agreed to in writing, software
13--  distributed under the License is distributed on an "AS IS" BASIS,
14--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15--  See the License for the specific language governing permissions and
16--  limitations under the License.
17-----------------------------------------------------------------------
18
19with Ada.Finalization;
20
21with Util.Http.Cookies;
22
23--  == Client ==
24--  The <tt>Util.Http.Clients</tt> package defines a set of API for an HTTP client to send
25--  requests to an HTTP server.
26--
27--  === GET request ===
28--  To retrieve a content using the HTTP GET operation, a client instance must be created.
29--  The response is returned in a specific object that must therefore be declared:
30--
31--    Http     : Util.Http.Clients.Client;
32--    Response : Util.Http.Clients.Response;
33--
34--  Before invoking the GET operation, the client can setup a number of HTTP headers.
35--
36--    Http.Add_Header ("X-Requested-By", "wget");
37--
38--  The GET operation is performed when the <tt>Get</tt> procedure is called:
39--
40--    Http.Get ("http://www.google.com", Response);
41--
42--  Once the response is received, the <tt>Response</tt> object contains the status of the
43--  HTTP response, the HTTP reply headers and the body.  A response header can be obtained
44--  by using the <tt>Get_Header</tt> function and the body using <tt>Get_Body</tt>:
45--
46--    Body : constant String := Response.Get_Body;
47--
48package Util.Http.Clients is
49
50   Connection_Error : exception;
51
52   --  ------------------------------
53   --  Http response
54   --  ------------------------------
55   --  The <b>Response</b> type represents a response returned by an HTTP request.
56   type Response is limited new Abstract_Response with private;
57
58   --  Returns a boolean indicating whether the named response header has already
59   --  been set.
60   overriding
61   function Contains_Header (Reply : in Response;
62                             Name  : in String) return Boolean;
63
64   --  Returns the value of the specified response header as a String. If the response
65   --  did not include a header of the specified name, this method returns null.
66   --  If there are multiple headers with the same name, this method returns the
67   --  first head in the request. The header name is case insensitive. You can use
68   --  this method with any response header.
69   overriding
70   function Get_Header (Reply  : in Response;
71                        Name   : in String) return String;
72
73   --  Sets a message header with the given name and value. If the header had already
74   --  been set, the new value overwrites the previous one. The containsHeader
75   --  method can be used to test for the presence of a header before setting its value.
76   overriding
77   procedure Set_Header (Reply    : in out Response;
78                         Name     : in String;
79                         Value    : in String);
80
81   --  Adds a request header with the given name and value.
82   --  This method allows request headers to have multiple values.
83   overriding
84   procedure Add_Header (Reply   : in out Response;
85                         Name    : in String;
86                         Value   : in String);
87
88   --  Iterate over the response headers and executes the <b>Process</b> procedure.
89   overriding
90   procedure Iterate_Headers (Reply   : in Response;
91                              Process : not null access
92                                procedure (Name  : in String;
93                                           Value : in String));
94
95   --  Get the response body as a string.
96   overriding
97   function Get_Body (Reply : in Response) return String;
98
99   --  Get the response status code.
100   overriding
101   function Get_Status (Reply : in Response) return Natural;
102
103   --  ------------------------------
104   --  Http client
105   --  ------------------------------
106   --  The <b>Client</b> type allows to execute HTTP GET/POST requests.
107   type Client is limited new Abstract_Request with private;
108   type Client_Access is access all Client;
109
110   --  Returns a boolean indicating whether the named response header has already
111   --  been set.
112   overriding
113   function Contains_Header (Request : in Client;
114                             Name    : in String) return Boolean;
115
116   --  Returns the value of the specified request header as a String. If the request
117   --  did not include a header of the specified name, this method returns null.
118   --  If there are multiple headers with the same name, this method returns the
119   --  first head in the request. The header name is case insensitive. You can use
120   --  this method with any response header.
121   overriding
122   function Get_Header (Request : in Client;
123                        Name    : in String) return String;
124
125   --  Sets a header with the given name and value. If the header had already
126   --  been set, the new value overwrites the previous one. The containsHeader
127   --  method can be used to test for the presence of a header before setting its value.
128   overriding
129   procedure Set_Header (Request  : in out Client;
130                         Name     : in String;
131                         Value    : in String);
132
133   --  Adds a header with the given name and value.
134   --  This method allows headers to have multiple values.
135   overriding
136   procedure Add_Header (Request  : in out Client;
137                         Name     : in String;
138                         Value    : in String);
139
140   --  Iterate over the request headers and executes the <b>Process</b> procedure.
141   overriding
142   procedure Iterate_Headers (Request : in Client;
143                              Process : not null access
144                                procedure (Name  : in String;
145                                           Value : in String));
146
147   --  Removes all headers with the given name.
148   procedure Remove_Header (Request : in out Client;
149                            Name    : in String);
150
151   --  Adds the specified cookie to the request.  This method can be called multiple
152   --  times to set more than one cookie.
153   procedure Add_Cookie (Http   : in out Client;
154                         Cookie : in Util.Http.Cookies.Cookie);
155
156   --  Execute an http GET request on the given URL.  Additional request parameters,
157   --  cookies and headers should have been set on the client object.
158   procedure Get (Request  : in out Client;
159                  URL      : in String;
160                  Reply    : out Response'Class);
161
162   --  Execute an http POST request on the given URL.  The post data is passed in <b>Data</b>.
163   --  Additional request cookies and headers should have been set on the client object.
164   procedure Post (Request : in out Client;
165                   URL     : in String;
166                   Data    : in String;
167                   Reply   : out Response'Class);
168
169private
170
171   subtype Http_Request is Abstract_Request;
172   subtype Http_Request_Access is Abstract_Request_Access;
173
174   subtype Http_Response is Abstract_Response;
175   subtype Http_Response_Access is Abstract_Response_Access;
176
177   type Http_Manager is interface;
178   type Http_Manager_Access is access all Http_Manager'Class;
179
180   procedure Create (Manager  : in Http_Manager;
181                     Http     : in out Client'Class) is abstract;
182
183   procedure Do_Get (Manager  : in Http_Manager;
184                     Http     : in Client'Class;
185                     URI      : in String;
186                     Reply    : out Response'Class) is abstract;
187
188   procedure Do_Post (Manager  : in Http_Manager;
189                      Http     : in Client'Class;
190                      URI      : in String;
191                      Data     : in String;
192                      Reply    : out Response'Class) is abstract;
193
194   Default_Http_Manager : Http_Manager_Access;
195
196   type Response is limited new Ada.Finalization.Limited_Controlled
197     and Abstract_Response with record
198      Delegate : Abstract_Response_Access;
199   end record;
200
201   --  Free the resource used by the response.
202   overriding
203   procedure Finalize (Reply : in out Response);
204
205   type Client is limited new Ada.Finalization.Limited_Controlled
206     and Abstract_Request with record
207      Manager  : Http_Manager_Access;
208      Delegate : Http_Request_Access;
209   end record;
210
211   --  Initialize the client
212   overriding
213   procedure Initialize (Http : in out Client);
214
215   overriding
216   procedure Finalize (Http : in out Client);
217
218end Util.Http.Clients;
219