blob: 2f3a5b7cd64a051fb1499475d833b936e526dd0a [file] [log] [blame]
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Author: matterbury@google.com (Matt Atterbury),
// morlovich@google.com (Maksim Orlovich)
#include "net/instaweb/rewriter/public/measurement_proxy_url_namer.h"
#include <cstddef> // for size_t
#include "base/logging.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/http/google_url.h"
namespace net_instaweb {
MeasurementProxyUrlNamer::MeasurementProxyUrlNamer(
const GoogleString& top_origin, const GoogleString& password)
: top_origin_(top_origin), password_(password) {
if (StringPiece(top_origin_).ends_with("/")) {
top_origin_.resize(top_origin.size() - 1);
}
}
MeasurementProxyUrlNamer::~MeasurementProxyUrlNamer() {
}
bool MeasurementProxyUrlNamer::Decode(
const GoogleUrl& request_url, const RewriteOptions*,
GoogleString* decoded) const {
StringPiece config, config_domain, password;
return DecodePathDetails(request_url, &config, &config_domain,
&password, decoded);
}
// Naming scheme:
// For cross-domain resources:
// https://top_domain_/code/config/password/config_host/resource_host/path
// For same-domain resources:
// https://top_domain_/code/config/password/resource_host/path
//
// Where code is:
// h: same-domain http
// x: cross-domain https
// s: same-domain https
// t: cross-domain https
bool MeasurementProxyUrlNamer::DecodePathDetails(
const GoogleUrl& request_url,
StringPiece* config,
StringPiece* config_domain,
StringPiece* password,
GoogleString* res_url) {
StringPiece request_path = request_url.PathSansLeaf();
StringPieceVector path_vector;
SplitStringPieceToVector(request_path, "/", &path_vector, false);
// The leading slash results in path_vector[0] being "", and all the
// other indices into it being one more than one would think.
DCHECK(path_vector.empty() || path_vector[0] == "");
if (path_vector.size() < 5) {
return false;
}
StringPiece code = path_vector[1];
*config = path_vector[2];
*password = path_vector[3];
StringPiece res_schema = "http";
if (code == "s" || code == "t") {
res_schema = "https";
}
size_t site_path_start;
StringPiece res_domain;
if (code == "h" || code == "s") {
// Same domain.
*config_domain = res_domain = path_vector[4];
site_path_start = 5;
} else if (code == "x" || code == "t") {
if (path_vector.size() < 6) {
return false;
}
*config_domain = path_vector[4];
res_domain = path_vector[5];
site_path_start = 6;
} else {
return false;
}
if (config_domain->empty() || res_domain.empty()) {
return false;
}
*res_url = StrCat(res_schema, "://", res_domain);
// There is also an empty fragment after the last directory, hence n
// being one less than the size here.
for (size_t i = site_path_start, n = path_vector.size() - 1; i < n; ++i) {
StrAppend(res_url, "/", path_vector[i]);
}
StrAppend(res_url, "/", request_url.LeafWithQuery());
return true;
}
bool MeasurementProxyUrlNamer::IsProxyEncoded(const GoogleUrl& url) const {
StringPiece config, config_domain, password;
GoogleString decoded;
if (DecodePathDetails(url, &config, &config_domain, &password, &decoded)) {
// Looks like the right syntax, but check to see if it's actually on our
// host and not elsewhere.
return (password == password_ && url.Origin() == top_origin_);
} else {
return false;
}
}
} // namespace net_instaweb