Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Unified Diff: components/arc/intent_helper/intent_filter.cc

Issue 2128913002: Implement chrome-side intent filtering. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make the compiler happy. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/arc/intent_helper/intent_filter.cc
diff --git a/components/arc/intent_helper/intent_filter.cc b/components/arc/intent_helper/intent_filter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..23b72fab00ae7d42eb802ff90a687323ce9d65cf
--- /dev/null
+++ b/components/arc/intent_helper/intent_filter.cc
@@ -0,0 +1,239 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
Yusuke Sato 2016/07/11 04:38:32 <algorithm> for std::transform, <ctype.h> for tolo
Ben Kwa 2016/07/11 21:22:58 Removed both after the switch to base::toLowerASCI
+#include "intent_filter.h"
Yusuke Sato 2016/07/11 04:38:31 components/arc/intent_helper/intent_filter.h
Ben Kwa 2016/07/11 21:22:58 Done.
+
+#include "url/gurl.h"
+
+namespace arc {
+
+IntentFilter::IntentFilter(
+ const mojom::IntentFilterPtr& mojo_intent_filter)
+{
Yusuke Sato 2016/07/11 04:38:32 ... mojo_intent_filter) {
Ben Kwa 2016/07/11 21:22:58 Done.
+ for (const mojom::AuthorityEntryPtr& authorityptr:
+ mojo_intent_filter->data_authorities) {
+ authorities_.push_back(AuthorityEntry(authorityptr));
+ }
+ for (const mojom::PatternMatcherPtr& pattern:
+ mojo_intent_filter->data_paths) {
+ paths_.push_back(PatternMatcher(pattern));
+ }
+ for (const mojom::PatternMatcherPtr& pattern:
+ mojo_intent_filter->data_scheme_specific_parts) {
+ scheme_specific_parts_.push_back(PatternMatcher(pattern));
+ }
+}
+
+IntentFilter::IntentFilter(const IntentFilter& other) = default;
+
+IntentFilter::~IntentFilter() = default;
+
+bool IntentFilter::match(
Yusuke Sato 2016/07/11 04:38:32 Could you let me know a list of function you trans
Ben Kwa 2016/07/11 21:22:58 Direct transcriptions: - IntentFilter::hasDataSche
+ const GURL& url) const {
+ // Chrome-side code only receives view intents for http/https URLs, so this
+ // match code really only implements the matchData part of the android
+ // IntentFilter class.
+ if (!url.SchemeIsHTTPOrHTTPS()) {
+ return false;
+ }
+
+ bool match = false;
+ if (scheme_specific_parts_.size() > 0) {
+ match = hasDataSchemeSpecificPart(url);
+ }
+ if (match == false) {
rickyz (no longer on Chrome) 2016/07/11 21:27:51 nit: if (!match) Or better yet, how about just re
Ben Kwa 2016/07/11 22:34:02 Ack. I can't believe I wrote that. Done.
+ // If there isn't any matching ssp, we need to match an authority.
+ if (authorities_.size() > 0) {
+ bool authMatch = matchDataAuthority(url);
rickyz (no longer on Chrome) 2016/07/11 21:27:51 Could reduce some nesting with: match = matchData
Ben Kwa 2016/07/11 22:34:02 Done.
+ if (authMatch) {
+ if (paths_.empty()) {
rickyz (no longer on Chrome) 2016/07/11 21:27:52 nit: would be nice to be consistent with .empty()
Ben Kwa 2016/07/11 22:34:01 Done.
+ match = authMatch;
+ } else if (hasDataPath(url)) {
+ match = true;
+ }
+ }
+ }
+ }
+ return match;
+}
+
+bool IntentFilter::hasDataSchemeSpecificPart(
+ const GURL& url) const {
+ // The scheme-specific-part is the content of the URL minus the ref fragment.
+ std::string ssp = url.GetContent();
+ if (url.has_ref()) {
rickyz (no longer on Chrome) 2016/07/11 21:27:52 Can we use GURL::ReplaceComponents instead to get
Ben Kwa 2016/07/11 22:34:01 Done.
+ std::string fragment = url.ref();
+ // Fragment doesn't include the leading '#', so decrement the position by 1
+ // when cutting it out of the ssp.
+ ssp = ssp.substr(0, ssp.rfind(fragment)-1);
+ }
+ for (const PatternMatcher& pattern: scheme_specific_parts_) {
+ if (pattern.match(ssp)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IntentFilter::hasDataPath(
+ const GURL& url) const {
+ const std::string path = url.path();
+ for (const PatternMatcher& pattern: paths_) {
+ if (pattern.match(path)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IntentFilter::matchDataAuthority(
+ const GURL& url) const {
+ for (const AuthorityEntry& authority: authorities_) {
+ if (authority.match(url)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+IntentFilter::AuthorityEntry::AuthorityEntry(
+ const mojom::AuthorityEntryPtr& entry):
+ host_(entry->host.get()),
+ port_(entry->port) {
+ // Wildcards are only allowed at the front of the host string.
+ wild_ = host_.length() > 0 && host_[0] == '*';
+ if (wild_) {
+ host_ = host_.substr(1);
+ }
+ std::transform(host_.begin(), host_.end(), host_.begin(), ::tolower);
Yusuke Sato 2016/07/11 04:38:32 base/strings/string_util.cc has ToLowerASCII(). ba
Ben Kwa 2016/07/11 21:22:58 I'm going with base::ToLowerASCII for now. Probab
rickyz (no longer on Chrome) 2016/07/11 21:27:52 According to https://developer.android.com/referen
Ben Kwa 2016/07/11 22:34:01 So, you're reading that note as prescriptive, but
+}
+
+bool IntentFilter::AuthorityEntry::match(
+ const GURL& url) const {
+ if (!url.has_host()) return false;
+ std::string host = url.host();
+ std::transform(host.begin(), host.end(), host.begin(), ::tolower);
Yusuke Sato 2016/07/11 04:38:32 same
Ben Kwa 2016/07/11 21:22:58 Done.
+ const int port = url.IntPort();
rickyz (no longer on Chrome) 2016/07/11 21:27:52 Do you want EffectiveIntPort here? This returns PO
Ben Kwa 2016/07/11 22:34:01 A filter with an explicitly specified default port
+
+ if (wild_) {
+ if (host.length() < host_.length()) {
+ return false;
+ }
+ host = host.substr(host.length() - host_.length());
rickyz (no longer on Chrome) 2016/07/11 21:27:52 Can we just use base::EndsWith from base/strings/s
Ben Kwa 2016/07/11 22:34:02 Done.
+ }
+ if (host.compare(host_) != 0) {
+ return false;
+ }
+ if (port_ >= 0) {
+ if (port_ != port) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+IntentFilter::PatternMatcher::PatternMatcher(
+ const mojom::PatternMatcherPtr& pattern):
+ pattern_(pattern->pattern.get()),
+ match_type_(pattern->type) {
+}
+
+bool IntentFilter::PatternMatcher::match(
+ const std::string& match) const {
rickyz (no longer on Chrome) 2016/07/11 21:27:52 I know Android's code uses match as a var name for
Ben Kwa 2016/07/11 22:34:01 Done.
+ if (match.length() == 0) {
+ return false;
+ }
+ switch (match_type_) {
+ case mojom::PatternType::PATTERN_LITERAL:
+ return pattern_.compare(match) == 0;
rickyz (no longer on Chrome) 2016/07/11 21:27:52 Perhaps pattern_ == match might read a little easi
Ben Kwa 2016/07/11 22:34:02 Done.
+ case mojom::PatternType::PATTERN_PREFIX:
+ return pattern_.compare(0, match.length(), match);
rickyz (no longer on Chrome) 2016/07/11 21:27:52 Should this be == 0? Or better yet, base::StartsWi
Ben Kwa 2016/07/11 22:34:01 Done.
rickyz (no longer on Chrome) 2016/07/11 23:26:44 I'd still like to see some Chrome side tests for t
Ben Kwa 2016/07/12 16:05:22 Oops, sorry. Will add tests in a follow-up.
+ case mojom::PatternType::PATTERN_SIMPLE_GLOB:
+ return matchGlob(match);
+ }
+
+ return false;
+}
+
+bool IntentFilter::PatternMatcher::matchGlob(
rickyz (no longer on Chrome) 2016/07/09 02:13:34 This should have a comment saying that it was tran
Ben Kwa 2016/07/11 21:22:58 I've added a comments noting the origins of this a
+ const std::string& match) const {
+ const size_t NP = pattern_.length();
+ const size_t NM = match.length();
+ if (NP == 0) {
+ return NM == 0;
+ }
+ size_t ip = 0, im = 0;
+ char nextChar = pattern_[0];
Yusuke Sato 2016/07/11 04:38:32 What about explicitly checking all the string acce
Ben Kwa 2016/07/11 21:22:58 Done.
+ while (ip < NP && im < NM) {
+ char c = nextChar;
+ ++ip;
+ nextChar = ip < NP ? pattern_[ip] : 0;
+ const bool escaped = (c == '\\');
+ if (escaped) {
+ c = nextChar;
+ ++ip;
+ nextChar = ip < NP ? pattern_[ip] : 0;
+ }
+ if (nextChar == '*') {
+ if (!escaped && c == '.') {
+ if (ip >= (NP-1)) {
+ // At the end with a pattern match
+ return true;
+ }
+ ++ip;
+ nextChar = pattern_[ip];
+ // Consume everything until the next char in the pattern is found.
+ if (nextChar == '\\') {
+ ++ip;
+ nextChar = ip < NP ? pattern_[ip] : 0;
+ }
+ do {
+ if (match[im] == nextChar) {
+ break;
+ }
+ ++im;
+ } while (im < NM);
+ if (im == NM) {
+ // Next char in the pattern didn't exist in the match.
+ return false;
+ }
+ ++ip;
+ nextChar = ip < NP ? pattern_[ip] : 0;
+ ++im;
+ } else {
+ // Consume only characters matching the one before '*'.
+ do {
+ if (match[im] != c) {
+ break;
+ }
+ ++im;
+ } while (im < NM);
+ ++ip;
+ nextChar = ip < NP ? pattern_[ip] : 0;
+ }
+ } else {
+ if (c != '.' && match[im] != c) return false;
+ ++im;
+ }
+ }
+
+ if (ip >= NP && im >= NM) {
+ // Reached the end of both strings
+ return true;
+ }
+
+ // One last check: we may have finished the match string, but still have a
+ // '.*' at the end of the pattern, which is still a match.
+ if (ip == NP-2 &&
+ pattern_[ip] == '.' &&
+ pattern_[ip+1] == '*') {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698