This CL merges the following changes from the Widevine repository: Avoid CdmSession reinitialization https://widevine-internal-review.googlesource.com/#/c/10530/ Fix timer-related unit tests. https://widevine-internal-review.googlesource.com/#/c/10510/ Correct return statement bug: 15590802 https://widevine-internal-review.googlesource.com/#/c/10553/ Usage reporting fixes bug/15388863 https://widevine-internal-review.googlesource.com/#/c/10460/ Make public methods virtual https://widevine-internal-review.googlesource.com/#/c/10500/ Fix the SetTimer contract in the CDM. https://widevine-internal-review.googlesource.com/#/c/10493/ Move inline CDM methods, add OVERRIDE. https://widevine-internal-review.googlesource.com/#/c/10475/ Simplify storage APIs related cleanup. https://widevine-internal-review.googlesource.com/#/c/10473/ Duration values are not correctly reported when queried b/15592374 https://widevine-internal-review.googlesource.com/#/c/10437/ Propagate IsKeyValid() through ContentDecryptionModule. https://widevine-internal-review.googlesource.com/#/c/10483/ Minor clean up in config_test_env. https://widevine-internal-review.googlesource.com/#/c/10440/ General clean up. https://widevine-internal-review.googlesource.com/#/c/10441/ Refactor HttpSocket and simplify UrlRequest interface. https://widevine-internal-review.googlesource.com/#/c/10410/ Install good keybox at end of unit tests b/15385981 https://widevine-internal-review.googlesource.com/#/c/10374/ Privacy crypto fixes b/15475012 https://widevine-internal-review.googlesource.com/#/c/10383/ Incorporate header files to resolve build issued based on customers feedback. https://widevine-internal-review.googlesource.com/#/c/10420/ Support unprovisioning b/12247651 https://widevine-internal-review.googlesource.com/#/c/10356/ Correct usage of Host::Allocate and Cdm::Decrypt. https://widevine-internal-review.googlesource.com/#/c/10378/ Fix logging bug, arguments in wrong order. https://widevine-internal-review.googlesource.com/#/c/10380/ Rename types that look like constants. https://widevine-internal-review.googlesource.com/#/c/10379/ Fix offline test failures b/13909635 https://widevine-internal-review.googlesource.com/#/c/10348/ Add -DUNIT_TEST to the unit test makefile for Android https://widevine-internal-review.googlesource.com/#/c/10375/ Refactor privacy-crypto and add dummy version. https://widevine-internal-review.googlesource.com/#/c/10353/ Remove References to Apiary https://widevine-internal-review.googlesource.com/#/c/9924/ Delete oldest entry in usage table when full bug: 15184824 https://widevine-internal-review.googlesource.com/#/c/10295/ Port DeviceFiles to iOS. https://widevine-internal-review.googlesource.com/#/c/10355/ Make testing functions in DeviceFiles private. https://widevine-internal-review.googlesource.com/#/c/10354/ Add RSA encryption to haystack https://widevine-internal-review.googlesource.com/#/c/10280/ Add string and vector includes to CDM header. https://widevine-internal-review.googlesource.com/#/c/10352/ First version of oemcrypto logging https://widevine-internal-review.googlesource.com/#/c/10252/ Update Names of Secure Stop Methods bug: 11987015 https://widevine-internal-review.googlesource.com/#/c/10152/ Adjust timing on the Usage Table unit test https://widevine-internal-review.googlesource.com/#/c/10307/ Fix all compiler warnings in CDM source release. https://widevine-internal-review.googlesource.com/#/c/10293/ Fix memset bug: args in wrong order https://widevine-internal-review.googlesource.com/#/c/10292/ Partial revert of 'Remove refs to test prov server, Level3 support...' https://widevine-internal-review.googlesource.com/#/c/10281/ Pack structure OEMCrypto_PST_Report https://widevine-internal-review.googlesource.com/#/c/10243/ Remove refs to test prov server, Level3 support; remove dead code https://widevine-internal-review.googlesource.com/#/c/10220/ Partial revert of 'Document data strings; clean up license server parameters.' https://widevine-internal-review.googlesource.com/#/c/10188/ Document data strings; clean up license server parameters. https://widevine-internal-review.googlesource.com/#/c/10120/ Fix broken build after partner branch merge. https://widevine-internal-review.googlesource.com/#/c/10181/ TODO Cleanup - core/src, core/include https://widevine-internal-review.googlesource.com/#/c/9965/ TODO Cleanup - cdm, chromium, core/test. https://widevine-internal-review.googlesource.com/#/c/9419/ Remove unneeded properties. https://widevine-internal-review.googlesource.com/#/c/10162/ Change-Id: If2bb9d743a562a3875bebb91933c0aaadea286b2
171 lines
4.9 KiB
C++
171 lines
4.9 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#include "url_request.h"
|
|
|
|
#include <errno.h>
|
|
#include <sstream>
|
|
|
|
#include "http_socket.h"
|
|
#include "log.h"
|
|
#include "string_conversions.h"
|
|
|
|
namespace {
|
|
|
|
const int kReadBufferSize = 1024;
|
|
const int kConnectTimeoutMs = 5000;
|
|
const int kWriteTimeoutMs = 3000;
|
|
const int kReadTimeoutMs = 3000;
|
|
|
|
// Concatenate all chunks into one blob and returns the response with
|
|
// header information.
|
|
void ConcatenateChunkedResponse(const std::string http_response,
|
|
std::string* modified_response) {
|
|
if (http_response.empty()) return;
|
|
|
|
modified_response->clear();
|
|
const std::string kChunkedTag = "Transfer-Encoding: chunked\r\n\r\n";
|
|
size_t chunked_tag_pos = http_response.find(kChunkedTag);
|
|
if (std::string::npos != chunked_tag_pos) {
|
|
// processes chunked encoding
|
|
size_t chunk_size = 0;
|
|
size_t chunk_size_pos = chunked_tag_pos + kChunkedTag.size();
|
|
sscanf(&http_response[chunk_size_pos], "%zx", &chunk_size);
|
|
if (chunk_size > http_response.size()) {
|
|
// precaution, in case we misread chunk size
|
|
LOGE("invalid chunk size %u", chunk_size);
|
|
return;
|
|
}
|
|
|
|
// Search for chunks in the following format:
|
|
// header
|
|
// chunk size\r\n <-- chunk_size_pos @ beginning of chunk size
|
|
// chunk data\r\n <-- chunk_pos @ beginning of chunk data
|
|
// chunk size\r\n
|
|
// chunk data\r\n
|
|
// 0\r\n
|
|
const std::string kCrLf = "\r\n";
|
|
size_t chunk_pos = http_response.find(kCrLf, chunk_size_pos);
|
|
modified_response->assign(http_response, 0, chunk_size_pos);
|
|
|
|
while ((chunk_size > 0) && (std::string::npos != chunk_pos)) {
|
|
chunk_pos += kCrLf.size();
|
|
modified_response->append(http_response, chunk_pos, chunk_size);
|
|
|
|
// Search for next chunk
|
|
chunk_size_pos = chunk_pos + chunk_size + kCrLf.size();
|
|
sscanf(&http_response[chunk_size_pos], "%zx", &chunk_size);
|
|
if (chunk_size > http_response.size()) {
|
|
// precaution, in case we misread chunk size
|
|
LOGE("invalid chunk size %u", chunk_size);
|
|
break;
|
|
}
|
|
chunk_pos = http_response.find(kCrLf, chunk_size_pos);
|
|
}
|
|
} else {
|
|
// Response is not chunked encoded
|
|
modified_response->assign(http_response);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
namespace wvcdm {
|
|
|
|
UrlRequest::UrlRequest(const std::string& url)
|
|
: is_connected_(false),
|
|
socket_(url) {
|
|
if (socket_.Connect(kConnectTimeoutMs)) {
|
|
is_connected_ = true;
|
|
} else {
|
|
LOGE("failed to connect to %s, port=%d", socket_.domain_name().c_str(),
|
|
socket_.port());
|
|
}
|
|
}
|
|
|
|
UrlRequest::~UrlRequest() {}
|
|
|
|
bool UrlRequest::GetResponse(std::string* message) {
|
|
std::string response;
|
|
|
|
// Keep reading until end of stream (0 bytes read) or timeout. Partial
|
|
// buffers worth of data can and do happen, especially with OpenSSL in
|
|
// non-blocking mode.
|
|
while (true) {
|
|
char read_buffer[kReadBufferSize];
|
|
int bytes = socket_.Read(read_buffer, sizeof(read_buffer), kReadTimeoutMs);
|
|
if (bytes > 0) {
|
|
response.append(read_buffer, bytes);
|
|
} else if (bytes < 0) {
|
|
LOGE("read error, errno = %d", errno);
|
|
return false;
|
|
} else {
|
|
// end of stream.
|
|
break;
|
|
}
|
|
}
|
|
|
|
ConcatenateChunkedResponse(response, message);
|
|
LOGD("HTTP response: (%d): %s", message->size(), b2a_hex(*message).c_str());
|
|
return true;
|
|
}
|
|
|
|
// static
|
|
int UrlRequest::GetStatusCode(const std::string& response) {
|
|
const std::string kHttpVersion("HTTP/1.1 ");
|
|
|
|
int status_code = -1;
|
|
size_t pos = response.find(kHttpVersion);
|
|
if (pos != std::string::npos) {
|
|
pos += kHttpVersion.size();
|
|
sscanf(response.substr(pos).c_str(), "%d", &status_code);
|
|
}
|
|
return status_code;
|
|
}
|
|
|
|
bool UrlRequest::PostRequestWithPath(const std::string& path,
|
|
const std::string& data) {
|
|
std::string request;
|
|
|
|
request.append("POST ");
|
|
request.append(path);
|
|
request.append(" HTTP/1.1\r\n");
|
|
|
|
request.append("Host: ");
|
|
request.append(socket_.domain_name());
|
|
request.append("\r\n");
|
|
|
|
request.append("Connection: close\r\n");
|
|
request.append("User-Agent: Widevine CDM v1.0\r\n");
|
|
|
|
// buffer to store length of data as a string
|
|
char data_size_buffer[32] = {0};
|
|
snprintf(data_size_buffer, sizeof(data_size_buffer), "%zd", data.size());
|
|
|
|
request.append("Content-Length: ");
|
|
request.append(data_size_buffer); // appends size of data
|
|
request.append("\r\n");
|
|
|
|
request.append("\r\n"); // empty line to terminate headers
|
|
|
|
request.append(data);
|
|
|
|
int ret = socket_.Write(request.c_str(), request.size(), kWriteTimeoutMs);
|
|
LOGD("HTTP request: (%d): %s", request.size(), b2a_hex(request).c_str());
|
|
return ret != -1;
|
|
}
|
|
|
|
bool UrlRequest::PostRequest(const std::string& data) {
|
|
return PostRequestWithPath(socket_.resource_path(), data);
|
|
}
|
|
|
|
bool UrlRequest::PostCertRequestInQueryString(const std::string& data) {
|
|
std::string path = socket_.resource_path();
|
|
path.append("&signedRequest=");
|
|
path.append(data);
|
|
|
|
return PostRequestWithPath(path, "");
|
|
}
|
|
|
|
} // namespace wvcdm
|