Skip to content
This repository
Browse code

Turn CNAMEs into a simple redirect.

  • Loading branch information...
commit 7118bde4725f364b7ccbfd05628aa760c3dcb9b8 1 parent d0102d6
Neil Williams authored June 27, 2012
2  r2/example.ini
@@ -72,6 +72,8 @@ domain = reddit.local
72 72
 shortdomain =
73 73
 # if you use www for the old-timey feel, put it here
74 74
 domain_prefix = 
  75
+# subdomains that don't need special processing
  76
+reserved_subdomains = www, ssl
75 77
 # the user used for "system" operations and messages
76 78
 system_user = reddit
77 79
 # list of admin accounts
100  r2/r2/config/middleware.py
@@ -39,7 +39,7 @@
39 39
 from r2.config.environment import load_environment
40 40
 from r2.config.rewrites import rewrites
41 41
 from r2.config.extensions import extension_mapping, set_extension
42  
-from r2.lib.utils import is_authorized_cname
  42
+from r2.lib.utils import is_subdomain
43 43
 
44 44
 
45 45
 # hack in Paste support for HTTP 429 "Too Many Requests"
@@ -134,76 +134,60 @@ class DomainMiddleware(object):
134 134
 
135 135
     def __init__(self, app):
136 136
         self.app = app
137  
-        auth_cnames = config['global_conf'].get('authorized_cnames', '')
138  
-        auth_cnames = [x.strip() for x in auth_cnames.split(',')]
139  
-        # we are going to be matching with endswith, so make sure there
140  
-        # are no empty strings that have snuck in
141  
-        self.auth_cnames = filter(None, auth_cnames)
142  
-
143  
-    def is_auth_cname(self, domain):
144  
-        return is_authorized_cname(domain, self.auth_cnames)
145 137
 
146 138
     def __call__(self, environ, start_response):
147  
-        # get base domain as defined in INI file
148  
-        base_domain = config['global_conf']['domain']
  139
+        g = config['pylons.g']
  140
+        http_host = environ.get('HTTP_HOST', 'localhost').lower()
  141
+        domain, s, port = http_host.partition(':')
  142
+
  143
+        # remember the port
149 144
         try:
150  
-            sub_domains, request_port  = environ['HTTP_HOST'].split(':')
151  
-            environ['request_port'] = int(request_port)
  145
+            environ['request_port'] = int(port)
152 146
         except ValueError:
153  
-            sub_domains = environ['HTTP_HOST'].split(':')[0]
154  
-        except KeyError:
155  
-            sub_domains = "localhost"
156  
-
157  
-        #If the domain doesn't end with base_domain, assume
158  
-        #this is a cname, and redirect to the frame controller.
159  
-        #Ignore localhost so paster shell still works.
160  
-        #If this is an error, don't redirect
161  
-        if (not sub_domains.endswith(base_domain)
162  
-            and (not sub_domains == 'localhost')):
163  
-            environ['sub_domain'] = sub_domains
164  
-            if not environ.get('extension'):
165  
-                if environ['PATH_INFO'].startswith('/frame'):
166  
-                    return self.app(environ, start_response)
167  
-                elif self.is_auth_cname(sub_domains):
168  
-                    environ['frameless_cname'] = True
169  
-                    environ['authorized_cname'] = True
170  
-                elif ("redditSession=cname" in environ.get('HTTP_COOKIE', '')
171  
-                      and environ['REQUEST_METHOD'] != 'POST'
172  
-                      and not environ['PATH_INFO'].startswith('/error')):
173  
-                    environ['original_path'] = environ['PATH_INFO']
174  
-                    environ['FULLPATH'] = environ['PATH_INFO'] = '/frame'
175  
-                else:
176  
-                    environ['frameless_cname'] = True
  147
+            pass
  148
+
  149
+        # localhost is exempt so paster run/shell will work
  150
+        # media_domain doesn't need special processing since it's just ads
  151
+        if domain == "localhost" or is_subdomain(domain, g.media_domain):
177 152
             return self.app(environ, start_response)
178 153
 
179  
-        sub_domains = sub_domains[:-len(base_domain)].strip('.')
180  
-        sub_domains = sub_domains.split('.')
  154
+        # tell reddit_base to redirect to the appropriate subreddit for
  155
+        # a legacy CNAME
  156
+        if not is_subdomain(domain, g.domain):
  157
+            environ['legacy-cname'] = domain
  158
+            return self.app(environ, start_response)
  159
+
  160
+        # figure out what subdomain we're on if any
  161
+        subdomains = domain[:-len(g.domain) - 1].split('.')
  162
+        extension_subdomains = dict(m="mobile",
  163
+                                    i="compact",
  164
+                                    api="api",
  165
+                                    rss="rss",
  166
+                                    xml="xml",
  167
+                                    json="json")
181 168
 
182 169
         sr_redirect = None
183  
-        for sd in list(sub_domains):
184  
-            # subdomains to disregard completely
185  
-            if sd in ('www', 'origin', 'beta', 'lab', 'pay', 'buttons', 'ssl'):
  170
+        for subdomain in subdomains[:]:
  171
