redirector.py revision f2477e01787aa58f445919b809d89e252beef54f
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import posixpath
6from urlparse import urlsplit
7
8from file_system import FileNotFoundError
9from future import Gettable, Future
10
11class Redirector(object):
12  def __init__(self, compiled_fs_factory, file_system):
13    self._file_system = file_system
14    self._cache = compiled_fs_factory.ForJson(file_system)
15
16  def Redirect(self, host, path):
17    ''' Check if a path should be redirected, first according to host
18    redirection rules, then from rules in redirects.json files.
19
20    Returns the path that should be redirected to, or None if no redirection
21    should occur.
22    '''
23    return self._RedirectOldHosts(host, path) or self._RedirectFromConfig(path)
24
25  def _RedirectFromConfig(self, url):
26    ''' Lookup the redirects configuration file in the directory that contains
27    the requested resource. If no redirection rule is matched, or no
28    configuration file exists, returns None.
29    '''
30    dirname, filename = posixpath.split(url)
31
32    try:
33      rules = self._cache.GetFromFile(
34          posixpath.join(dirname, 'redirects.json')).Get()
35    except FileNotFoundError:
36      return None
37
38    redirect = rules.get(filename)
39    if redirect is None:
40      return None
41    if (redirect.startswith('/') or
42        urlsplit(redirect).scheme in ('http', 'https')):
43      return redirect
44
45    return posixpath.normpath(posixpath.join('/', dirname, redirect))
46
47  def _RedirectOldHosts(self, host, path):
48    ''' Redirect paths from the old code.google.com to the new
49    developer.chrome.com, retaining elements like the channel and https, if
50    used.
51    '''
52    if urlsplit(host).hostname != 'code.google.com':
53      return None
54
55    path = path.split('/')
56    if path and path[0] == 'chrome':
57      path.pop(0)
58
59    return 'https://developer.chrome.com/' + posixpath.join(*path)
60
61  def Cron(self):
62    ''' Load files during a cron run.
63    '''
64    futures = []
65    for root, dirs, files in self._file_system.Walk(''):
66      if 'redirects.json' in files:
67        futures.append(
68            self._cache.GetFromFile(posixpath.join(root, 'redirects.json')))
69    return Future(delegate=Gettable(lambda: [f.Get() for f in futures]))
70