7 #include "packager/media/base/http_key_fetcher.h" 11 #include "packager/base/logging.h" 12 #include "packager/base/strings/string_number_conversions.h" 13 #include "packager/base/strings/stringprintf.h" 14 #include "packager/base/synchronization/lock.h" 19 const char kUserAgentString[] =
"shaka-packager-http_fetcher/1.0";
20 const char kSoapActionHeader[] =
21 "SOAPAction: \"http://schemas.microsoft.com/DRM/2007/03/protocols/" 22 "AcquirePackagingData\"";
23 const char kXmlContentTypeHeader[] =
"Content-Type: text/xml; charset=UTF-8";
24 const char kJsonContentTypeHeader[] =
"Content-Type: application/json";
26 const int kMinLogLevelForCurlDebugFunction = 2;
28 int CurlDebugFunction(CURL* ,
33 const char* type_text;
34 int log_level = kMinLogLevelForCurlDebugFunction;
37 type_text =
"== Info";
38 log_level = kMinLogLevelForCurlDebugFunction + 1;
40 case CURLINFO_HEADER_IN:
41 type_text =
"<= Recv header";
42 log_level = kMinLogLevelForCurlDebugFunction;
44 case CURLINFO_HEADER_OUT:
45 type_text =
"=> Send header";
46 log_level = kMinLogLevelForCurlDebugFunction;
48 case CURLINFO_DATA_IN:
49 type_text =
"<= Recv data";
50 log_level = kMinLogLevelForCurlDebugFunction + 1;
52 case CURLINFO_DATA_OUT:
53 type_text =
"=> Send data";
54 log_level = kMinLogLevelForCurlDebugFunction + 1;
56 case CURLINFO_SSL_DATA_IN:
57 type_text =
"<= Recv SSL data";
58 log_level = kMinLogLevelForCurlDebugFunction + 2;
60 case CURLINFO_SSL_DATA_OUT:
61 type_text =
"=> Send SSL data";
62 log_level = kMinLogLevelForCurlDebugFunction + 2;
69 VLOG(log_level) <<
"\n\n" 70 << type_text <<
" (0x" << std::hex << size << std::dec
73 << std::string(data, size) <<
"\nHex Format: \n" 74 << base::HexEncode(data, size);
81 ScopedCurl() { ptr_ = curl_easy_init(); }
84 curl_easy_cleanup(ptr_);
87 CURL*
get() {
return ptr_; }
91 DISALLOW_COPY_AND_ASSIGN(ScopedCurl);
94 size_t AppendToString(
char* ptr,
size_t size,
size_t nmemb, std::string* response) {
97 const size_t total_size = size * nmemb;
98 response->append(ptr, total_size);
102 class LibCurlInitializer {
104 LibCurlInitializer() : initialized_(false) {
105 base::AutoLock lock(lock_);
107 curl_global_init(CURL_GLOBAL_DEFAULT);
112 ~LibCurlInitializer() {
113 base::AutoLock lock(lock_);
115 curl_global_cleanup();
116 initialized_ =
false;
124 DISALLOW_COPY_AND_ASSIGN(LibCurlInitializer);
131 HttpKeyFetcher::HttpKeyFetcher() : timeout_in_seconds_(0) {}
134 : timeout_in_seconds_(timeout_in_seconds) {}
136 HttpKeyFetcher::~HttpKeyFetcher() {}
139 const std::string& request,
140 std::string* response) {
141 return Post(url, request, response);
145 return FetchInternal(GET, path,
"", response);
149 const std::string& data,
150 std::string* response) {
151 return FetchInternal(POST, path, data, response);
154 Status HttpKeyFetcher::FetchInternal(HttpMethod method,
155 const std::string& path,
156 const std::string& data,
157 std::string* response) {
158 DCHECK(method == GET || method == POST);
159 static LibCurlInitializer lib_curl_initializer;
161 ScopedCurl scoped_curl;
162 CURL* curl = scoped_curl.get();
164 LOG(ERROR) <<
"curl_easy_init() failed.";
165 return Status(error::HTTP_FAILURE,
"curl_easy_init() failed.");
169 curl_easy_setopt(curl, CURLOPT_URL, path.c_str());
170 curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgentString);
171 curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_in_seconds_);
172 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
173 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
174 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToString);
175 curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
177 if (!client_cert_private_key_file_.empty() && !client_cert_file_.empty()) {
180 curl_easy_setopt(curl, CURLOPT_SSLKEY,
181 client_cert_private_key_file_.data());
182 if (!client_cert_private_key_password_.empty()) {
183 curl_easy_setopt(curl, CURLOPT_KEYPASSWD,
184 client_cert_private_key_password_.data());
186 curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE,
"PEM");
187 curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE,
"PEM");
188 curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_file_.data());
190 if (!ca_file_.empty()) {
192 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
193 curl_easy_setopt(curl, CURLOPT_CAINFO, ca_file_.data());
195 if (method == POST) {
196 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
197 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
199 curl_slist* chunk =
nullptr;
200 if (data.find(
"soap:Envelope") != std::string::npos) {
202 chunk = curl_slist_append(chunk, kXmlContentTypeHeader);
203 chunk = curl_slist_append(chunk, kSoapActionHeader);
205 chunk = curl_slist_append(chunk, kJsonContentTypeHeader);
207 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
210 if (VLOG_IS_ON(kMinLogLevelForCurlDebugFunction)) {
211 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, CurlDebugFunction);
212 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
215 CURLcode res = curl_easy_perform(curl);
216 if (res != CURLE_OK) {
217 std::string error_message = base::StringPrintf(
218 "curl_easy_perform() failed: %s.", curl_easy_strerror(res));
219 if (res == CURLE_HTTP_RETURNED_ERROR) {
220 long response_code = 0;
221 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
222 error_message += base::StringPrintf(
" Response code: %ld.", response_code);
225 LOG(ERROR) << error_message;
227 res == CURLE_OPERATION_TIMEDOUT ? error::TIME_OUT : error::HTTP_FAILURE,
All the methods that are virtual are virtual for mocking.