This source file includes following definitions.
- AreSchemesEqual
- DoesBeginSlashWindowsDriveSpec
- DoIsRelativeURL
- CopyToLastSlash
- CopyOneComponent
- CopyBaseDriveSpecIfNecessary
- DoResolveRelativePath
- DoResolveRelativeHost
- DoResolveAbsoluteFile
- DoResolveRelativeURL
- IsRelativeURL
- IsRelativeURL
- ResolveRelativeURL
- ResolveRelativeURL
#include "base/logging.h"
#include "url/url_canon.h"
#include "url/url_canon_internal.h"
#include "url/url_file.h"
#include "url/url_parse_internal.h"
#include "url/url_util_internal.h"
namespace url_canon {
namespace {
template<typename CHAR>
bool AreSchemesEqual(const char* base,
const url_parse::Component& base_scheme,
const CHAR* cmp,
const url_parse::Component& cmp_scheme) {
if (base_scheme.len != cmp_scheme.len)
return false;
for (int i = 0; i < base_scheme.len; i++) {
if (CanonicalSchemeChar(cmp[cmp_scheme.begin + i]) !=
base[base_scheme.begin + i])
return false;
}
return true;
}
#ifdef WIN32
template<typename CHAR>
bool DoesBeginSlashWindowsDriveSpec(const CHAR* spec, int start_offset,
int spec_len) {
if (start_offset >= spec_len)
return false;
return url_parse::IsURLSlash(spec[start_offset]) &&
url_parse::DoesBeginWindowsDriveSpec(spec, start_offset + 1, spec_len);
}
#endif
template<typename CHAR>
bool DoIsRelativeURL(const char* base,
const url_parse::Parsed& base_parsed,
const CHAR* url,
int url_len,
bool is_base_hierarchical,
bool* is_relative,
url_parse::Component* relative_component) {
*is_relative = false;
int begin = 0;
url_parse::TrimURL(url, &begin, &url_len);
if (begin >= url_len) {
*relative_component = url_parse::Component(begin, 0);
*is_relative = true;
return true;
}
#ifdef WIN32
if (url_parse::DoesBeginWindowsDriveSpec(url, begin, url_len) ||
url_parse::DoesBeginUNCPath(url, begin, url_len, true))
return true;
#endif
url_parse::Component scheme;
const bool scheme_is_empty =
!url_parse::ExtractScheme(url, url_len, &scheme) || scheme.len == 0;
if (scheme_is_empty) {
if (url[begin] == '#') {
} else if (!is_base_hierarchical) {
return false;
}
*relative_component = url_parse::MakeRange(begin, url_len);
*is_relative = true;
return true;
}
int scheme_end = scheme.end();
for (int i = scheme.begin; i < scheme_end; i++) {
if (!CanonicalSchemeChar(url[i])) {
if (!is_base_hierarchical) {
return false;
}
*relative_component = url_parse::MakeRange(begin, url_len);
*is_relative = true;
return true;
}
}
if (!AreSchemesEqual(base, base_parsed.scheme, url, scheme))
return true;
if (!is_base_hierarchical)
return true;
int colon_offset = scheme.end();
if (url_util::CompareSchemeComponent(url, scheme, "filesystem"))
return true;
int num_slashes = url_parse::CountConsecutiveSlashes(url, colon_offset + 1,
url_len);
if (num_slashes == 0 || num_slashes == 1) {
*is_relative = true;
*relative_component = url_parse::MakeRange(colon_offset + 1, url_len);
return true;
}
return true;
}
void CopyToLastSlash(const char* spec,
int begin,
int end,
CanonOutput* output) {
int last_slash = -1;
for (int i = end - 1; i >= begin; i--) {
if (spec[i] == '/') {
last_slash = i;
break;
}
}
if (last_slash < 0)
return;
for (int i = begin; i <= last_slash; i++)
output->push_back(spec[i]);
}
void CopyOneComponent(const char* source,
const url_parse::Component& source_component,
CanonOutput* output,
url_parse::Component* output_component) {
if (source_component.len < 0) {
*output_component = url_parse::Component();
return;
}
output_component->begin = output->length();
int source_end = source_component.end();
for (int i = source_component.begin; i < source_end; i++)
output->push_back(source[i]);
output_component->len = output->length() - output_component->begin;
}
#ifdef WIN32
template<typename CHAR>
int CopyBaseDriveSpecIfNecessary(const char* base_url,
int base_path_begin,
int base_path_end,
const CHAR* relative_url,
int path_start,
int relative_url_len,
CanonOutput* output) {
if (base_path_begin >= base_path_end)
return base_path_begin;
if (url_parse::DoesBeginWindowsDriveSpec(relative_url,
path_start, relative_url_len)) {
return base_path_begin;
}
if (DoesBeginSlashWindowsDriveSpec(base_url,
base_path_begin,
base_path_end)) {
output->push_back('/');
output->push_back(base_url[base_path_begin + 1]);
output->push_back(base_url[base_path_begin + 2]);
return base_path_begin + 3;
}
return base_path_begin;
}
#endif
template<typename CHAR>
bool DoResolveRelativePath(const char* base_url,
const url_parse::Parsed& base_parsed,
bool base_is_file,
const CHAR* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
bool success = true;
url_parse::Component path, query, ref;
url_parse::ParsePathInternal(relative_url,
relative_component,
&path,
&query,
&ref);
output->Append(base_url, base_parsed.path.begin);
if (path.len > 0) {
int true_path_begin = output->length();
int base_path_begin = base_parsed.path.begin;
#ifdef WIN32
if (base_is_file) {
base_path_begin = CopyBaseDriveSpecIfNecessary(
base_url, base_parsed.path.begin, base_parsed.path.end(),
relative_url, relative_component.begin, relative_component.end(),
output);
}
#endif
if (url_parse::IsURLSlash(relative_url[path.begin])) {
success &= CanonicalizePath(relative_url, path,
output, &out_parsed->path);
} else {
int path_begin = output->length();
CopyToLastSlash(base_url, base_path_begin, base_parsed.path.end(),
output);
success &= CanonicalizePartialPath(relative_url, path, path_begin,
output);
out_parsed->path = url_parse::MakeRange(path_begin, output->length());
}
CanonicalizeQuery(relative_url, query, query_converter,
output, &out_parsed->query);
CanonicalizeRef(relative_url, ref, output, &out_parsed->ref);
out_parsed->path = url_parse::MakeRange(true_path_begin,
out_parsed->path.end());
return success;
}
CopyOneComponent(base_url, base_parsed.path, output, &out_parsed->path);
if (query.is_valid()) {
CanonicalizeQuery(relative_url, query, query_converter,
output, &out_parsed->query);
CanonicalizeRef(relative_url, ref, output, &out_parsed->ref);
return success;
}
if (base_parsed.query.is_valid())
output->push_back('?');
CopyOneComponent(base_url, base_parsed.query, output, &out_parsed->query);
if (ref.is_valid()) {
CanonicalizeRef(relative_url, ref, output, &out_parsed->ref);
return success;
}
DCHECK(false) << "Not reached";
return success;
}
template<typename CHAR>
bool DoResolveRelativeHost(const char* base_url,
const url_parse::Parsed& base_parsed,
const CHAR* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
url_parse::Parsed relative_parsed;
url_parse::ParseAfterScheme(relative_url, relative_component.end(),
relative_component.begin, &relative_parsed);
Replacements<CHAR> replacements;
replacements.SetUsername(relative_url, relative_parsed.username);
replacements.SetPassword(relative_url, relative_parsed.password);
replacements.SetHost(relative_url, relative_parsed.host);
replacements.SetPort(relative_url, relative_parsed.port);
replacements.SetPath(relative_url, relative_parsed.path);
replacements.SetQuery(relative_url, relative_parsed.query);
replacements.SetRef(relative_url, relative_parsed.ref);
return ReplaceStandardURL(base_url, base_parsed, replacements,
query_converter, output, out_parsed);
}
template<typename CHAR>
bool DoResolveAbsoluteFile(const CHAR* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
url_parse::Parsed relative_parsed;
url_parse::ParseFileURL(&relative_url[relative_component.begin],
relative_component.len, &relative_parsed);
return CanonicalizeFileURL(&relative_url[relative_component.begin],
relative_component.len, relative_parsed,
query_converter, output, out_parsed);
}
template<typename CHAR>
bool DoResolveRelativeURL(const char* base_url,
const url_parse::Parsed& base_parsed,
bool base_is_file,
const CHAR* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
*out_parsed = base_parsed;
if (base_parsed.path.len <= 0) {
int base_len = base_parsed.Length();
for (int i = 0; i < base_len; i++)
output->push_back(base_url[i]);
return false;
}
if (relative_component.len <= 0) {
int base_len = base_parsed.Length();
base_len -= base_parsed.ref.len + 1;
out_parsed->ref.reset();
output->Append(base_url, base_len);
return true;
}
int num_slashes = url_parse::CountConsecutiveSlashes(
relative_url, relative_component.begin, relative_component.end());
#ifdef WIN32
int after_slashes = relative_component.begin + num_slashes;
if (url_parse::DoesBeginUNCPath(relative_url, relative_component.begin,
relative_component.end(), !base_is_file) ||
((num_slashes == 0 || base_is_file) &&
url_parse::DoesBeginWindowsDriveSpec(relative_url, after_slashes,
relative_component.end()))) {
return DoResolveAbsoluteFile(relative_url, relative_component,
query_converter, output, out_parsed);
}
#else
if (base_is_file &&
(num_slashes >= 2 || num_slashes == relative_component.len)) {
return DoResolveAbsoluteFile(relative_url, relative_component,
query_converter, output, out_parsed);
}
#endif
if (num_slashes >= 2) {
return DoResolveRelativeHost(base_url, base_parsed,
relative_url, relative_component,
query_converter, output, out_parsed);
}
return DoResolveRelativePath(base_url, base_parsed, base_is_file,
relative_url, relative_component,
query_converter, output, out_parsed);
}
}
bool IsRelativeURL(const char* base,
const url_parse::Parsed& base_parsed,
const char* fragment,
int fragment_len,
bool is_base_hierarchical,
bool* is_relative,
url_parse::Component* relative_component) {
return DoIsRelativeURL<char>(
base, base_parsed, fragment, fragment_len, is_base_hierarchical,
is_relative, relative_component);
}
bool IsRelativeURL(const char* base,
const url_parse::Parsed& base_parsed,
const base::char16* fragment,
int fragment_len,
bool is_base_hierarchical,
bool* is_relative,
url_parse::Component* relative_component) {
return DoIsRelativeURL<base::char16>(
base, base_parsed, fragment, fragment_len, is_base_hierarchical,
is_relative, relative_component);
}
bool ResolveRelativeURL(const char* base_url,
const url_parse::Parsed& base_parsed,
bool base_is_file,
const char* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
return DoResolveRelativeURL<char>(
base_url, base_parsed, base_is_file, relative_url,
relative_component, query_converter, output, out_parsed);
}
bool ResolveRelativeURL(const char* base_url,
const url_parse::Parsed& base_parsed,
bool base_is_file,
const base::char16* relative_url,
const url_parse::Component& relative_component,
CharsetConverter* query_converter,
CanonOutput* output,
url_parse::Parsed* out_parsed) {
return DoResolveRelativeURL<base::char16>(
base_url, base_parsed, base_is_file, relative_url,
relative_component, query_converter, output, out_parsed);
}
}