This source file includes following definitions.
- IsAccessPointSupported
- IsGoodRlzChar
- NormalizeRlz
- GetEventsFromResponseString
- RecordStatefulEvent
- GetProductEventsAsCgiHelper
- SetURLRequestContext
- GetProductEventsAsCgi
- RecordProductEvent
- ClearProductEvent
- GetAccessPointRlz
- SetAccessPointRlz
- FormFinancialPingRequest
- PingFinancialServer
- IsPingResponseValid
- ParseFinancialPingResponse
- SendFinancialPing
- SendFinancialPing
- ParsePingResponse
- GetPingParams
#include "rlz/lib/rlz_lib.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "rlz/lib/assert.h"
#include "rlz/lib/crc32.h"
#include "rlz/lib/financial_ping.h"
#include "rlz/lib/lib_values.h"
#include "rlz/lib/rlz_value_store.h"
#include "rlz/lib/string_utils.h"
namespace {
struct ReturnedEvent {
rlz_lib::AccessPoint access_point;
rlz_lib::Event event_type;
};
bool IsAccessPointSupported(rlz_lib::AccessPoint point) {
switch (point) {
case rlz_lib::NO_ACCESS_POINT:
case rlz_lib::LAST_ACCESS_POINT:
case rlz_lib::MOBILE_IDLE_SCREEN_BLACKBERRY:
case rlz_lib::MOBILE_IDLE_SCREEN_WINMOB:
case rlz_lib::MOBILE_IDLE_SCREEN_SYMBIAN:
return false;
case rlz_lib::IE_DEFAULT_SEARCH:
case rlz_lib::IE_HOME_PAGE:
case rlz_lib::IETB_SEARCH_BOX:
case rlz_lib::QUICK_SEARCH_BOX:
case rlz_lib::GD_DESKBAND:
case rlz_lib::GD_SEARCH_GADGET:
case rlz_lib::GD_WEB_SERVER:
case rlz_lib::GD_OUTLOOK:
case rlz_lib::CHROME_OMNIBOX:
case rlz_lib::CHROME_HOME_PAGE:
default:
return true;
}
}
bool IsGoodRlzChar(const char ch) {
if (IsAsciiAlpha(ch) || IsAsciiDigit(ch))
return true;
switch (ch) {
case '_':
case '-':
case '!':
case '@':
case '$':
case '*':
case '(':
case ')':
case ';':
case '.':
case '<':
case '>':
return true;
}
return false;
}
void NormalizeRlz(const char* raw_rlz, char* normalized_rlz) {
size_t index = 0;
for (; raw_rlz[index] != 0 && index < rlz_lib::kMaxRlzLength; ++index) {
char current = raw_rlz[index];
if (IsGoodRlzChar(current)) {
normalized_rlz[index] = current;
} else {
normalized_rlz[index] = '.';
}
}
normalized_rlz[index] = 0;
}
void GetEventsFromResponseString(
const std::string& response_line,
const std::string& field_header,
std::vector<ReturnedEvent>* event_array) {
std::string events = response_line.substr(field_header.size());
base::TrimWhitespaceASCII(events, base::TRIM_LEADING, &events);
int events_length = events.find_first_of("\r\n ");
if (events_length < 0)
events_length = events.size();
events = events.substr(0, events_length);
int event_end_index = -1;
do {
int event_begin = event_end_index + 1;
event_end_index = events.find(rlz_lib::kEventsCgiSeparator, event_begin);
int event_end = event_end_index;
if (event_end < 0)
event_end = events_length;
std::string event_string = events.substr(event_begin,
event_end - event_begin);
if (event_string.size() != 3)
continue;
rlz_lib::AccessPoint point = rlz_lib::NO_ACCESS_POINT;
rlz_lib::Event event = rlz_lib::INVALID_EVENT;
if (!GetAccessPointFromName(event_string.substr(0, 2).c_str(), &point) ||
point == rlz_lib::NO_ACCESS_POINT) {
continue;
}
if (!GetEventFromName(event_string.substr(event_string.size() - 1).c_str(),
&event) || event == rlz_lib::INVALID_EVENT) {
continue;
}
ReturnedEvent current_event = {point, event};
event_array->push_back(current_event);
} while (event_end_index >= 0);
}
bool RecordStatefulEvent(rlz_lib::Product product, rlz_lib::AccessPoint point,
rlz_lib::Event event) {
rlz_lib::ScopedRlzValueStoreLock lock;
rlz_lib::RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
return false;
const char* point_name = GetAccessPointName(point);
const char* event_name = GetEventName(event);
if (!point_name || !event_name)
return false;
if (!point_name[0] || !event_name[0])
return false;
std::string new_event_value;
base::StringAppendF(&new_event_value, "%s%s", point_name, event_name);
return store->AddStatefulEvent(product, new_event_value.c_str());
}
bool GetProductEventsAsCgiHelper(rlz_lib::Product product, char* cgi,
size_t cgi_size,
rlz_lib::RlzValueStore* store) {
std::string cgi_arg;
base::StringAppendF(&cgi_arg, "%s=", rlz_lib::kEventsCgiVariable);
if (cgi_size <= cgi_arg.size())
return false;
size_t index;
for (index = 0; index < cgi_arg.size(); ++index)
cgi[index] = cgi_arg[index];
std::vector<std::string> events;
if (!store->ReadProductEvents(product, &events))
return false;
size_t num_values = 0;
for (num_values = 0; num_values < events.size(); ++num_values) {
cgi[index] = '\0';
int divider = num_values > 0 ? 1 : 0;
int size = cgi_size - (index + divider);
if (size <= 0)
return cgi_size >= (rlz_lib::kMaxCgiLength + 1);
strncpy(cgi + index + divider, events[num_values].c_str(), size);
if (divider)
cgi[index] = rlz_lib::kEventsCgiSeparator;
index += std::min((int)events[num_values].length(), size) + divider;
}
cgi[index] = '\0';
return num_values > 0;
}
}
namespace rlz_lib {
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
bool SetURLRequestContext(net::URLRequestContextGetter* context) {
return FinancialPing::SetURLRequestContext(context);
}
#endif
bool GetProductEventsAsCgi(Product product, char* cgi, size_t cgi_size) {
if (!cgi || cgi_size <= 0) {
ASSERT_STRING("GetProductEventsAsCgi: Invalid buffer");
return false;
}
cgi[0] = 0;
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
return false;
size_t size_local = std::min(
static_cast<size_t>(kMaxCgiLength + 1), cgi_size);
bool result = GetProductEventsAsCgiHelper(product, cgi, size_local, store);
if (!result) {
ASSERT_STRING("GetProductEventsAsCgi: Possibly insufficient buffer size");
cgi[0] = 0;
return false;
}
return true;
}
bool RecordProductEvent(Product product, AccessPoint point, Event event) {
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
return false;
const char* point_name = GetAccessPointName(point);
const char* event_name = GetEventName(event);
if (!point_name || !event_name)
return false;
if (!point_name[0] || !event_name[0])
return false;
std::string new_event_value;
base::StringAppendF(&new_event_value, "%s%s", point_name, event_name);
if (store->IsStatefulEvent(product, new_event_value.c_str())) {
return true;
}
return store->AddProductEvent(product, new_event_value.c_str());
}
bool ClearProductEvent(Product product, AccessPoint point, Event event) {
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
return false;
const char* point_name = GetAccessPointName(point);
const char* event_name = GetEventName(event);
if (!point_name || !event_name)
return false;
if (!point_name[0] || !event_name[0])
return false;
std::string event_value;
base::StringAppendF(&event_value, "%s%s", point_name, event_name);
return store->ClearProductEvent(product, event_value.c_str());
}
bool GetAccessPointRlz(AccessPoint point, char* rlz, size_t rlz_size) {
if (!rlz || rlz_size <= 0) {
ASSERT_STRING("GetAccessPointRlz: Invalid buffer");
return false;
}
rlz[0] = 0;
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
return false;
if (!IsAccessPointSupported(point))
return false;
return store->ReadAccessPointRlz(point, rlz, rlz_size);
}
bool SetAccessPointRlz(AccessPoint point, const char* new_rlz) {
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
return false;
if (!new_rlz) {
ASSERT_STRING("SetAccessPointRlz: Invalid buffer");
return false;
}
if (!IsAccessPointSupported(point)) {
ASSERT_STRING(("SetAccessPointRlz: "
"Cannot set RLZ for unsupported access point."));
return false;
}
size_t rlz_length = strlen(new_rlz);
if (rlz_length > kMaxRlzLength) {
ASSERT_STRING("SetAccessPointRlz: RLZ length is exceeds max allowed.");
return false;
}
char normalized_rlz[kMaxRlzLength + 1];
NormalizeRlz(new_rlz, normalized_rlz);
VERIFY(strlen(new_rlz) == rlz_length);
if (normalized_rlz[0] == 0)
return store->ClearAccessPointRlz(point);
return store->WriteAccessPointRlz(point, normalized_rlz);
}
bool FormFinancialPingRequest(Product product, const AccessPoint* access_points,
const char* product_signature,
const char* product_brand,
const char* product_id,
const char* product_lang,
bool exclude_machine_id,
char* request, size_t request_buffer_size) {
if (!request || request_buffer_size == 0)
return false;
request[0] = 0;
std::string request_string;
if (!FinancialPing::FormRequest(product, access_points, product_signature,
product_brand, product_id, product_lang,
exclude_machine_id, &request_string))
return false;
if (request_string.size() >= request_buffer_size)
return false;
strncpy(request, request_string.c_str(), request_buffer_size);
request[request_buffer_size - 1] = 0;
return true;
}
bool PingFinancialServer(Product product, const char* request, char* response,
size_t response_buffer_size) {
if (!response || response_buffer_size == 0)
return false;
response[0] = 0;
if (!FinancialPing::IsPingTime(product, false))
return false;
std::string response_string;
if (!FinancialPing::PingServer(request, &response_string))
return false;
if (response_string.size() >= response_buffer_size)
return false;
strncpy(response, response_string.c_str(), response_buffer_size);
response[response_buffer_size - 1] = 0;
return true;
}
bool IsPingResponseValid(const char* response, int* checksum_idx) {
if (!response || !response[0])
return false;
if (checksum_idx)
*checksum_idx = -1;
if (strlen(response) > kMaxPingResponseLength) {
ASSERT_STRING("IsPingResponseValid: response is too long to parse.");
return false;
}
std::string response_string(response);
std::string checksum_param("\ncrc32: ");
int calculated_crc;
int checksum_index = response_string.find(checksum_param);
if (checksum_index >= 0) {
std::string message(response_string.substr(0, checksum_index + 1));
if (!Crc32(message.c_str(), &calculated_crc))
return false;
} else {
checksum_param = "crc32: ";
if (!StartsWithASCII(response_string, checksum_param, true))
return false;
checksum_index = 0;
if (!Crc32("", &calculated_crc))
return false;
}
int checksum_end = response_string.find("\n", checksum_index + 1);
if (checksum_end < 0)
checksum_end = response_string.size();
int checksum_begin = checksum_index + checksum_param.size();
std::string checksum = response_string.substr(checksum_begin,
checksum_end - checksum_begin + 1);
base::TrimWhitespaceASCII(checksum, base::TRIM_ALL, &checksum);
if (checksum_idx)
*checksum_idx = checksum_index;
return calculated_crc == HexStringToInteger(checksum.c_str());
}
bool ParseFinancialPingResponse(Product product, const char* response) {
FinancialPing::UpdateLastPingTime(product);
return ParsePingResponse(product, response);
}
bool SendFinancialPing(Product product, const AccessPoint* access_points,
const char* product_signature,
const char* product_brand,
const char* product_id, const char* product_lang,
bool exclude_machine_id) {
return SendFinancialPing(product, access_points, product_signature,
product_brand, product_id, product_lang,
exclude_machine_id, false);
}
bool SendFinancialPing(Product product, const AccessPoint* access_points,
const char* product_signature,
const char* product_brand,
const char* product_id, const char* product_lang,
bool exclude_machine_id,
const bool skip_time_check) {
std::string request;
if (!FinancialPing::FormRequest(product, access_points, product_signature,
product_brand, product_id, product_lang,
exclude_machine_id, &request))
return false;
if (!FinancialPing::IsPingTime(product, skip_time_check))
return false;
FinancialPing::UpdateLastPingTime(product);
std::string response;
if (!FinancialPing::PingServer(request.c_str(), &response))
return false;
return ParsePingResponse(product, response.c_str());
}
bool ParsePingResponse(Product product, const char* response) {
rlz_lib::ScopedRlzValueStoreLock lock;
rlz_lib::RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(rlz_lib::RlzValueStore::kWriteAccess))
return false;
std::string response_string(response);
int response_length = -1;
if (!IsPingResponseValid(response, &response_length))
return false;
if (0 == response_length)
return true;
std::string events_variable;
std::string stateful_events_variable;
base::SStringPrintf(&events_variable, "%s: ", kEventsCgiVariable);
base::SStringPrintf(&stateful_events_variable, "%s: ",
kStatefulEventsCgiVariable);
int rlz_cgi_length = strlen(kRlzCgiVariable);
int line_end_index = -1;
do {
int line_begin = line_end_index + 1;
line_end_index = response_string.find("\n", line_begin);
int line_end = line_end_index;
if (line_end < 0)
line_end = response_length;
if (line_end <= line_begin)
continue;
std::string response_line;
response_line = response_string.substr(line_begin, line_end - line_begin);
if (StartsWithASCII(response_line, kRlzCgiVariable, true)) {
int separator_index = -1;
if ((separator_index = response_line.find(": ")) < 0)
continue;
std::string point_name =
response_line.substr(3, separator_index - rlz_cgi_length);
AccessPoint point = NO_ACCESS_POINT;
if (!GetAccessPointFromName(point_name.c_str(), &point) ||
point == NO_ACCESS_POINT)
continue;
std::string rlz_value(response_line.substr(separator_index + 2));
base::TrimWhitespaceASCII(rlz_value, base::TRIM_LEADING, &rlz_value);
size_t rlz_length = rlz_value.find_first_of("\r\n ");
if (rlz_length == std::string::npos)
rlz_length = rlz_value.size();
if (rlz_length > kMaxRlzLength)
continue;
if (IsAccessPointSupported(point))
SetAccessPointRlz(point, rlz_value.substr(0, rlz_length).c_str());
} else if (StartsWithASCII(response_line, events_variable, true)) {
std::vector<ReturnedEvent> event_array;
GetEventsFromResponseString(response_line, events_variable, &event_array);
for (size_t i = 0; i < event_array.size(); ++i) {
ClearProductEvent(product, event_array[i].access_point,
event_array[i].event_type);
}
} else if (StartsWithASCII(response_line, stateful_events_variable, true)) {
std::vector<ReturnedEvent> event_array;
GetEventsFromResponseString(response_line, stateful_events_variable,
&event_array);
for (size_t i = 0; i < event_array.size(); ++i) {
RecordStatefulEvent(product, event_array[i].access_point,
event_array[i].event_type);
}
}
} while (line_end_index >= 0);
#if defined(OS_WIN)
SetMachineDealCodeFromPingResponse(response);
#endif
return true;
}
bool GetPingParams(Product product, const AccessPoint* access_points,
char* cgi, size_t cgi_size) {
if (!cgi || cgi_size <= 0) {
ASSERT_STRING("GetPingParams: Invalid buffer");
return false;
}
cgi[0] = 0;
if (!access_points) {
ASSERT_STRING("GetPingParams: access_points is NULL");
return false;
}
std::string cgi_string(kProtocolCgiArgument);
base::StringAppendF(&cgi_string, "&%s=", kRlzCgiVariable);
{
ScopedRlzValueStoreLock lock;
RlzValueStore* store = lock.GetStore();
if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
return false;
bool first_rlz = true;
for (int i = 0; access_points[i] != NO_ACCESS_POINT; i++) {
char rlz[kMaxRlzLength + 1];
if (GetAccessPointRlz(access_points[i], rlz, arraysize(rlz))) {
const char* access_point = GetAccessPointName(access_points[i]);
if (!access_point)
continue;
base::StringAppendF(&cgi_string, "%s%s%s%s",
first_rlz ? "" : kRlzCgiSeparator,
access_point, kRlzCgiIndicator, rlz);
first_rlz = false;
}
}
#if defined(OS_WIN)
char dcc[kMaxDccLength + 1];
dcc[0] = 0;
if (GetMachineDealCode(dcc, arraysize(dcc)) && dcc[0])
base::StringAppendF(&cgi_string, "&%s=%s", kDccCgiVariable, dcc);
#endif
}
if (cgi_string.size() >= cgi_size)
return false;
strncpy(cgi, cgi_string.c_str(), cgi_size);
cgi[cgi_size - 1] = 0;
return true;
}
}