Home | History | Annotate | Download | only in server2
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 # This helps you preview the apps and extensions docs.
      7 #
      8 #    ./preview.py --help
      9 #
     10 # There are two modes: server- and render- mode. The default is server, in which
     11 # a webserver is started on a port (default 8000). Navigating to paths on
     12 # http://localhost:8000, for example
     13 #
     14 #     http://localhost:8000/extensions/tabs.html
     15 #
     16 # will render the documentation for the extension tabs API.
     17 #
     18 # On the other hand, render mode statically renders docs to stdout. Use this
     19 # to save the output (more convenient than needing to save the page in a
     20 # browser), handy when uploading the docs somewhere (e.g. for a review),
     21 # and for profiling the server. For example,
     22 #
     23 #    ./preview.py -r extensions/tabs.html
     24 #
     25 # will output the documentation for the tabs API on stdout and exit immediately.
     26 
     27 # NOTE: RUN THIS FIRST. Or all third_party imports will fail.
     28 import build_server
     29 # Copy all the files necessary to run the server. These are cleaned up when the
     30 # server quits.
     31 build_server.main()
     32 
     33 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
     34 import logging
     35 import optparse
     36 import posixpath
     37 import time
     38 
     39 from local_renderer import LocalRenderer
     40 
     41 class _RequestHandler(BaseHTTPRequestHandler):
     42   '''A HTTPRequestHandler that outputs the docs page generated by Handler.
     43   '''
     44   def do_GET(self):
     45     # Sanitize path to guarantee that it stays within the server.
     46     if not posixpath.abspath(self.path.lstrip('/')).startswith(
     47                              posixpath.abspath('')):
     48       return
     49 
     50     # Rewrite paths that would otherwise be served from app.yaml.
     51     self.path = {
     52       '/robots.txt': '../../server2/robots.txt',
     53       '/favicon.ico': '../../server2/chrome-32.ico',
     54       '/apple-touch-icon-precomposed.png': '../../server2/chrome-128.png'
     55     }.get(self.path, self.path)
     56     response = LocalRenderer.Render(self.path, headers=dict(self.headers))
     57     self.protocol_version = 'HTTP/1.1'
     58     self.send_response(response.status)
     59     for k, v in response.headers.iteritems():
     60       self.send_header(k, v)
     61     self.end_headers()
     62     self.wfile.write(response.content.ToString())
     63 
     64 if __name__ == '__main__':
     65   parser = optparse.OptionParser(
     66       description='Runs a server to preview the extension documentation.',
     67       usage='usage: %prog [option]...')
     68   parser.add_option('-p', '--port', default='8000',
     69       help='port to run the server on')
     70   parser.add_option('-r', '--render', default='',
     71       help='statically render a page and print to stdout rather than starting '
     72            'the server, e.g. apps/storage.html. The path may optionally end '
     73            'with #n where n is the number of times to render the page before '
     74            'printing it, e.g. apps/storage.html#50, to use for profiling.')
     75   parser.add_option('-t', '--time', action='store_true',
     76       help='Print the time taken rendering rather than the result.')
     77 
     78   (opts, argv) = parser.parse_args()
     79 
     80   if opts.render:
     81     if opts.render.find('#') >= 0:
     82       (path, iterations) = opts.render.rsplit('#', 1)
     83       extra_iterations = int(iterations) - 1
     84     else:
     85       path = opts.render
     86       extra_iterations = 0
     87 
     88     if opts.time:
     89       start_time = time.time()
     90 
     91     response = LocalRenderer.Render(path)
     92     if response.status != 200:
     93       print('Error status: %s' % response.status)
     94       exit(1)
     95 
     96     for _ in range(extra_iterations):
     97       LocalRenderer.Render(path)
     98 
     99     if opts.time:
    100       print('Took %s seconds' % (time.time() - start_time))
    101     else:
    102       print(response.content.ToString())
    103     exit()
    104 
    105   print('Starting previewserver on port %s' % opts.port)
    106   print('')
    107   print('The extension documentation can be found at:')
    108   print('')
    109   print('  http://localhost:%s/extensions/' % opts.port)
    110   print('')
    111   print('The apps documentation can be found at:')
    112   print('')
    113   print('  http://localhost:%s/apps/' % opts.port)
    114   print('')
    115 
    116   logging.getLogger().setLevel(logging.INFO)
    117   server = HTTPServer(('', int(opts.port)), _RequestHandler)
    118   try:
    119     server.serve_forever()
    120   finally:
    121     server.socket.close()
    122