This source file includes following definitions.
- HasPatternMatchingAnnotation
- ParseManifest
#include "webkit/browser/appcache/manifest_parser.h"
#include "base/command_line.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "url/gurl.h"
namespace appcache {
namespace {
bool HasPatternMatchingAnnotation(const wchar_t* line_p,
const wchar_t* line_end) {
while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
++line_p;
if (line_p == line_end)
return false;
std::wstring annotation(line_p, line_end - line_p);
return annotation == L"isPattern";
}
}
enum Mode {
EXPLICIT,
INTERCEPT,
FALLBACK,
ONLINE_WHITELIST,
UNKNOWN_MODE,
};
enum InterceptVerb {
RETURN,
EXECUTE,
UNKNOWN_VERB,
};
Manifest::Manifest() : online_whitelist_all(false) {}
Manifest::~Manifest() {}
bool ParseManifest(const GURL& manifest_url, const char* data, int length,
Manifest& manifest) {
const wchar_t kSignature[] = L"CACHE MANIFEST";
const size_t kSignatureLength = arraysize(kSignature) - 1;
const wchar_t kChromiumSignature[] = L"CHROMIUM CACHE MANIFEST";
const size_t kChromiumSignatureLength = arraysize(kChromiumSignature) - 1;
DCHECK(manifest.explicit_urls.empty());
DCHECK(manifest.fallback_namespaces.empty());
DCHECK(manifest.online_whitelist_namespaces.empty());
DCHECK(!manifest.online_whitelist_all);
Mode mode = EXPLICIT;
std::wstring data_string;
base::CodepageToWide(std::string(data, length), base::kCodepageUTF8,
base::OnStringConversionError::SUBSTITUTE, &data_string);
const wchar_t* p = data_string.c_str();
const wchar_t* end = p + data_string.length();
int bom_offset = 0;
if (!data_string.empty() && data_string[0] == 0xFEFF) {
bom_offset = 1;
++p;
}
if (p >= end)
return false;
if (0 == data_string.compare(bom_offset, kSignatureLength,
kSignature)) {
p += kSignatureLength;
} else if (0 == data_string.compare(bom_offset, kChromiumSignatureLength,
kChromiumSignature)) {
p += kChromiumSignatureLength;
} else {
return false;
}
if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
return false;
while (p < end && *p != '\r' && *p != '\n')
++p;
while (1) {
while (p < end && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'))
++p;
if (p == end)
break;
const wchar_t* line_start = p;
while (p < end && *p != '\r' && *p != '\n')
++p;
if (*line_start == '#')
continue;
const wchar_t* tmp = p - 1;
while (tmp > line_start && (*tmp == ' ' || *tmp == '\t'))
--tmp;
std::wstring line(line_start, tmp - line_start + 1);
if (line == L"CACHE:") {
mode = EXPLICIT;
} else if (line == L"FALLBACK:") {
mode = FALLBACK;
} else if (line == L"NETWORK:") {
mode = ONLINE_WHITELIST;
} else if (line == L"CHROMIUM-INTERCEPT:") {
mode = INTERCEPT;
} else if (*(line.end() - 1) == ':') {
mode = UNKNOWN_MODE;
} else if (mode == UNKNOWN_MODE) {
continue;
} else if (line == L"*" && mode == ONLINE_WHITELIST) {
manifest.online_whitelist_all = true;
continue;
} else if (mode == EXPLICIT || mode == ONLINE_WHITELIST) {
const wchar_t *line_p = line.c_str();
const wchar_t *line_end = line_p + line.length();
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
base::string16 url16;
base::WideToUTF16(line.c_str(), line_p - line.c_str(), &url16);
GURL url = manifest_url.Resolve(url16);
if (!url.is_valid())
continue;
if (url.has_ref()) {
GURL::Replacements replacements;
replacements.ClearRef();
url = url.ReplaceComponents(replacements);
}
if (url.scheme() != manifest_url.scheme()) {
continue;
}
if (mode == EXPLICIT) {
manifest.explicit_urls.insert(url.spec());
} else {
bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
manifest.online_whitelist_namespaces.push_back(
Namespace(NETWORK_NAMESPACE, url, GURL(), is_pattern));
}
} else if (mode == INTERCEPT) {
const wchar_t* line_p = line.c_str();
const wchar_t* line_end = line_p + line.length();
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
if (line_p == line_end)
continue;
base::string16 namespace_url16;
base::WideToUTF16(line.c_str(), line_p - line.c_str(), &namespace_url16);
GURL namespace_url = manifest_url.Resolve(namespace_url16);
if (!namespace_url.is_valid())
continue;
if (namespace_url.has_ref()) {
GURL::Replacements replacements;
replacements.ClearRef();
namespace_url = namespace_url.ReplaceComponents(replacements);
}
if (manifest_url.GetOrigin() != namespace_url.GetOrigin())
continue;
while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
++line_p;
const wchar_t* type_start = line_p;
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
InterceptVerb verb = UNKNOWN_VERB;
std::wstring type(type_start, line_p - type_start);
if (type == L"return") {
verb = RETURN;
} else if (type == L"execute" &&
CommandLine::ForCurrentProcess()->HasSwitch(
kEnableExecutableHandlers)) {
verb = EXECUTE;
}
if (verb == UNKNOWN_VERB)
continue;
while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
++line_p;
const wchar_t* target_url_start = line_p;
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
base::string16 target_url16;
base::WideToUTF16(target_url_start, line_p - target_url_start,
&target_url16);
GURL target_url = manifest_url.Resolve(target_url16);
if (!target_url.is_valid())
continue;
if (target_url.has_ref()) {
GURL::Replacements replacements;
replacements.ClearRef();
target_url = target_url.ReplaceComponents(replacements);
}
if (manifest_url.GetOrigin() != target_url.GetOrigin())
continue;
bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
manifest.intercept_namespaces.push_back(
Namespace(INTERCEPT_NAMESPACE, namespace_url,
target_url, is_pattern, verb == EXECUTE));
} else if (mode == FALLBACK) {
const wchar_t* line_p = line.c_str();
const wchar_t* line_end = line_p + line.length();
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
if (line_p == line_end) {
continue;
}
base::string16 namespace_url16;
base::WideToUTF16(line.c_str(), line_p - line.c_str(), &namespace_url16);
GURL namespace_url = manifest_url.Resolve(namespace_url16);
if (!namespace_url.is_valid())
continue;
if (namespace_url.has_ref()) {
GURL::Replacements replacements;
replacements.ClearRef();
namespace_url = namespace_url.ReplaceComponents(replacements);
}
if (manifest_url.GetOrigin() != namespace_url.GetOrigin()) {
continue;
}
while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
++line_p;
const wchar_t* fallback_start = line_p;
while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
++line_p;
base::string16 fallback_url16;
base::WideToUTF16(fallback_start, line_p - fallback_start,
&fallback_url16);
GURL fallback_url = manifest_url.Resolve(fallback_url16);
if (!fallback_url.is_valid())
continue;
if (fallback_url.has_ref()) {
GURL::Replacements replacements;
replacements.ClearRef();
fallback_url = fallback_url.ReplaceComponents(replacements);
}
if (manifest_url.GetOrigin() != fallback_url.GetOrigin()) {
continue;
}
bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
manifest.fallback_namespaces.push_back(
Namespace(FALLBACK_NAMESPACE, namespace_url,
fallback_url, is_pattern));
} else {
NOTREACHED();
}
}
return true;
}
}