diff --git a/r2/r2/config/middleware.py b/r2/r2/config/middleware.py index 4b5a210b5..0a42a77fe 100644 --- a/r2/r2/config/middleware.py +++ b/r2/r2/config/middleware.py @@ -32,6 +32,7 @@ from paste.cascade import Cascade from paste.registry import RegistryManager from paste.urlparser import StaticURLParser from paste.deploy.converters import asbool +from paste.request import path_info_split from pylons import config, response from pylons.middleware import ErrorDocuments, ErrorHandler from pylons.wsgiapp import PylonsApp @@ -222,18 +223,17 @@ class SubredditMiddleware(object): return self.app(environ, start_response) class DomainListingMiddleware(object): - domain_pattern = re.compile(r'\A/domain/(([-\w]+\.)+[\w]+)') - def __init__(self, app): self.app = app def __call__(self, environ, start_response): if not environ.has_key('subreddit'): path = environ['PATH_INFO'] - domain = self.domain_pattern.match(path) - if domain: - environ['domain'] = domain.groups()[0] - environ['PATH_INFO'] = self.domain_pattern.sub('', path) or '/' + domain, rest = path_info_split(path) + if domain == "domain" and rest: + domain, rest = path_info_split(rest) + environ['domain'] = domain + environ['PATH_INFO'] = rest or '/' return self.app(environ, start_response) class ExtensionMiddleware(object): diff --git a/r2/r2/controllers/reddit_base.py b/r2/r2/controllers/reddit_base.py index 5f7faa920..b2ac59c97 100644 --- a/r2/r2/controllers/reddit_base.py +++ b/r2/r2/controllers/reddit_base.py @@ -55,7 +55,7 @@ from r2.lib.errors import ( errors, reddit_http_error, ) -from r2.lib.filters import _force_utf8 +from r2.lib.filters import _force_utf8, _force_unicode from r2.lib.strings import strings from r2.lib.template_helpers import add_sr, JSPreload from r2.lib.tracking import encrypt, decrypt @@ -331,6 +331,7 @@ def set_obey_over18(): "querystring parameter for API to obey over18 filtering rules" c.obey_over18 = request.GET.get("obey_over18") == "true" +valid_ascii_domain = re.compile(r'\A(\w[-\w]*\.)+[\w]+\Z') def set_subreddit(): #the r parameter gets added by javascript for POST requests so we #can reference c.site in api.py @@ -390,6 +391,12 @@ def set_subreddit(): #if we didn't find a subreddit, check for a domain listing if not sr_name and isinstance(c.site, DefaultSR) and domain: + # Redirect IDN to their IDNA name if necessary + idna = _force_unicode(domain).encode("idna") + if idna != domain: + redirect_to("/domain/%s%s" % (idna, request.environ["PATH_INFO"])) + if not c.error_page and not valid_ascii_domain.match(domain): + abort(404) c.site = DomainSR(domain) if isinstance(c.site, FakeSubreddit): diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index 4c85d7da0..2c000c8d5 100644 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -610,7 +610,10 @@ class Reddit(Templated): toolbar.append(NavMenu(more_buttons, title=menu.more, type='tabdrop')) if not isinstance(c.site, DefaultSR) and not c.cname: - toolbar.insert(0, PageNameNav('subreddit')) + func = 'subreddit' + if isinstance(c.site, DomainSR): + func = 'domain' + toolbar.insert(0, PageNameNav(func)) return toolbar diff --git a/r2/r2/models/subreddit.py b/r2/r2/models/subreddit.py index 707fe31ca..0e72cf901 100644 --- a/r2/r2/models/subreddit.py +++ b/r2/r2/models/subreddit.py @@ -1562,6 +1562,9 @@ class DomainSR(FakeSubreddit): self.domain = domain self.name = domain self.title = domain + ' ' + _('on reddit.com') + idn = domain.decode('idna') + if idn != domain: + self.idn = idn def get_links(self, sort, time): from r2.lib.db import queries diff --git a/r2/r2/public/static/css/reddit.less b/r2/r2/public/static/css/reddit.less index 2c4194718..34e1774f5 100755 --- a/r2/r2/public/static/css/reddit.less +++ b/r2/r2/public/static/css/reddit.less @@ -3950,6 +3950,18 @@ ul#image-preview-list .description pre { #sr-searchfield { margin: 0 5px; } +#sr-name-box { + display: inline-block; + span { + display: block; + unicode-bidi: isolate; + } + .tooltip { + border-bottom: 1px dotted; + margin-bottom: 2px; + } +} + .sr-name { font-size: small; vertical-align: top; diff --git a/r2/r2/templates/pagenamenav.compact b/r2/r2/templates/pagenamenav.compact index 62240e4d7..5671953ae 100644 --- a/r2/r2/templates/pagenamenav.compact +++ b/r2/r2/templates/pagenamenav.compact @@ -22,6 +22,12 @@ <%namespace file="utils.html" import="plain_link"/> +<%def name="domain()"> + + ${plain_link(c.site.name, c.site.path, _sr_path=False)} + + + <%def name="subreddit()"> ${plain_link(c.site.name, c.site.path, _sr_path=False)} diff --git a/r2/r2/templates/pagenamenav.html b/r2/r2/templates/pagenamenav.html index 8429ca408..c15e7ee2c 100644 --- a/r2/r2/templates/pagenamenav.html +++ b/r2/r2/templates/pagenamenav.html @@ -20,7 +20,7 @@ ## reddit Inc. All Rights Reserved. ############################################################################### -<%namespace file="utils.html" import="plain_link"/> +<%namespace file="utils.html" import="plain_link, _md"/> <%def name="subreddit()"> @@ -31,6 +31,29 @@ +<%def name="domain()"> +
+ + ${plain_link(getattr(c.site, "idn", c.site.name), c.site.path, _sr_path=False)} + % if hasattr(thing, "title"): + : ${thing.title} + % endif + + % if hasattr(c.site, "idn"): + + ${c.site.name} +
+
+

+ ${_md("This is an [internationalized domain name](http://en.wikipedia.org/wiki/Internationalized_domain_name). We've modified how it is displayed [for security reasons](http://en.wikipedia.org/wiki/IDN_homograph_attack).")} +

+
+
+
+ % endif +
+ + <%def name="subreddits()"> ${plain_link(_("subreddits"), "/subreddits/", _sr_path=False)} diff --git a/r2/r2/templates/pagenamenav.mobile b/r2/r2/templates/pagenamenav.mobile index a7f91a4a5..f88557053 100644 --- a/r2/r2/templates/pagenamenav.mobile +++ b/r2/r2/templates/pagenamenav.mobile @@ -20,6 +20,12 @@ ## reddit Inc. All Rights Reserved. ############################################################################### +<%def name="domain()"> + + ${c.site.name} + + + <%def name="subreddit()"> ${c.site.name}