+            if subdomain in g.reserved_subdomains:
186 172
                 continue
187  
-            # subdomains which change the extension
188  
-            elif sd == 'm':
189  
-                environ['reddit-domain-extension'] = 'mobile'
190  
-            elif sd == 'I':
191  
-                environ['reddit-domain-extension'] = 'compact'
192  
-            elif sd == 'i':
193  
-                environ['reddit-domain-extension'] = 'compact'
194  
-            elif sd in ('api', 'rss', 'xml', 'json'):
195  
-                environ['reddit-domain-extension'] = sd
196  
-            elif (len(sd) == 2 or (len(sd) == 5 and sd[2] == '-')) and self.lang_re.match(sd):
197  
-                environ['reddit-prefer-lang'] = sd
198  
-                environ['reddit-domain-prefix'] = sd
  173
+
  174
+            extension = extension_subdomains.get(subdomain)
  175
+            if extension:
  176
+                environ['reddit-domain-extension'] = extension
  177
+            elif self.lang_re.match(subdomain):
  178
+                environ['reddit-prefer-lang'] = subdomain
  179
+                environ['reddit-domain-prefix'] = subdomain
199 180
             else:
200  
-                sr_redirect = sd
201  
-                sub_domains.remove(sd)
  181
+                sr_redirect = subdomain
  182
+                subdomains.remove(subdomain)
202 183
 
  184
+        # if there was a subreddit subdomain, redirect
203 185
         if sr_redirect and environ.get("FULLPATH"):
204 186
             r = Response()
205  
-            sub_domains.append(base_domain)
206  
-            redir = "%s/r/%s/%s" % ('.'.join(sub_domains),
  187
+            if not subdomains and g.domain_prefix:
  188
+                subdomains.append(g.domain_prefix)
  189
+            subdomains.append(g.domain)
  190
+            redir = "%s/r/%s/%s" % ('.'.join(subdomains),
207 191
                                     sr_redirect, environ['FULLPATH'])
208 192
             redir = "http://" + redir.replace('//', '/')
209 193
             r.status_code = 301
4  r2/r2/controllers/error.py
@@ -24,7 +24,7 @@
24 24
 
25 25
 import pylons
26 26
 import paste.fileapp
27  
-from paste.httpexceptions import HTTPFound
  27
+from paste.httpexceptions import HTTPFound, HTTPMovedPermanently
28 28
 from pylons.middleware import error_document_template, media_path
29 29
 from pylons import c, request, g
30 30
 from pylons.i18n import _
@@ -89,7 +89,7 @@ def __before__(self):
89 89
         try:
90 90
             c.error_page = True
91 91
             RedditController.__before__(self)
92  
-        except HTTPFound:
  92
+        except (HTTPMovedPermanently, HTTPFound):
93 93
             # ignore an attempt to redirect from an error page
94 94
             pass
95 95
         except:
10  r2/r2/controllers/reddit_base.py
@@ -262,9 +262,13 @@ def set_subreddit():
262 262
     c.site = Frontpage
263 263
     if not sr_name:
264 264
         #check for cnames
265  
-        sub_domain = request.environ.get('sub_domain')
266  
-        if sub_domain and not sub_domain.endswith(g.media_domain):
267  
-            c.site = Subreddit._by_domain(sub_domain) or Frontpage
  265
+        cname = request.environ.get('legacy-cname')
  266
+        if cname:
  267
+            sr = Subreddit._by_domain(cname) or Frontpage
  268
+            domain = g.domain
  269
+            if g.domain_prefix:
  270
+                domain = ".".join((g.domain_prefix, domain))
  271
+            redirect_to('http://%s%s' % (domain, sr.path), _code=301)
268 272
     elif sr_name == 'r':
269 273
         #reddits
270 274
         c.site = Sub
1  r2/r2/lib/app_globals.py
@@ -136,6 +136,7 @@ class Globals(object):
136 136
             's3_media_buckets',
137 137
             'allowed_pay_countries',
138 138
             'case_sensitive_domains',
  139
+            'reserved_subdomains',
139 140
         ],
140 141
 
141 142
         ConfigValue.choice: {
4  r2/r2/lib/utils/utils.py
@@ -55,9 +55,6 @@ def randstr(len, reallyrandom = False):
55 55
     return ''.join(random.choice(alphabet)
56 56
                    for i in range(len))
57 57
 
58  
-def is_authorized_cname(domain, cnames):
59  
-    return any(is_subdomain(domain, cname) for cname in cnames)
60  
-
61 58
 class Storage(dict):
62 59
     """
63 60
     A Storage object is like a dictionary except `obj.foo` can be used
@@ -533,7 +530,6 @@ def is_reddit_url(self, subreddit = None):
533 530
         from pylons import g
534 531
         return (not self.hostname or
535 532
                 is_subdomain(self.hostname, g.domain) or
536  
-                is_authorized_cname(self.hostname, g.authorized_cnames) or
537 533
                 (subreddit and subreddit.domain and
538 534
                  is_subdomain(self.hostname, subreddit.domain)))
539 535
 

0 notes on commit 7118bde

Please sign in to comment.
Something went wrong with that request. Please try again.