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