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;
// URL scheme plus some operator prefix. Subclasses should override this method.
- (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
// 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
......
......@@ -4,7 +4,11 @@
#import "ios/chrome/browser/web/mailto_handler.h"
#include <set>
#include "base/strings/string_util.h"
#import "base/strings/sys_string_conversions.h"
#include "net/base/url_util.h"
#include "url/gurl.h"
#include "url/url_constants.h"
......@@ -14,7 +18,27 @@
#error "This file requires ARC support."
#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 appStoreID = _appStoreID;
......@@ -24,6 +48,9 @@
if (self) {
_appName = [appName 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;
}
......@@ -40,29 +67,22 @@
return @"mailtohandler:/co?";
}
- (NSSet<NSString*>*)supportedHeaders {
return [NSSet<NSString*>
setWithObjects:@"to", @"cc", @"bcc", @"subject", @"body", nil];
}
- (NSString*)rewriteMailtoURL:(const GURL&)gURL {
if (!gURL.SchemeIs(url::kMailToScheme))
return nil;
NSMutableArray* outParams = [NSMutableArray array];
NSString* recipient = base::SysUTF8ToNSString(gURL.path());
if ([recipient length]) {
[outParams addObject:[NSString stringWithFormat:@"to=%@", recipient]];
}
NSString* query = base::SysUTF8ToNSString(gURL.query());
for (NSString* keyvalue : [query componentsSeparatedByString:@"&"]) {
NSArray* pair = [keyvalue componentsSeparatedByString:@"="];
if ([pair count] != 2U || ![[self supportedHeaders] containsObject:pair[0]])
continue;
[outParams
addObject:[NSString stringWithFormat:@"%@=%@", pair[0], pair[1]]];
GURL result(base::SysNSStringToUTF8([self beginningScheme]));
if (gURL.path().length())
result = AppendQueryParameter(result, "to", gURL.path());
net::QueryIterator it(gURL);
while (!it.IsAtEnd()) {
// Normalizes the keys to all lowercase, but keeps the value unchanged.
std::string key = base::ToLowerASCII(it.GetKey());
if (_supportedHeaders.find(key) != _supportedHeaders.end()) {
result = AppendQueryParameter(result, key, it.GetValue());
}
it.Advance();
}
return [NSString stringWithFormat:@"%@%@", [self beginningScheme],
[outParams componentsJoinedByString:@"&"]];
return base::SysUTF8ToNSString(result.spec());
}
@end
......@@ -8,38 +8,60 @@
#include "testing/gtest_mac.h"
#include "url/gurl.h"
// Tests constructor.
TEST(MailtoHandlerTest, TestConstructor) {
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
EXPECT_NSEQ(@"Some App", [handler appName]);
EXPECT_NSEQ(@"12345", [handler appStoreID]);
EXPECT_NSEQ(@"mailtohandler:/co?", [handler beginningScheme]);
EXPECT_GT([[handler supportedHeaders] count], 0U);
}
// Tests mailto URL with and without a subject.
TEST(MailtoHandlerTest, TestRewriteGood) {
MailtoHandler* handler = [[MailtoHandler alloc] init];
// Tests mailto URL without a subject.
MailtoHandler* handler =
[[MailtoHandler alloc] initWithName:@"Some App" appStoreID:@"12345"];
NSString* result = [handler rewriteMailtoURL:GURL("mailto:user@domain.com")];
EXPECT_NSEQ(@"mailtohandler:/co?to=user@domain.com", result);
// Tests mailto URL with a subject.
result =
[handler rewriteMailtoURL:GURL("mailto:user@domain.com?subject=hello")];
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:
GURL("mailto:someone@there.com?garbage=in&garbageOut&subject=trash")];
EXPECT_NSEQ(@"mailtohandler:/co?to=someone@there.com&subject=trash", result);
}
TEST(MailtoHandlerTest, TestRewriteBad) {
MailtoHandler* handler = [[MailtoHandler alloc] init];
// Tests mailto URL with a body that includes a = sign.
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")];
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