1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
6 #define LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
7 
8 #include <limits>
9 #include <map>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include <base/macros.h>
16 #include <brillo/brillo_export.h>
17 #include <brillo/errors/error.h>
18 #include <brillo/http/http_connection.h>
19 #include <brillo/http/http_transport.h>
20 
21 namespace brillo {
22 namespace http {
23 
24 // HTTP request verbs
25 namespace request_type {
26 BRILLO_EXPORT extern const char kOptions[];
27 BRILLO_EXPORT extern const char kGet[];
28 BRILLO_EXPORT extern const char kHead[];
29 BRILLO_EXPORT extern const char kPost[];
30 BRILLO_EXPORT extern const char kPut[];
31 BRILLO_EXPORT extern const char kPatch[];  // Non-standard HTTP/1.1 verb
32 BRILLO_EXPORT extern const char kDelete[];
33 BRILLO_EXPORT extern const char kTrace[];
34 BRILLO_EXPORT extern const char kConnect[];
35 BRILLO_EXPORT extern const char kCopy[];   // Non-standard HTTP/1.1 verb
36 BRILLO_EXPORT extern const char kMove[];   // Non-standard HTTP/1.1 verb
37 }  // namespace request_type
38 
39 // HTTP request header names
40 namespace request_header {
41 BRILLO_EXPORT extern const char kAccept[];
42 BRILLO_EXPORT extern const char kAcceptCharset[];
43 BRILLO_EXPORT extern const char kAcceptEncoding[];
44 BRILLO_EXPORT extern const char kAcceptLanguage[];
45 BRILLO_EXPORT extern const char kAllow[];
46 BRILLO_EXPORT extern const char kAuthorization[];
47 BRILLO_EXPORT extern const char kCacheControl[];
48 BRILLO_EXPORT extern const char kConnection[];
49 BRILLO_EXPORT extern const char kContentEncoding[];
50 BRILLO_EXPORT extern const char kContentLanguage[];
51 BRILLO_EXPORT extern const char kContentLength[];
52 BRILLO_EXPORT extern const char kContentLocation[];
53 BRILLO_EXPORT extern const char kContentMd5[];
54 BRILLO_EXPORT extern const char kContentRange[];
55 BRILLO_EXPORT extern const char kContentType[];
56 BRILLO_EXPORT extern const char kCookie[];
57 BRILLO_EXPORT extern const char kDate[];
58 BRILLO_EXPORT extern const char kExpect[];
59 BRILLO_EXPORT extern const char kExpires[];
60 BRILLO_EXPORT extern const char kFrom[];
61 BRILLO_EXPORT extern const char kHost[];
62 BRILLO_EXPORT extern const char kIfMatch[];
63 BRILLO_EXPORT extern const char kIfModifiedSince[];
64 BRILLO_EXPORT extern const char kIfNoneMatch[];
65 BRILLO_EXPORT extern const char kIfRange[];
66 BRILLO_EXPORT extern const char kIfUnmodifiedSince[];
67 BRILLO_EXPORT extern const char kLastModified[];
68 BRILLO_EXPORT extern const char kMaxForwards[];
69 BRILLO_EXPORT extern const char kPragma[];
70 BRILLO_EXPORT extern const char kProxyAuthorization[];
71 BRILLO_EXPORT extern const char kRange[];
72 BRILLO_EXPORT extern const char kReferer[];
73 BRILLO_EXPORT extern const char kTE[];
74 BRILLO_EXPORT extern const char kTrailer[];
75 BRILLO_EXPORT extern const char kTransferEncoding[];
76 BRILLO_EXPORT extern const char kUpgrade[];
77 BRILLO_EXPORT extern const char kUserAgent[];
78 BRILLO_EXPORT extern const char kVia[];
79 BRILLO_EXPORT extern const char kWarning[];
80 }  // namespace request_header
81 
82 // HTTP response header names
83 namespace response_header {
84 BRILLO_EXPORT extern const char kAcceptRanges[];
85 BRILLO_EXPORT extern const char kAge[];
86 BRILLO_EXPORT extern const char kAllow[];
87 BRILLO_EXPORT extern const char kCacheControl[];
88 BRILLO_EXPORT extern const char kConnection[];
89 BRILLO_EXPORT extern const char kContentEncoding[];
90 BRILLO_EXPORT extern const char kContentLanguage[];
91 BRILLO_EXPORT extern const char kContentLength[];
92 BRILLO_EXPORT extern const char kContentLocation[];
93 BRILLO_EXPORT extern const char kContentMd5[];
94 BRILLO_EXPORT extern const char kContentRange[];
95 BRILLO_EXPORT extern const char kContentType[];
96 BRILLO_EXPORT extern const char kDate[];
97 BRILLO_EXPORT extern const char kETag[];
98 BRILLO_EXPORT extern const char kExpires[];
99 BRILLO_EXPORT extern const char kLastModified[];
100 BRILLO_EXPORT extern const char kLocation[];
101 BRILLO_EXPORT extern const char kPragma[];
102 BRILLO_EXPORT extern const char kProxyAuthenticate[];
103 BRILLO_EXPORT extern const char kRetryAfter[];
104 BRILLO_EXPORT extern const char kServer[];
105 BRILLO_EXPORT extern const char kSetCookie[];
106 BRILLO_EXPORT extern const char kTrailer[];
107 BRILLO_EXPORT extern const char kTransferEncoding[];
108 BRILLO_EXPORT extern const char kUpgrade[];
109 BRILLO_EXPORT extern const char kVary[];
110 BRILLO_EXPORT extern const char kVia[];
111 BRILLO_EXPORT extern const char kWarning[];
112 BRILLO_EXPORT extern const char kWwwAuthenticate[];
113 }  // namespace response_header
114 
115 // HTTP request status (error) codes
116 namespace status_code {
117 // OK to continue with request
118 static const int Continue = 100;
119 // Server has switched protocols in upgrade header
120 static const int SwitchProtocols = 101;
121 
122 // Request completed
123 static const int Ok = 200;
124 // Object created, reason = new URI
125 static const int Created = 201;
126 // Async completion (TBS)
127 static const int Accepted = 202;
128 // Partial completion
129 static const int Partial = 203;
130 // No info to return
131 static const int NoContent = 204;
132 // Request completed, but clear form
133 static const int ResetContent = 205;
134 // Partial GET fulfilled
135 static const int PartialContent = 206;
136 
137 // Server couldn't decide what to return
138 static const int Ambiguous = 300;
139 // Object permanently moved
140 static const int Moved = 301;
141 // Object temporarily moved
142 static const int Redirect = 302;
143 // Redirection w/ new access method
144 static const int RedirectMethod = 303;
145 // If-Modified-Since was not modified
146 static const int NotModified = 304;
147 // Redirection to proxy, location header specifies proxy to use
148 static const int UseProxy = 305;
149 // HTTP/1.1: keep same verb
150 static const int RedirectKeepVerb = 307;
151 
152 // Invalid syntax
153 static const int BadRequest = 400;
154 // Access denied
155 static const int Denied = 401;
156 // Payment required
157 static const int PaymentRequired = 402;
158 // Request forbidden
159 static const int Forbidden = 403;
160 // Object not found
161 static const int NotFound = 404;
162 // Method is not allowed
163 static const int BadMethod = 405;
164 // No response acceptable to client found
165 static const int NoneAcceptable = 406;
166 // Proxy authentication required
167 static const int ProxyAuthRequired = 407;
168 // Server timed out waiting for request
169 static const int RequestTimeout = 408;
170 // User should resubmit with more info
171 static const int Conflict = 409;
172 // The resource is no longer available
173 static const int Gone = 410;
174 // The server refused to accept request w/o a length
175 static const int LengthRequired = 411;
176 // Precondition given in request failed
177 static const int PrecondionFailed = 412;
178 // Request entity was too large
179 static const int RequestTooLarge = 413;
180 // Request URI too long
181 static const int UriTooLong = 414;
182 // Unsupported media type
183 static const int UnsupportedMedia = 415;
184 // Retry after doing the appropriate action.
185 static const int RetryWith = 449;
186 
187 // Internal server error
188 static const int InternalServerError = 500;
189 // Request not supported
190 static const int NotSupported = 501;
191 // Error response received from gateway
192 static const int BadGateway = 502;
193 // Temporarily overloaded
194 static const int ServiceUnavailable = 503;
195 // Timed out waiting for gateway
196 static const int GatewayTimeout = 504;
197 // HTTP version not supported
198 static const int VersionNotSupported = 505;
199 }  // namespace status_code
200 
201 class Response;  // Just a forward declaration.
202 class FormData;
203 
204 ///////////////////////////////////////////////////////////////////////////////
205 // Request class is the main object used to set up and initiate an HTTP
206 // communication session. It is used to specify the HTTP request method,
207 // request URL and many optional parameters (such as HTTP headers, user agent,
208 // referer URL and so on.
209 //
210 // Once everything is setup, GetResponse() method is used to send the request
211 // and obtain the server response. The returned Response object can be
212 // used to inspect the response code, HTTP headers and/or response body.
213 ///////////////////////////////////////////////////////////////////////////////
214 class BRILLO_EXPORT Request final {
215  public:
216   // The main constructor. |url| specifies the remote host address/path
217   // to send the request to. |method| is the HTTP request verb and
218   // |transport| is the HTTP transport implementation for server communications.
219   Request(const std::string& url,
220           const std::string& method,
221           std::shared_ptr<Transport> transport);
222   ~Request();
223 
224   // Gets/Sets "Accept:" header value. The default value is "*/*" if not set.
225   void SetAccept(const std::string& accept_mime_types);
226   const std::string& GetAccept() const;
227 
228   // Gets/Sets "Content-Type:" header value
229   void SetContentType(const std::string& content_type);
230   const std::string& GetContentType() const;
231 
232   // Adds additional HTTP request header
233   void AddHeader(const std::string& header, const std::string& value);
234   void AddHeaders(const HeaderList& headers);
235 
236   // Removes HTTP request header
237   void RemoveHeader(const std::string& header);
238 
239   // Adds a request body. This is not to be used with GET method
240   bool AddRequestBody(const void* data, size_t size, brillo::ErrorPtr* error);
241   bool AddRequestBody(StreamPtr stream, brillo::ErrorPtr* error);
242 
243   // Adds a request body. This is not to be used with GET method.
244   // This method also sets the correct content-type of the request, including
245   // the multipart data boundary.
246   bool AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,
247                                 brillo::ErrorPtr* error);
248 
249   // Adds a stream for the response. Otherwise a MemoryStream will be used.
250   bool AddResponseStream(StreamPtr stream, brillo::ErrorPtr* error);
251 
252   // Makes a request for a subrange of data. Specifies a partial range with
253   // either from beginning of the data to the specified offset (if |bytes| is
254   // negative) or from the specified offset to the end of data (if |bytes| is
255   // positive).
256   // All individual ranges will be sent as part of "Range:" HTTP request header.
257   void AddRange(int64_t bytes);
258 
259   // Makes a request for a subrange of data. Specifies a full range with
260   // start and end bytes from the beginning of the requested data.
261   // All individual ranges will be sent as part of "Range:" HTTP request header.
262   void AddRange(uint64_t from_byte, uint64_t to_byte);
263 
264   // Returns the request URL
265   const std::string& GetRequestURL() const;
266 
267   // Returns the request verb.
268   const std::string& GetRequestMethod() const;
269 
270   // Gets/Sets a request referer URL (sent as "Referer:" request header).
271   void SetReferer(const std::string& referer);
272   const std::string& GetReferer() const;
273 
274   // Gets/Sets a user agent string (sent as "User-Agent:" request header).
275   void SetUserAgent(const std::string& user_agent);
276   const std::string& GetUserAgent() const;
277 
278   // Sends the request to the server and blocks until the response is received,
279   // which is returned as the response object.
280   // In case the server couldn't be reached for whatever reason, returns
281   // empty unique_ptr (null). In such a case, the additional error information
282   // can be returned through the optional supplied |error| parameter.
283   std::unique_ptr<Response> GetResponseAndBlock(brillo::ErrorPtr* error);
284 
285   // Sends out the request and invokes the |success_callback| when the response
286   // is received. In case of an error, the |error_callback| is invoked.
287   // Returns the ID of the asynchronous request created.
288   RequestID GetResponse(const SuccessCallback& success_callback,
289                         const ErrorCallback& error_callback);
290 
291  private:
292   friend class HttpRequestTest;
293 
294   // Helper function to create an http::Connection and send off request headers.
295   BRILLO_PRIVATE bool SendRequestIfNeeded(brillo::ErrorPtr* error);
296 
297   // Implementation that provides particular HTTP transport.
298   std::shared_ptr<Transport> transport_;
299 
300   // An established connection for adding request body. This connection
301   // is maintained by the request object after the headers have been
302   // sent and before the response is requested.
303   std::shared_ptr<Connection> connection_;
304 
305   // Full request URL, such as "http://www.host.com/path/to/object"
306   const std::string request_url_;
307   // HTTP request verb, such as "GET", "POST", "PUT", ...
308   const std::string method_;
309 
310   // Referrer URL, if any. Sent to the server via "Referer: " header.
311   std::string referer_;
312   // User agent string, if any. Sent to the server via "User-Agent: " header.
313   std::string user_agent_;
314   // Content type of the request body data.
315   // Sent to the server via "Content-Type: " header.
316   std::string content_type_;
317   // List of acceptable response data types.
318   // Sent to the server via "Accept: " header.
319   std::string accept_ = "*/*";
320 
321   // List of optional request headers provided by the caller.
322   std::multimap<std::string, std::string> headers_;
323   // List of optional data ranges to request partial content from the server.
324   // Sent to the server as "Range: " header.
325   std::vector<std::pair<uint64_t, uint64_t>> ranges_;
326 
327   // range_value_omitted is used in |ranges_| list to indicate omitted value.
328   // E.g. range (10,range_value_omitted) represents bytes from 10 to the end
329   // of the data stream.
330   const uint64_t range_value_omitted = std::numeric_limits<uint64_t>::max();
331 
332   DISALLOW_COPY_AND_ASSIGN(Request);
333 };
334 
335 ///////////////////////////////////////////////////////////////////////////////
336 // Response class is returned from Request::GetResponse() and is a way
337 // to get to response status, error codes, response HTTP headers and response
338 // data (body) if available.
339 ///////////////////////////////////////////////////////////////////////////////
340 class BRILLO_EXPORT Response final {
341  public:
342   explicit Response(const std::shared_ptr<Connection>& connection);
343   ~Response();
344 
345   // Returns true if server returned a success code (status code below 400).
346   bool IsSuccessful() const;
347 
348   // Returns the HTTP status code (e.g. 200 for success)
349   int GetStatusCode() const;
350 
351   // Returns the status text (e.g. for error 403 it could be "NOT AUTHORIZED").
352   std::string GetStatusText() const;
353 
354   // Returns the content type of the response data.
355   std::string GetContentType() const;
356 
357   // Returns response data stream by transferring ownership of the data stream
358   // from Response class to the caller.
359   StreamPtr ExtractDataStream(ErrorPtr* error);
360 
361   // Extracts the data from the underlying response data stream as a byte array.
362   std::vector<uint8_t> ExtractData();
363 
364   // Extracts the data from the underlying response data stream as a string.
365   std::string ExtractDataAsString();
366 
367   // Returns a value of a given response HTTP header.
368   std::string GetHeader(const std::string& header_name) const;
369 
370  private:
371   friend class HttpRequestTest;
372 
373   std::shared_ptr<Connection> connection_;
374 
375   DISALLOW_COPY_AND_ASSIGN(Response);
376 };
377 
378 }  // namespace http
379 }  // namespace brillo
380 
381 #endif  // LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
382