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