Squashed commit of 3 CLs related to provisioning retries

Bug: 8770327

    1. Allow provisioning retries

    Allow multiple provisioning request messages to be generated without
    requiring an equal number of HandleProvisioningResponse's. This is to
    allow for lost messages.

    2. Properly deletes cdm and crypto sessions created for cert provisioning.

    The CleanupProvisioningSession() has not been deleting the cdm and crypto sessions
    created for certificate provisioning properly. The lives of these sessions are
    short and therefore, not added to the CdmSessionMap. We need to explicitly delete
    these objects when error occurs or when we are done with provisioning.

    3. Fixes provisioning responses that contain multiple chunks.

    When we make multiple provisioning requests during testing, Apiary
    sends response that contains more than one chunk. The test app.
    needs to parse the response and concatenates the chunk data.
    Otherwise, the size for each chunk is treated as base64 encoded data,
    which will generate error when we try to deserialize the response
    message.

Merge of https://widevine-internal-review.googlesource.com/#/c/5451/
from the Widevine CDM repository

Change-Id: I5b0ed982849c12628a3949f8d51515fcf6ce5a5f
This commit is contained in:
Jeff Tinker
2013-05-06 23:04:34 -07:00
parent d0f1784615
commit 7aa99d4a36
3 changed files with 150 additions and 36 deletions

View File

@@ -77,6 +77,81 @@ class WvCdmRequestLicenseTest : public testing::Test {
EXPECT_NE(0, static_cast<int>(server_url.size()));
}
void DumpResponse(const std::string& description,
const std::string& response) {
if (description.empty())
return;
LOGD("%s (%d bytes):", description.c_str(), response.size());
size_t remaining = response.size();
size_t portion = 0;
size_t start = 0;
while (remaining > 0) {
// LOGX may not get to empty its buffer if it is too large,
// pick an arbitrary small size to be safe
portion = (remaining < 512) ? remaining : 512;
LOGD("%s", response.substr(start, portion).c_str());
start += portion;
remaining -= portion;
}
LOGD("total bytes dumped(%d)", start);
}
// concatinates all chunks into one blob
// TODO (edwinwong) move this function to url_request class as GetMessageBody
void ConcatenateChunkedResponse(const std::string http_response,
std::string* message_body) {
if (http_response.empty())
return;
message_body->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], "%x", &chunk_size);
if (chunk_size > http_response.size()) {
// precaution, in case we misread chunk size
LOGE("invalid chunk size %u", chunk_size);
return;
}
/*
* searches for chunks
*
* 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) +
kCrLf.size();
message_body->assign(&http_response[0], chunk_size_pos);
while ((chunk_size > 0) && (std::string::npos != chunk_pos)) {
message_body->append(&http_response[chunk_pos], chunk_size);
// searches for next chunk
chunk_size_pos = chunk_pos + chunk_size + kCrLf.size();
sscanf(&http_response[chunk_size_pos], "%x", &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) + kCrLf.size();
}
} else {
// response is not chunked encoded
message_body->assign(http_response);
}
}
// posts a request and extracts the drm message from the response
std::string GetKeyRequestResponse(const std::string& server_url,
const std::string& client_auth,
@@ -88,14 +163,17 @@ class WvCdmRequestLicenseTest : public testing::Test {
}
url_request.PostRequest(key_msg_);
std::string response;
int resp_bytes = url_request.GetResponse(response);
LOGD("response:\r\n%s", response.c_str());
std::string http_response;
std::string message_body;
int resp_bytes = url_request.GetResponse(http_response);
if (resp_bytes) {
ConcatenateChunkedResponse(http_response, &message_body);
}
LOGD("end %d bytes response dump", resp_bytes);
// Youtube server returns 400 for invalid message while play server returns
// 500, so just test inequity here for invalid message
int status_code = url_request.GetStatusCode(response);
int status_code = url_request.GetStatusCode(message_body);
if (expected_response == 200) {
EXPECT_EQ(200, status_code);
} else {
@@ -105,7 +183,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
std::string drm_msg;
if (200 == status_code) {
LicenseRequest lic_request;
lic_request.GetDrmMessage(response, drm_msg);
lic_request.GetDrmMessage(message_body, drm_msg);
LOGV("drm msg: %u bytes\r\n%s", drm_msg.size(),
HexEncode(reinterpret_cast<const uint8_t*>(drm_msg.data()),
drm_msg.size()).c_str());
@@ -123,24 +201,23 @@ class WvCdmRequestLicenseTest : public testing::Test {
}
url_request.PostCertRequestInQueryString(key_msg_);
std::string response;
int resp_bytes = url_request.GetResponse(response);
std::string http_response;
std::string message_body;
int resp_bytes = url_request.GetResponse(http_response);
if (resp_bytes) {
LOGD("size=%u, response start:\t\rn%s", response.size(),
response.substr(0, 1024).c_str());
LOGD("end:\r\n%s", response.substr(response.size() - 256).c_str());
ConcatenateChunkedResponse(http_response, &message_body);
}
LOGD("end %d bytes response dump", resp_bytes);
// Youtube server returns 400 for invalid message while play server returns
// 500, so just test inequity here for invalid message
int status_code = url_request.GetStatusCode(response);
int status_code = url_request.GetStatusCode(message_body);
if (expected_response == 200) {
EXPECT_EQ(200, status_code);
} else {
EXPECT_NE(200, status_code);
}
return response;
return message_body;
}
void VerifyKeyRequestResponse(const std::string& server_url,
@@ -170,12 +247,28 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
decryptor_.OpenSession(g_key_system, &session_id_);
std::string provisioning_server_url = "";
decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url);
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url));
EXPECT_STREQ(provisioning_server_url.data(), kDefaultProvisioningServerUrl.data());
std::string response = GetCertRequestResponse(kDefaultProvisioningServerUrl, 200);
if (!response.empty())
decryptor_.HandleProvisioningResponse(response);
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
decryptor_.CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, ProvisioningRetryTest) {
decryptor_.OpenSession(g_key_system, &session_id_);
std::string provisioning_server_url = "";
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url));
EXPECT_STREQ(provisioning_server_url.data(), kDefaultProvisioningServerUrl.data());
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url));
EXPECT_STREQ(provisioning_server_url.data(), kDefaultProvisioningServerUrl.data());
std::string response = GetCertRequestResponse(kDefaultProvisioningServerUrl, 200);
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
decryptor_.CloseSession(session_id_);
}