Merge "Log X-Google fields on failed HTTP requests."
This commit is contained in:
@@ -21,6 +21,10 @@ const int kConnectTimeoutMs = 15000;
|
||||
const int kWriteTimeoutMs = 12000;
|
||||
const int kReadTimeoutMs = 12000;
|
||||
|
||||
const std::string kGoogleHeaderUpper("X-Google");
|
||||
const std::string kGoogleHeaderLower("x-google");
|
||||
const std::string kCrLf("\r\n");
|
||||
|
||||
// Concatenate all chunks into one blob and returns the response with
|
||||
// header information.
|
||||
void ConcatenateChunkedResponse(const std::string http_response,
|
||||
@@ -48,7 +52,6 @@ void ConcatenateChunkedResponse(const std::string http_response,
|
||||
// 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);
|
||||
|
||||
@@ -131,6 +134,45 @@ int UrlRequest::GetStatusCode(const std::string& response) {
|
||||
return status_code;
|
||||
}
|
||||
|
||||
// static
|
||||
bool UrlRequest::GetDebugHeaderFields(
|
||||
const std::string& response, std::map<std::string, std::string>* fields) {
|
||||
if (fields == nullptr) return false;
|
||||
fields->clear();
|
||||
|
||||
const auto find_next = [&](size_t pos) -> size_t {
|
||||
// Some of Google's HTTPS return header fields in lower case,
|
||||
// this lambda will check for both and return the position that
|
||||
// that is next or npos if none are found.
|
||||
const size_t lower_pos = response.find(kGoogleHeaderLower, pos + 1);
|
||||
const size_t upper_pos = response.find(kGoogleHeaderUpper, pos + 1);
|
||||
if (lower_pos == std::string::npos) return upper_pos;
|
||||
if (upper_pos == std::string::npos || lower_pos < upper_pos)
|
||||
return lower_pos;
|
||||
return upper_pos;
|
||||
};
|
||||
|
||||
// Search is relatively simple, and may pick up additional matches within
|
||||
// the body of the request. This is not anticiapted for the limited use
|
||||
// cases of parsing provisioning/license/renewal responses.
|
||||
for (size_t key_pos = find_next(0); key_pos != std::string::npos;
|
||||
key_pos = find_next(key_pos)) {
|
||||
const size_t end_key_pos = response.find(":", key_pos);
|
||||
const size_t end_value_pos = response.find(kCrLf, key_pos);
|
||||
// Skip if the colon cannot be found. Technically possible to find
|
||||
// "X-Google" inside the value of a nother header field.
|
||||
if (end_key_pos == std::string::npos || end_value_pos == std::string::npos)
|
||||
continue;
|
||||
const size_t value_pos = end_key_pos + 2;
|
||||
if (end_value_pos < value_pos) continue;
|
||||
const std::string key = response.substr(key_pos, end_key_pos - key_pos);
|
||||
const std::string value =
|
||||
response.substr(value_pos, end_value_pos - value_pos);
|
||||
fields->insert({key, value});
|
||||
}
|
||||
return !fields->empty();
|
||||
}
|
||||
|
||||
bool UrlRequest::PostRequestWithPath(const std::string& path,
|
||||
const std::string& data) {
|
||||
std::string request;
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#ifndef CDM_TEST_URL_REQUEST_H_
|
||||
#define CDM_TEST_URL_REQUEST_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "http_socket.h"
|
||||
|
||||
@@ -27,6 +29,10 @@ class UrlRequest {
|
||||
bool GetResponse(std::string* message);
|
||||
static int GetStatusCode(const std::string& response);
|
||||
|
||||
static bool GetDebugHeaderFields(
|
||||
const std::string& response,
|
||||
std::map<std::string, std::string>* header_fields);
|
||||
|
||||
private:
|
||||
bool PostRequestWithPath(const std::string& path, const std::string& data);
|
||||
|
||||
|
||||
104
libwvdrmengine/cdm/core/test/url_request_unittest.cpp
Normal file
104
libwvdrmengine/cdm/core/test/url_request_unittest.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "url_request.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "test_base.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
|
||||
// A sample HTTP response which contains an HTTP header with several
|
||||
// standard and non-standard header fields. The fields of interests
|
||||
// those beginning with "X-Google-" or "x-google-".
|
||||
const std::string kSampleResponse =
|
||||
"HTTP/2 301\r\n"
|
||||
"Location: https://www.google.com/\r\b"
|
||||
"Content-Type: text/html; charset=UTF-8\r\n"
|
||||
"X-Google-GFE-Backend-Request-Info: eid=7js14zjC48OpziR0VCF02a0\r\n"
|
||||
"x-google-signals: FRAMEWORK=TEST\r\n"
|
||||
"X-Google-Binary-Version: 322287520\r\n"
|
||||
"X-Google-Request-Cost: 2.50\r\n"
|
||||
"Date: Thu, 23 Jul 2020 22:52:55 GMT\r\n"
|
||||
"Expires: Sat, 22 Aug 2020 22:52:55 GMT\r\n"
|
||||
"Cache-Control: public, max-age=2592000\r\n"
|
||||
"x-google-data-version: 322866295\r\n"
|
||||
"Server: gws\r\n"
|
||||
"X-Google-Debug-Label: /srv/alt/job/service.number/1380\r\n"
|
||||
"Content-Length: 220\r\n"
|
||||
"X-XSS-Protection: 0\r\n"
|
||||
"X-Frame-Options: SAMEORIGIN\r\n"
|
||||
"X-Google-Service: web\r\n"
|
||||
"X-Google-DOS-Service-Trace: main:home\r\n"
|
||||
"Alt-Svc: h3-29=\":443\"; ma=2592000,h3-27=\":443\"; "
|
||||
"ma=2592000,h3-25=\":443\"; ma=2592000,h3-T050=\":443\"; "
|
||||
"ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; "
|
||||
"ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; "
|
||||
"v=\"46,43\"\r\n"
|
||||
"\r\n"
|
||||
"<HTML><HEAD><meta http-equiv=\"content-type\" "
|
||||
"content=\"text/html;charset=utf-8\">\r\n"
|
||||
"<TITLE>301 Moved</TITLE></HEAD><BODY>\r\n"
|
||||
"<H1>301 Moved</H1>\r\n"
|
||||
"The document has moved\r\n"
|
||||
"<A HREF=\"https://www.google.com/\">here</A>.\r\n"
|
||||
"</BODY></HTML>\r\n\r\n";
|
||||
|
||||
// A map containing all the Google debug header fields found in
|
||||
// |kSampleResponse|.
|
||||
const std::map<std::string, std::string> kSampleFields = {
|
||||
{"X-Google-GFE-Backend-Request-Info", "eid=7js14zjC48OpziR0VCF02a0"},
|
||||
{"x-google-signals", "FRAMEWORK=TEST"},
|
||||
{"X-Google-Binary-Version", "322287520"},
|
||||
{"X-Google-Request-Cost", "2.50"},
|
||||
{"x-google-data-version", "322866295"},
|
||||
{"X-Google-Debug-Label", "/srv/alt/job/service.number/1380"},
|
||||
{"X-Google-Service", "web"},
|
||||
{"X-Google-DOS-Service-Trace", "main:home"}};
|
||||
|
||||
// A sample HTTP response which does not contain any special header fields.
|
||||
const std::string kFieldlessResponse =
|
||||
"HTTP/2 301\r\n"
|
||||
"Location: https://www.google.com/\r\b"
|
||||
"Content-Type: text/html; charset=UTF-8\r\n"
|
||||
"Date: Thu, 23 Jul 2020 22:52:55 GMT\r\n"
|
||||
"Content-Length: 220\r\n"
|
||||
"\r\n"
|
||||
"<HTML><HEAD><meta http-equiv=\"content-type\" "
|
||||
"content=\"text/html;charset=utf-8\">\r\n"
|
||||
"<TITLE>301 Moved</TITLE></HEAD><BODY>\r\n"
|
||||
"<H1>301 Moved</H1>\r\n"
|
||||
"The document has moved\r\n"
|
||||
"<A HREF=\"https://www.google.com/\">here</A>.\r\n"
|
||||
"</BODY></HTML>\r\n\r\n";
|
||||
|
||||
} // namespace
|
||||
|
||||
class UrlRequestTest : public WvCdmTestBase {
|
||||
protected:
|
||||
void SetUp() override { WvCdmTestBase::SetUp(); }
|
||||
void TearDown() override {}
|
||||
};
|
||||
|
||||
TEST_F(UrlRequestTest, ParseDebugHeader) {
|
||||
// Output map cannot be null.
|
||||
EXPECT_FALSE(UrlRequest::GetDebugHeaderFields(kSampleResponse, nullptr));
|
||||
std::map<std::string, std::string> fields;
|
||||
// Expect false if no debug information can be determined.
|
||||
EXPECT_FALSE(UrlRequest::GetDebugHeaderFields(kFieldlessResponse, &fields));
|
||||
// Expect success.
|
||||
EXPECT_TRUE(UrlRequest::GetDebugHeaderFields(kSampleResponse, &fields));
|
||||
EXPECT_EQ(kSampleFields.size(), fields.size());
|
||||
for (auto it = kSampleFields.cbegin(); it != kSampleFields.cend(); ++it) {
|
||||
auto field = fields.find(it->first);
|
||||
EXPECT_NE(fields.end(), field);
|
||||
EXPECT_EQ(it->second, field->second) << "Key: \"" << it->first << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
Reference in New Issue
Block a user