1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li
5*1a96fba6SXin Li #include <brillo/http/http_request.h>
6*1a96fba6SXin Li
7*1a96fba6SXin Li #include <base/bind.h>
8*1a96fba6SXin Li #include <base/callback.h>
9*1a96fba6SXin Li #include <base/logging.h>
10*1a96fba6SXin Li #include <brillo/http/http_form_data.h>
11*1a96fba6SXin Li #include <brillo/map_utils.h>
12*1a96fba6SXin Li #include <brillo/mime_utils.h>
13*1a96fba6SXin Li #include <brillo/streams/memory_stream.h>
14*1a96fba6SXin Li #include <brillo/strings/string_utils.h>
15*1a96fba6SXin Li
16*1a96fba6SXin Li namespace brillo {
17*1a96fba6SXin Li namespace http {
18*1a96fba6SXin Li
19*1a96fba6SXin Li // request_type
20*1a96fba6SXin Li const char request_type::kOptions[] = "OPTIONS";
21*1a96fba6SXin Li const char request_type::kGet[] = "GET";
22*1a96fba6SXin Li const char request_type::kHead[] = "HEAD";
23*1a96fba6SXin Li const char request_type::kPost[] = "POST";
24*1a96fba6SXin Li const char request_type::kPut[] = "PUT";
25*1a96fba6SXin Li const char request_type::kPatch[] = "PATCH";
26*1a96fba6SXin Li const char request_type::kDelete[] = "DELETE";
27*1a96fba6SXin Li const char request_type::kTrace[] = "TRACE";
28*1a96fba6SXin Li const char request_type::kConnect[] = "CONNECT";
29*1a96fba6SXin Li const char request_type::kCopy[] = "COPY";
30*1a96fba6SXin Li const char request_type::kMove[] = "MOVE";
31*1a96fba6SXin Li
32*1a96fba6SXin Li // request_header
33*1a96fba6SXin Li const char request_header::kAccept[] = "Accept";
34*1a96fba6SXin Li const char request_header::kAcceptCharset[] = "Accept-Charset";
35*1a96fba6SXin Li const char request_header::kAcceptEncoding[] = "Accept-Encoding";
36*1a96fba6SXin Li const char request_header::kAcceptLanguage[] = "Accept-Language";
37*1a96fba6SXin Li const char request_header::kAllow[] = "Allow";
38*1a96fba6SXin Li const char request_header::kAuthorization[] = "Authorization";
39*1a96fba6SXin Li const char request_header::kCacheControl[] = "Cache-Control";
40*1a96fba6SXin Li const char request_header::kConnection[] = "Connection";
41*1a96fba6SXin Li const char request_header::kContentEncoding[] = "Content-Encoding";
42*1a96fba6SXin Li const char request_header::kContentLanguage[] = "Content-Language";
43*1a96fba6SXin Li const char request_header::kContentLength[] = "Content-Length";
44*1a96fba6SXin Li const char request_header::kContentLocation[] = "Content-Location";
45*1a96fba6SXin Li const char request_header::kContentMd5[] = "Content-MD5";
46*1a96fba6SXin Li const char request_header::kContentRange[] = "Content-Range";
47*1a96fba6SXin Li const char request_header::kContentType[] = "Content-Type";
48*1a96fba6SXin Li const char request_header::kCookie[] = "Cookie";
49*1a96fba6SXin Li const char request_header::kDate[] = "Date";
50*1a96fba6SXin Li const char request_header::kExpect[] = "Expect";
51*1a96fba6SXin Li const char request_header::kExpires[] = "Expires";
52*1a96fba6SXin Li const char request_header::kFrom[] = "From";
53*1a96fba6SXin Li const char request_header::kHost[] = "Host";
54*1a96fba6SXin Li const char request_header::kIfMatch[] = "If-Match";
55*1a96fba6SXin Li const char request_header::kIfModifiedSince[] = "If-Modified-Since";
56*1a96fba6SXin Li const char request_header::kIfNoneMatch[] = "If-None-Match";
57*1a96fba6SXin Li const char request_header::kIfRange[] = "If-Range";
58*1a96fba6SXin Li const char request_header::kIfUnmodifiedSince[] = "If-Unmodified-Since";
59*1a96fba6SXin Li const char request_header::kLastModified[] = "Last-Modified";
60*1a96fba6SXin Li const char request_header::kMaxForwards[] = "Max-Forwards";
61*1a96fba6SXin Li const char request_header::kPragma[] = "Pragma";
62*1a96fba6SXin Li const char request_header::kProxyAuthorization[] = "Proxy-Authorization";
63*1a96fba6SXin Li const char request_header::kRange[] = "Range";
64*1a96fba6SXin Li const char request_header::kReferer[] = "Referer";
65*1a96fba6SXin Li const char request_header::kTE[] = "TE";
66*1a96fba6SXin Li const char request_header::kTrailer[] = "Trailer";
67*1a96fba6SXin Li const char request_header::kTransferEncoding[] = "Transfer-Encoding";
68*1a96fba6SXin Li const char request_header::kUpgrade[] = "Upgrade";
69*1a96fba6SXin Li const char request_header::kUserAgent[] = "User-Agent";
70*1a96fba6SXin Li const char request_header::kVia[] = "Via";
71*1a96fba6SXin Li const char request_header::kWarning[] = "Warning";
72*1a96fba6SXin Li
73*1a96fba6SXin Li // response_header
74*1a96fba6SXin Li const char response_header::kAcceptRanges[] = "Accept-Ranges";
75*1a96fba6SXin Li const char response_header::kAge[] = "Age";
76*1a96fba6SXin Li const char response_header::kAllow[] = "Allow";
77*1a96fba6SXin Li const char response_header::kCacheControl[] = "Cache-Control";
78*1a96fba6SXin Li const char response_header::kConnection[] = "Connection";
79*1a96fba6SXin Li const char response_header::kContentEncoding[] = "Content-Encoding";
80*1a96fba6SXin Li const char response_header::kContentLanguage[] = "Content-Language";
81*1a96fba6SXin Li const char response_header::kContentLength[] = "Content-Length";
82*1a96fba6SXin Li const char response_header::kContentLocation[] = "Content-Location";
83*1a96fba6SXin Li const char response_header::kContentMd5[] = "Content-MD5";
84*1a96fba6SXin Li const char response_header::kContentRange[] = "Content-Range";
85*1a96fba6SXin Li const char response_header::kContentType[] = "Content-Type";
86*1a96fba6SXin Li const char response_header::kDate[] = "Date";
87*1a96fba6SXin Li const char response_header::kETag[] = "ETag";
88*1a96fba6SXin Li const char response_header::kExpires[] = "Expires";
89*1a96fba6SXin Li const char response_header::kLastModified[] = "Last-Modified";
90*1a96fba6SXin Li const char response_header::kLocation[] = "Location";
91*1a96fba6SXin Li const char response_header::kPragma[] = "Pragma";
92*1a96fba6SXin Li const char response_header::kProxyAuthenticate[] = "Proxy-Authenticate";
93*1a96fba6SXin Li const char response_header::kRetryAfter[] = "Retry-After";
94*1a96fba6SXin Li const char response_header::kServer[] = "Server";
95*1a96fba6SXin Li const char response_header::kSetCookie[] = "Set-Cookie";
96*1a96fba6SXin Li const char response_header::kTrailer[] = "Trailer";
97*1a96fba6SXin Li const char response_header::kTransferEncoding[] = "Transfer-Encoding";
98*1a96fba6SXin Li const char response_header::kUpgrade[] = "Upgrade";
99*1a96fba6SXin Li const char response_header::kVary[] = "Vary";
100*1a96fba6SXin Li const char response_header::kVia[] = "Via";
101*1a96fba6SXin Li const char response_header::kWarning[] = "Warning";
102*1a96fba6SXin Li const char response_header::kWwwAuthenticate[] = "WWW-Authenticate";
103*1a96fba6SXin Li
104*1a96fba6SXin Li // ***********************************************************
105*1a96fba6SXin Li // ********************** Request Class **********************
106*1a96fba6SXin Li // ***********************************************************
Request(const std::string & url,const std::string & method,std::shared_ptr<Transport> transport)107*1a96fba6SXin Li Request::Request(const std::string& url,
108*1a96fba6SXin Li const std::string& method,
109*1a96fba6SXin Li std::shared_ptr<Transport> transport)
110*1a96fba6SXin Li : transport_(transport), request_url_(url), method_(method) {
111*1a96fba6SXin Li VLOG(1) << "http::Request created";
112*1a96fba6SXin Li if (!transport_)
113*1a96fba6SXin Li transport_ = http::Transport::CreateDefault();
114*1a96fba6SXin Li }
115*1a96fba6SXin Li
~Request()116*1a96fba6SXin Li Request::~Request() {
117*1a96fba6SXin Li VLOG(1) << "http::Request destroyed";
118*1a96fba6SXin Li }
119*1a96fba6SXin Li
AddRange(int64_t bytes)120*1a96fba6SXin Li void Request::AddRange(int64_t bytes) {
121*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
122*1a96fba6SXin Li if (bytes < 0) {
123*1a96fba6SXin Li ranges_.emplace_back(Request::range_value_omitted, -bytes);
124*1a96fba6SXin Li } else {
125*1a96fba6SXin Li ranges_.emplace_back(bytes, Request::range_value_omitted);
126*1a96fba6SXin Li }
127*1a96fba6SXin Li }
128*1a96fba6SXin Li
AddRange(uint64_t from_byte,uint64_t to_byte)129*1a96fba6SXin Li void Request::AddRange(uint64_t from_byte, uint64_t to_byte) {
130*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
131*1a96fba6SXin Li ranges_.emplace_back(from_byte, to_byte);
132*1a96fba6SXin Li }
133*1a96fba6SXin Li
GetResponseAndBlock(brillo::ErrorPtr * error)134*1a96fba6SXin Li std::unique_ptr<Response> Request::GetResponseAndBlock(
135*1a96fba6SXin Li brillo::ErrorPtr* error) {
136*1a96fba6SXin Li if (!SendRequestIfNeeded(error) || !connection_->FinishRequest(error))
137*1a96fba6SXin Li return std::unique_ptr<Response>();
138*1a96fba6SXin Li std::unique_ptr<Response> response(new Response(connection_));
139*1a96fba6SXin Li connection_.reset();
140*1a96fba6SXin Li transport_.reset(); // Indicate that the response has been received
141*1a96fba6SXin Li return response;
142*1a96fba6SXin Li }
143*1a96fba6SXin Li
GetResponse(const SuccessCallback & success_callback,const ErrorCallback & error_callback)144*1a96fba6SXin Li RequestID Request::GetResponse(const SuccessCallback& success_callback,
145*1a96fba6SXin Li const ErrorCallback& error_callback) {
146*1a96fba6SXin Li ErrorPtr error;
147*1a96fba6SXin Li if (!SendRequestIfNeeded(&error)) {
148*1a96fba6SXin Li transport_->RunCallbackAsync(
149*1a96fba6SXin Li FROM_HERE, base::Bind(error_callback, 0, base::Owned(error.release())));
150*1a96fba6SXin Li return 0;
151*1a96fba6SXin Li }
152*1a96fba6SXin Li RequestID id =
153*1a96fba6SXin Li connection_->FinishRequestAsync(success_callback, error_callback);
154*1a96fba6SXin Li connection_.reset();
155*1a96fba6SXin Li transport_.reset(); // Indicate that the request has been dispatched.
156*1a96fba6SXin Li return id;
157*1a96fba6SXin Li }
158*1a96fba6SXin Li
SetAccept(const std::string & accept_mime_types)159*1a96fba6SXin Li void Request::SetAccept(const std::string& accept_mime_types) {
160*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
161*1a96fba6SXin Li accept_ = accept_mime_types;
162*1a96fba6SXin Li }
163*1a96fba6SXin Li
GetAccept() const164*1a96fba6SXin Li const std::string& Request::GetAccept() const {
165*1a96fba6SXin Li return accept_;
166*1a96fba6SXin Li }
167*1a96fba6SXin Li
SetContentType(const std::string & contentType)168*1a96fba6SXin Li void Request::SetContentType(const std::string& contentType) {
169*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
170*1a96fba6SXin Li content_type_ = contentType;
171*1a96fba6SXin Li }
172*1a96fba6SXin Li
GetContentType() const173*1a96fba6SXin Li const std::string& Request::GetContentType() const {
174*1a96fba6SXin Li return content_type_;
175*1a96fba6SXin Li }
176*1a96fba6SXin Li
AddHeader(const std::string & header,const std::string & value)177*1a96fba6SXin Li void Request::AddHeader(const std::string& header, const std::string& value) {
178*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
179*1a96fba6SXin Li headers_.emplace(header, value);
180*1a96fba6SXin Li }
181*1a96fba6SXin Li
AddHeaders(const HeaderList & headers)182*1a96fba6SXin Li void Request::AddHeaders(const HeaderList& headers) {
183*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
184*1a96fba6SXin Li headers_.insert(headers.begin(), headers.end());
185*1a96fba6SXin Li }
186*1a96fba6SXin Li
AddRequestBody(const void * data,size_t size,brillo::ErrorPtr * error)187*1a96fba6SXin Li bool Request::AddRequestBody(const void* data,
188*1a96fba6SXin Li size_t size,
189*1a96fba6SXin Li brillo::ErrorPtr* error) {
190*1a96fba6SXin Li if (!SendRequestIfNeeded(error))
191*1a96fba6SXin Li return false;
192*1a96fba6SXin Li StreamPtr stream = MemoryStream::OpenCopyOf(data, size, error);
193*1a96fba6SXin Li return stream && connection_->SetRequestData(std::move(stream), error);
194*1a96fba6SXin Li }
195*1a96fba6SXin Li
AddRequestBody(StreamPtr stream,brillo::ErrorPtr * error)196*1a96fba6SXin Li bool Request::AddRequestBody(StreamPtr stream, brillo::ErrorPtr* error) {
197*1a96fba6SXin Li return SendRequestIfNeeded(error) &&
198*1a96fba6SXin Li connection_->SetRequestData(std::move(stream), error);
199*1a96fba6SXin Li }
200*1a96fba6SXin Li
AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,brillo::ErrorPtr * error)201*1a96fba6SXin Li bool Request::AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,
202*1a96fba6SXin Li brillo::ErrorPtr* error) {
203*1a96fba6SXin Li AddHeader(request_header::kContentType, form_data->GetContentType());
204*1a96fba6SXin Li if (!SendRequestIfNeeded(error))
205*1a96fba6SXin Li return false;
206*1a96fba6SXin Li return connection_->SetRequestData(form_data->ExtractDataStream(), error);
207*1a96fba6SXin Li }
208*1a96fba6SXin Li
AddResponseStream(StreamPtr stream,brillo::ErrorPtr * error)209*1a96fba6SXin Li bool Request::AddResponseStream(StreamPtr stream, brillo::ErrorPtr* error) {
210*1a96fba6SXin Li if (!SendRequestIfNeeded(error))
211*1a96fba6SXin Li return false;
212*1a96fba6SXin Li connection_->SetResponseData(std::move(stream));
213*1a96fba6SXin Li return true;
214*1a96fba6SXin Li }
215*1a96fba6SXin Li
GetRequestURL() const216*1a96fba6SXin Li const std::string& Request::GetRequestURL() const {
217*1a96fba6SXin Li return request_url_;
218*1a96fba6SXin Li }
219*1a96fba6SXin Li
GetRequestMethod() const220*1a96fba6SXin Li const std::string& Request::GetRequestMethod() const {
221*1a96fba6SXin Li return method_;
222*1a96fba6SXin Li }
223*1a96fba6SXin Li
SetReferer(const std::string & referer)224*1a96fba6SXin Li void Request::SetReferer(const std::string& referer) {
225*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
226*1a96fba6SXin Li referer_ = referer;
227*1a96fba6SXin Li }
228*1a96fba6SXin Li
GetReferer() const229*1a96fba6SXin Li const std::string& Request::GetReferer() const {
230*1a96fba6SXin Li return referer_;
231*1a96fba6SXin Li }
232*1a96fba6SXin Li
SetUserAgent(const std::string & user_agent)233*1a96fba6SXin Li void Request::SetUserAgent(const std::string& user_agent) {
234*1a96fba6SXin Li DCHECK(transport_) << "Request already sent";
235*1a96fba6SXin Li user_agent_ = user_agent;
236*1a96fba6SXin Li }
237*1a96fba6SXin Li
GetUserAgent() const238*1a96fba6SXin Li const std::string& Request::GetUserAgent() const {
239*1a96fba6SXin Li return user_agent_;
240*1a96fba6SXin Li }
241*1a96fba6SXin Li
SendRequestIfNeeded(brillo::ErrorPtr * error)242*1a96fba6SXin Li bool Request::SendRequestIfNeeded(brillo::ErrorPtr* error) {
243*1a96fba6SXin Li if (transport_) {
244*1a96fba6SXin Li if (!connection_) {
245*1a96fba6SXin Li http::HeaderList headers = brillo::MapToVector(headers_);
246*1a96fba6SXin Li std::vector<std::string> ranges;
247*1a96fba6SXin Li if (method_ != request_type::kHead) {
248*1a96fba6SXin Li ranges.reserve(ranges_.size());
249*1a96fba6SXin Li for (auto p : ranges_) {
250*1a96fba6SXin Li if (p.first != range_value_omitted ||
251*1a96fba6SXin Li p.second != range_value_omitted) {
252*1a96fba6SXin Li std::string range;
253*1a96fba6SXin Li if (p.first != range_value_omitted) {
254*1a96fba6SXin Li range = brillo::string_utils::ToString(p.first);
255*1a96fba6SXin Li }
256*1a96fba6SXin Li range += '-';
257*1a96fba6SXin Li if (p.second != range_value_omitted) {
258*1a96fba6SXin Li range += brillo::string_utils::ToString(p.second);
259*1a96fba6SXin Li }
260*1a96fba6SXin Li ranges.push_back(range);
261*1a96fba6SXin Li }
262*1a96fba6SXin Li }
263*1a96fba6SXin Li }
264*1a96fba6SXin Li if (!ranges.empty())
265*1a96fba6SXin Li headers.emplace_back(
266*1a96fba6SXin Li request_header::kRange,
267*1a96fba6SXin Li "bytes=" + brillo::string_utils::Join(",", ranges));
268*1a96fba6SXin Li
269*1a96fba6SXin Li headers.emplace_back(request_header::kAccept, GetAccept());
270*1a96fba6SXin Li if (method_ != request_type::kGet && method_ != request_type::kHead) {
271*1a96fba6SXin Li if (!content_type_.empty())
272*1a96fba6SXin Li headers.emplace_back(request_header::kContentType, content_type_);
273*1a96fba6SXin Li }
274*1a96fba6SXin Li connection_ = transport_->CreateConnection(
275*1a96fba6SXin Li request_url_, method_, headers, user_agent_, referer_, error);
276*1a96fba6SXin Li }
277*1a96fba6SXin Li
278*1a96fba6SXin Li if (connection_)
279*1a96fba6SXin Li return true;
280*1a96fba6SXin Li } else {
281*1a96fba6SXin Li brillo::Error::AddTo(error,
282*1a96fba6SXin Li FROM_HERE,
283*1a96fba6SXin Li http::kErrorDomain,
284*1a96fba6SXin Li "response_already_received",
285*1a96fba6SXin Li "HTTP response already received");
286*1a96fba6SXin Li }
287*1a96fba6SXin Li return false;
288*1a96fba6SXin Li }
289*1a96fba6SXin Li
290*1a96fba6SXin Li // ************************************************************
291*1a96fba6SXin Li // ********************** Response Class **********************
292*1a96fba6SXin Li // ************************************************************
Response(const std::shared_ptr<Connection> & connection)293*1a96fba6SXin Li Response::Response(const std::shared_ptr<Connection>& connection)
294*1a96fba6SXin Li : connection_{connection} {
295*1a96fba6SXin Li VLOG(1) << "http::Response created";
296*1a96fba6SXin Li }
297*1a96fba6SXin Li
~Response()298*1a96fba6SXin Li Response::~Response() {
299*1a96fba6SXin Li VLOG(1) << "http::Response destroyed";
300*1a96fba6SXin Li }
301*1a96fba6SXin Li
IsSuccessful() const302*1a96fba6SXin Li bool Response::IsSuccessful() const {
303*1a96fba6SXin Li int code = GetStatusCode();
304*1a96fba6SXin Li return code >= status_code::Continue && code < status_code::BadRequest;
305*1a96fba6SXin Li }
306*1a96fba6SXin Li
GetStatusCode() const307*1a96fba6SXin Li int Response::GetStatusCode() const {
308*1a96fba6SXin Li if (!connection_)
309*1a96fba6SXin Li return -1;
310*1a96fba6SXin Li
311*1a96fba6SXin Li return connection_->GetResponseStatusCode();
312*1a96fba6SXin Li }
313*1a96fba6SXin Li
GetStatusText() const314*1a96fba6SXin Li std::string Response::GetStatusText() const {
315*1a96fba6SXin Li if (!connection_)
316*1a96fba6SXin Li return std::string();
317*1a96fba6SXin Li
318*1a96fba6SXin Li return connection_->GetResponseStatusText();
319*1a96fba6SXin Li }
320*1a96fba6SXin Li
GetContentType() const321*1a96fba6SXin Li std::string Response::GetContentType() const {
322*1a96fba6SXin Li return GetHeader(response_header::kContentType);
323*1a96fba6SXin Li }
324*1a96fba6SXin Li
ExtractDataStream(ErrorPtr * error)325*1a96fba6SXin Li StreamPtr Response::ExtractDataStream(ErrorPtr* error) {
326*1a96fba6SXin Li return connection_->ExtractDataStream(error);
327*1a96fba6SXin Li }
328*1a96fba6SXin Li
ExtractData()329*1a96fba6SXin Li std::vector<uint8_t> Response::ExtractData() {
330*1a96fba6SXin Li std::vector<uint8_t> data;
331*1a96fba6SXin Li StreamPtr src_stream = connection_->ExtractDataStream(nullptr);
332*1a96fba6SXin Li StreamPtr dest_stream = MemoryStream::CreateRef(&data, nullptr);
333*1a96fba6SXin Li if (src_stream && dest_stream) {
334*1a96fba6SXin Li char buffer[1024];
335*1a96fba6SXin Li size_t read = 0;
336*1a96fba6SXin Li while (src_stream->ReadBlocking(buffer, sizeof(buffer), &read, nullptr) &&
337*1a96fba6SXin Li read > 0) {
338*1a96fba6SXin Li CHECK(dest_stream->WriteAllBlocking(buffer, read, nullptr));
339*1a96fba6SXin Li }
340*1a96fba6SXin Li }
341*1a96fba6SXin Li return data;
342*1a96fba6SXin Li }
343*1a96fba6SXin Li
ExtractDataAsString()344*1a96fba6SXin Li std::string Response::ExtractDataAsString() {
345*1a96fba6SXin Li std::vector<uint8_t> data = ExtractData();
346*1a96fba6SXin Li return std::string{data.begin(), data.end()};
347*1a96fba6SXin Li }
348*1a96fba6SXin Li
GetHeader(const std::string & header_name) const349*1a96fba6SXin Li std::string Response::GetHeader(const std::string& header_name) const {
350*1a96fba6SXin Li if (connection_)
351*1a96fba6SXin Li return connection_->GetResponseHeader(header_name);
352*1a96fba6SXin Li
353*1a96fba6SXin Li return std::string();
354*1a96fba6SXin Li }
355*1a96fba6SXin Li
356*1a96fba6SXin Li } // namespace http
357*1a96fba6SXin Li } // namespace brillo
358