redirector.py revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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 branch_utility import BranchUtility
9from file_system import FileNotFoundError
10from third_party.json_schema_compiler.json_parse import Parse
11
12class Redirector(object):
13  def __init__(self, compiled_fs_factory, file_system, root_path):
14    self._root_path = root_path
15    self._file_system = file_system
16    self._cache = compiled_fs_factory.Create(
17      lambda _, rules: Parse(rules), Redirector)
18
19  def Redirect(self, host, path):
20    ''' Check if a path should be redirected, first according to host
21    redirection rules, then from rules in redirects.json files.
22
23    Returns the path that should be redirected to, or None if no redirection
24    should occur.
25    '''
26    return self._RedirectOldHosts(host, path) or self._RedirectFromConfig(path)
27
28  def _RedirectFromConfig(self, url):
29    ''' Lookup the redirects configuration file in the directory that contains
30    the requested resource. If no redirection rule is matched, or no
31    configuration file exists, returns None.
32    '''
33    dirname, filename = posixpath.split(url)
34
35    try:
36      rules = self._cache.GetFromFile(
37          posixpath.join(self._root_path, dirname, 'redirects.json'))
38    except FileNotFoundError:
39      return None
40
41    redirect = rules.get(filename)
42    if redirect is None:
43      return None
44    if (redirect.startswith('/') or
45        urlsplit(redirect).scheme in ('http', 'https')):
46      return redirect
47
48    return posixpath.normpath('/' + posixpath.join(dirname, redirect))
49
50  def _RedirectOldHosts(self, host, path):
51    ''' Redirect paths from the old code.google.com to the new
52    developer.chrome.com, retaining elements like the channel and https, if
53    used.
54    '''
55    if urlsplit(host).hostname != 'code.google.com':
56      return None
57
58    path = path.split('/')
59    if path and path[0] == 'chrome':
60      path.pop(0)
61
62    for channel in BranchUtility.GetAllChannelNames():
63      if channel in path:
64        path.remove(channel)
65        path.insert(0, channel)
66        break
67
68    return 'https://developer.chrome.com/' + posixpath.join(*path)
69
70  def Cron(self):
71    ''' Load files during a cron run.
72    '''
73    for root, dirs, files in self._file_system.Walk(self._root_path + '/'):
74      if 'redirects.json' in files:
75        self._cache.GetFromFile('%s/redirects.json' % posixpath.join(
76            self._root_path, root))
77