194b5036ee6ba866e1702848855b6d687d1e70afaAlexey Samsonov// Copyright 2014 The Chromium Authors. All rights reserved.
29aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany// Use of this source code is governed by a BSD-style license that can be
39aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany// found in the LICENSE file.
49aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany
59aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "components/copresence/rpc/http_post.h"
69aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany
79aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany// TODO(ckehoe): Support third-party protobufs too.
89aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include <google/protobuf/message_lite.h>
99aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany
109aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "base/bind.h"
110a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov#include "google_apis/google_api_keys.h"
129aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "net/base/load_flags.h"
139aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "net/base/net_errors.h"
149aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "net/base/url_util.h"
159aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "net/http/http_status_code.h"
16d865fecddccebf898ceed24d096fc58fb29a6e57Chandler Carruth#include "net/url_request/url_fetcher.h"
170a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov#include "net/url_request/url_request_context_getter.h"
189aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany#include "url/gurl.h"
199aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany
209aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryanynamespace copresence {
210a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
220a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonovconst char HttpPost::kApiKeyField[] = "key";
230a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonovconst char HttpPost::kTracingField[] = "trace";
240a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
250a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey SamsonovHttpPost::HttpPost(net::URLRequestContextGetter* url_context_getter,
260a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov                   const std::string& server_host,
27bfa45e11e52081c55294355f36fa547f163dcc67Dmitry Vyukov                   const std::string& rpc_name,
280a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov                   const std::string& tracing_token,
29d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov                   std::string api_key,
300a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov                   const google::protobuf::MessageLite& request_proto) {
310a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  // Create the base URL to call.
320a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  GURL url(server_host + "/" + rpc_name);
3315503b0a4331c7f27f9cebc25e25c2e494f61cb9Alexey Samsonov
340a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  // Add the tracing token, if specified.
350a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  if (!tracing_token.empty()) {
360a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov    url = net::AppendQueryParameter(
37d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov        url, kTracingField, "token:" + tracing_token);
38bfa45e11e52081c55294355f36fa547f163dcc67Dmitry Vyukov  }
39d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov
400a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  // If no API key is specified, use the Chrome API key.
410a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  if (api_key.empty()) {
4215503b0a4331c7f27f9cebc25e25c2e494f61cb9Alexey Samsonov#ifdef GOOGLE_CHROME_BUILD
430a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov    DCHECK(google_apis::HasKeysConfigured());
440a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov    api_key = google_apis::GetAPIKey();
450a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov#else
4697daee89b35f6141db09aee612f0f377f754092fDmitry Vyukov    LOG(ERROR) << "No Copresence API key provided";
47d51a1a10cba87be50e9ada9fa21337c387edb237Dmitry Vyukov#endif
48bfa45e11e52081c55294355f36fa547f163dcc67Dmitry Vyukov  }
490a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  url = net::AppendQueryParameter(url, kApiKeyField, api_key);
500a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
510a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  // Serialize the proto for transmission.
520a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  std::string request_data;
530a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  bool serialize_success = request_proto.SerializeToString(&request_data);
542ea978704a794e536d2801affcc7f301092d75daAlexey Samsonov  DCHECK(serialize_success);
550a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
569aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany  // Configure and send the request.
579aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany  url_fetcher_.reset(net::URLFetcher::Create(
58dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov      kUrlFetcherId, url, net::URLFetcher::POST, this));
59dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  url_fetcher_->SetRequestContext(url_context_getter);
60dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  url_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE |
61dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                             net::LOAD_DISABLE_CACHE |
62dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                             net::LOAD_DO_NOT_SAVE_COOKIES |
63dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                             net::LOAD_DO_NOT_SEND_COOKIES |
64dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                             net::LOAD_DO_NOT_SEND_AUTH_DATA);
65dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  url_fetcher_->SetUploadData("application/x-protobuf", request_data);
66dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov}
670a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
680a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey SamsonovHttpPost::~HttpPost() {}
690a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov
700a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonovvoid HttpPost::Start(const ResponseCallback& response_callback) {
710a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  response_callback_ = response_callback;
720a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  DVLOG(3) << "Sending Copresence request to "
730a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov           << url_fetcher_->GetOriginalURL().spec();
740a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov  url_fetcher_->Start();
750a4c906dbc8f150657ddd4f19a7192b779f1d605Alexey Samsonov}
769aead37421a6e4bf43265e5195c6ac31fc519982Kostya Serebryany
7715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonovvoid HttpPost::OnURLFetchComplete(const net::URLFetcher* source) {
7815a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  DCHECK_EQ(url_fetcher_.get(), source);
7915a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
8015a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  // Gather response info.
8115a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  std::string response;
8215a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  source->GetResponseAsString(&response);
8315a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  int response_code = source->GetResponseCode();
8415a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
85230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  // Log any errors.
86230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  if (response_code < 0) {
87230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov    net::URLRequestStatus status = source->GetStatus();
88230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov    LOG(WARNING) << "Couldn't contact the Copresence server at "
89230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov                 << source->GetURL() << ". Status code " << status.status();
90230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov    LOG_IF(WARNING, status.error())
91230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov        << "Network error: " << net::ErrorToString(status.error());
92230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov    LOG_IF(WARNING, !response.empty()) << "HTTP response: " << response;
93230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  } else if (response_code != net::HTTP_OK) {
9415a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov    LOG(WARNING) << "Copresence request got HTTP response code "
9515a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov                 << response_code << ". Response:\n" << response;
9615a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  }
9715a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
9815a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  // Return the response.
9915a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov  response_callback_.Run(response_code, response);
10015a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov}
10115a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov
10215a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov}  // namespace copresence
10315a77612e0a89c1df444a2034e531c8968d0cedfAlexey Samsonov