Commit 466ef2d5 authored by Peter K. Lee's avatar Peter K. Lee Committed by Commit Bot

Handles mailto: URLs with equal sign in body= parameter

Original method expects only a single equal sign in each
query parameter and that the query string is only in lower
case. However, body may contain a URL with may have an
unescaped equal sign. And query string keys may be in mixed
case.

As part of this fix, also removed -supportedHeaders from
public API and use GURL for query parameter processing.

Bug: 747949
Change-Id: Ia157983e946d7301300d22f41e007bd10ce8b786
Reviewed-on: https://chromium-review.googlesource.com/594873
Commit-Queue: Peter Lee <pkl@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491280}
parent b3fdb534
...@@ -31,9 +31,6 @@ class GURL; ...@@ -31,9 +31,6 @@ class GURL;
// URL scheme plus some operator prefix. Subclasses should override this method. // URL scheme plus some operator prefix. Subclasses should override this method.
- (NSString*)beginningScheme; - (NSString*)beginningScheme;
// Returns a set of NSString for mailto: parameters supported by this handler.
- (NSSet<NSString*>*)supportedHeaders;
// Rewrites |gURL| into a URL with a different URL scheme that will cause a // Rewrites |gURL| into a URL with a different URL scheme that will cause a
// native iOS app to be launched to handle the mailto: URL. Returns nil if // native iOS app to be launched to handle the mailto: URL. Returns nil if
// |gURL| is not a mailto: URL. Base class implementation provides the typical // |gURL| is not a mailto: URL. Base class implementation provides the typical
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#import "ios/chrome/browser/web/mailto_handler.h" #import "ios/chrome/browser/web/mailto_handler.h"
#include <set>
#include "base/strings/string_util.h"
#import "base/strings/sys_string_conversions.h" #import "base/strings/sys_string_conversions.h"
#include "net/base/url_util.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/url_constants.h" #include "url/url_constants.h"
...@@ -14,7 +18,27 @@ ...@@ -14,7 +18,27 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@implementation MailtoHandler namespace {
// Convenience function to add key with unescaped value to input URL.
GURL AppendQueryParameter(const GURL& input,
const std::string& key,
const std::string& value) {
std::string query(input.query());
if (!query.empty())
query += "&";
query += key + "=" + value;
GURL::Replacements replacements;
replacements.SetQueryStr(query);
return input.ReplaceComponents(replacements);
}
} // namespace
@implementation MailtoHandler {
std::set<std::string> _supportedHeaders;
}
@synthesize appName = _appName; @synthesize appName = _appName;
@synthesize appStoreID = _appStoreID; @synthesize appStoreID = _appStoreID;
...@@ -24,6 +48,9 @@ ...@@ -24,6 +48,9 @@
if (self) { if (self) {
_appName = [appName copy]; _appName = [appName copy];
_appStoreID = [appStoreID copy]; _appStoreID = [appStoreID copy];
// List of typical query parameter keys acceptable to mailto: URLs.
_supportedHeaders =
std::set<std::string>({"to", "cc", "bcc", "subject", "body"});
} }
return self; return self;
} }
...@@ -40,29 +67,22 @@ ...@@ -40,29 +67,22 @@
return @"mailtohandler:/co?"; return @"mailtohandler:/co?";
} }
- (NSSet<NSString*>*)supportedHeaders {
return [NSSet<NSString*>
setWithObjects:@"to", @"cc", @"bcc", @"subject", @"body", nil];
}
- (NSString*)rewriteMailtoURL:(const GURL&)gURL { - (NSString*)rewriteMailtoURL:(const GURL&)gURL {
if (!gURL.SchemeIs(url::kMailToScheme)) if (!gURL.SchemeIs(url::kMailToScheme))
return nil; return nil;
NSMutableArray* outParams = [NSMutableArray array]; GURL result(base::SysNSStringToUTF8([self beginningScheme]));
NSString* recipient = base::SysUTF8ToNSString(gURL.path()); if (gURL.path().length())
if ([recipient length]) { result = AppendQueryParameter(result, "to", gURL.path());
[outParams addObject:[NSString stringWithFormat:@"to=%@", recipient]]; net::QueryIterator it(gURL);
} while (!it.IsAtEnd()) {
NSString* query = base::SysUTF8ToNSString(gURL.query()); // Normalizes the keys to all lowercase, but keeps the value unchanged.
for (NSString* keyvalue : [query componentsSeparatedByString:@"&"]) { std::string key = base::ToLowerASCII(it.GetKey());
NSArray* pair = [keyvalue componentsSeparatedByString:@"="]; if (_supportedHeaders.find(key) != _supportedHeaders.end()) {
if ([pair count] != 2U || ![[self supportedHeaders] containsObject:pair[0]]) result = AppendQueryParameter(result, key, it.GetValue());
continue; }
[outParams it.Advance();
addObject:[NSString stringWithFormat:@"%@=%@", pair[0], pair[1]]];
} }
return [NSString stringWithFormat:@"%@%@", [self beginningScheme], return base::SysUTF8ToNSString(result.spec());
[outParams componentsJoinedByString:@"&"]];
} }
@end @end
...@@ -8,38 +8,60 @@ ...@@ -8,38 +8,60 @@
#include "testing/gtest_mac.h" #include "testing/gtest_mac.h"
#include "url/gurl.h" #include "url/gurl.h"
// Tests constructor.
TEST(MailtoHandlerTest, TestConstructor) { TEST(MailtoHandlerTest, TestConstructor) {
MailtoHandler* handler = MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"]; [[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
EXPECT_NSEQ(@"Some App", [handler appName]); EXPECT_NSEQ(@"Some App", [handler appName]);
EXPECT_NSEQ(@"12345", [handler appStoreID]); EXPECT_NSEQ(@"12345", [handler appStoreID]);
EXPECT_NSEQ(@"mailtohandler:/co?", [handler beginningScheme]); EXPECT_NSEQ(@"mailtohandler:/co?", [handler beginningScheme]);
EXPECT_GT([[handler supportedHeaders] count], 0U);
} }
// Tests mailto URL with and without a subject.
TEST(MailtoHandlerTest, TestRewriteGood) { TEST(MailtoHandlerTest, TestRewriteGood) {
MailtoHandler* handler = [[MailtoHandler alloc] init]; MailtoHandler* handler =
// Tests mailto URL without a subject. [[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result = [handler rewriteMailtoURL:GURL("mailto:user@domain.com")]; NSString* result = [handler rewriteMailtoURL:GURL("mailto:user@domain.com")];
EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com", result); EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com", result);
// Tests mailto URL with a subject. // Tests mailto URL with a subject.
result = result =
[handler rewriteMailtoURL:GURL("mailto:user@domain.com?subject=hello")]; [handler rewriteMailtoURL:GURL("mailto:user@domain.com?subject=hello")];
EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com&subject=hello", result); EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com&subject=hello", result);
// Tests mailto URL with unrecognized query parameters. }
result = [handler
// Tests mailto URL with unrecognized query parameters.
TEST(MailtoHandlerTest, TestRewriteUnrecognizedParams) {
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result = [handler
rewriteMailtoURL: rewriteMailtoURL:
GURL("mailto:someone@there.com?garbage=in&garbageOut&subject=trash")]; GURL("mailto:someone@there.com?garbage=in&garbageOut&subject=trash")];
EXPECT_NSEQ(@"mailtohandler:/co?to=someone@there.com&subject=trash", result); EXPECT_NSEQ(@"mailtohandler:/co?to=someone@there.com&subject=trash", result);
} }
TEST(MailtoHandlerTest, TestRewriteBad) { // Tests mailto URL with a body that includes a = sign.
MailtoHandler* handler = [[MailtoHandler alloc] init]; TEST(MailtoHandlerTest, TestRewriteBodyWithUrl) {
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result = [handler
rewriteMailtoURL:GURL("mailto:user@domain.com?body=http://foo.bar?x=y")];
EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com&body=http://foo.bar?x=y",
result);
}
// Tests mailto URL with parameters that are mixed upper/lower cases.
TEST(MailtoHandlerTest, TestRewriteWithMixedCase) {
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result =
[handler rewriteMailtoURL:GURL("mailto:?Subject=Blah&BODY=stuff")];
EXPECT_NSEQ(@"mailtohandler:/co?subject=Blah&body=stuff", result);
}
// Tests that non-mailto URLs returns nil.
TEST(MailtoHandlerTest, TestRewriteNotMailto) {
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result = [handler rewriteMailtoURL:GURL("http://www.google.com")]; NSString* result = [handler rewriteMailtoURL:GURL("http://www.google.com")];
EXPECT_FALSE(result); EXPECT_FALSE(result);
result = [handler
rewriteMailtoURL:
GURL("mailto:user@domain.com?foo=bar&cc=someone@somewhere.com")];
EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com&cc=someone@somewhere.com",
result);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment