DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
http_key_fetcher.cc
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/base/http_key_fetcher.h"
8 
9 #include <curl/curl.h>
10 
11 #include "packager/base/logging.h"
12 #include "packager/base/strings/stringprintf.h"
13 #include "packager/base/synchronization/lock.h"
14 
15 namespace edash_packager {
16 
17 namespace {
18 const char kUserAgentString[] = "edash-packager-http_fetcher/1.0";
19 
20 // Scoped CURL implementation which cleans up itself when goes out of scope.
21 class ScopedCurl {
22  public:
23  ScopedCurl() { ptr_ = curl_easy_init(); }
24  ~ScopedCurl() {
25  if (ptr_)
26  curl_easy_cleanup(ptr_);
27  }
28 
29  CURL* get() { return ptr_; }
30 
31  private:
32  CURL* ptr_;
33  DISALLOW_COPY_AND_ASSIGN(ScopedCurl);
34 };
35 
36 size_t AppendToString(char* ptr, size_t size, size_t nmemb, std::string* response) {
37  DCHECK(ptr);
38  DCHECK(response);
39  const size_t total_size = size * nmemb;
40  response->append(ptr, total_size);
41  return total_size;
42 }
43 
44 class LibCurlInitializer {
45  public:
46  LibCurlInitializer() : initialized_(false) {
47  base::AutoLock lock(lock_);
48  if (!initialized_) {
49  curl_global_init(CURL_GLOBAL_DEFAULT);
50  initialized_ = true;
51  }
52  }
53 
54  ~LibCurlInitializer() {
55  base::AutoLock lock(lock_);
56  if (initialized_) {
57  curl_global_cleanup();
58  initialized_ = false;
59  }
60  }
61 
62  private:
63  base::Lock lock_;
64  bool initialized_;
65 
66  DISALLOW_COPY_AND_ASSIGN(LibCurlInitializer);
67 };
68 
69 } // namespace
70 
71 namespace media {
72 
73 HttpKeyFetcher::HttpKeyFetcher() : timeout_in_seconds_(0) {}
74 
75 HttpKeyFetcher::HttpKeyFetcher(uint32_t timeout_in_seconds)
76  : timeout_in_seconds_(timeout_in_seconds) {}
77 
78 HttpKeyFetcher::~HttpKeyFetcher() {}
79 
80 Status HttpKeyFetcher::FetchKeys(const std::string& url,
81  const std::string& request,
82  std::string* response) {
83  return Post(url, request, response);
84 }
85 
86 Status HttpKeyFetcher::Get(const std::string& path, std::string* response) {
87  return FetchInternal(GET, path, "", response);
88 }
89 
90 Status HttpKeyFetcher::Post(const std::string& path,
91  const std::string& data,
92  std::string* response) {
93  return FetchInternal(POST, path, data, response);
94 }
95 
96 Status HttpKeyFetcher::FetchInternal(HttpMethod method,
97  const std::string& path,
98  const std::string& data,
99  std::string* response) {
100  DCHECK(method == GET || method == POST);
101 
102  static LibCurlInitializer lib_curl_initializer;
103 
104  ScopedCurl scoped_curl;
105  CURL* curl = scoped_curl.get();
106  if (!curl) {
107  LOG(ERROR) << "curl_easy_init() failed.";
108  return Status(error::HTTP_FAILURE, "curl_easy_init() failed.");
109  }
110  response->clear();
111 
112  curl_easy_setopt(curl, CURLOPT_URL, path.c_str());
113  curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgentString);
114  curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_in_seconds_);
115  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
116  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
117  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToString);
118  curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
119  if (method == POST) {
120  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
121  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
122  }
123 
124  CURLcode res = curl_easy_perform(curl);
125  if (res != CURLE_OK) {
126  std::string error_message = base::StringPrintf(
127  "curl_easy_perform() failed: %s.", curl_easy_strerror(res));
128  if (res == CURLE_HTTP_RETURNED_ERROR) {
129  long response_code = 0;
130  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
131  error_message += base::StringPrintf(" Response code: %ld.", response_code);
132  }
133 
134  LOG(ERROR) << error_message;
135  return Status(
136  res == CURLE_OPERATION_TIMEDOUT ? error::TIME_OUT : error::HTTP_FAILURE,
137  error_message);
138  }
139  return Status::OK;
140 }
141 
142 } // namespace media
143 } // namespace edash_packager
HttpKeyFetcher()
Creates a fetcher with no timeout.
virtual Status Get(const std::string &url, std::string *response)
virtual Status Post(const std::string &url, const std::string &data, std::string *response)
Status FetchKeys(const std::string &url, const std::string &request, std::string *response) override