OLD | NEW |
---|---|
(Empty) | |
1 # Copyright 2015 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 | |
5 """Simple Markdown browser for a Git checkout.""" | |
6 | |
7 import SimpleHTTPServer | |
8 import SocketServer | |
9 import argparse | |
10 import codecs | |
11 import os | |
12 import socket | |
13 import sys | |
14 | |
15 | |
16 SRC_DIR = os.path.dirname(os.path.dirname( | |
17 os.path.dirname(os.path.abspath(__file__)))) | |
18 sys.path.append(os.path.join(SRC_DIR, 'third_party', 'Python-Markdown')) | |
19 import markdown | |
20 | |
21 | |
22 def main(argv): | |
23 parser = argparse.ArgumentParser(prog='md_browser') | |
scottmg
2015/09/22 04:58:01
+4 like an animal! :)
Dirk Pranke
2015/09/22 21:16:27
will fix. stupid chromium coding standards :).
| |
24 parser.add_argument('-p', '--port', type=int, default=8080, | |
25 help='port to run on (default = %(default)s)') | |
26 args = parser.parse_args(argv) | |
27 | |
28 try: | |
29 s = Server(args.port, SRC_DIR) | |
30 s.serve_forever() | |
31 s.shutdown() | |
32 return 0 | |
33 except KeyboardInterrupt: | |
34 return 130 | |
35 | |
36 | |
37 class Server(SocketServer.TCPServer): | |
38 def __init__(self, port, top_level): | |
39 SocketServer.TCPServer.__init__(self, ('0.0.0.0', port), Handler) | |
40 self.port = port | |
41 self.top_level = top_level | |
42 | |
43 def server_bind(self): | |
44 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
45 self.socket.bind(self.server_address) | |
46 | |
47 | |
48 class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): | |
49 def do_GET(self): | |
50 full_path = os.path.abspath(os.path.join(self.server.top_level, | |
51 self.path[1:])) | |
scottmg
2015/09/22 04:58:01
I guess it doesn't matter for this usage, but you
nodir
2015/09/22 16:38:18
os.path.abspath returns a normalized path, so the
scottmg
2015/09/22 17:32:46
(I meant that by entering localhost:8080/../../../
Dirk Pranke
2015/09/22 21:16:27
Right, but Nodir's saying (correctly, I believe) t
scottmg
2015/09/22 21:26:39
Oh, you're right. Sorry.
| |
52 if not full_path.startswith(self.server.top_level): | |
53 self._do_unknown() | |
54 elif self.path == '/doc.css': | |
55 self._write_file('doc.css') | |
56 elif not os.path.exists(full_path): | |
57 self._do_not_found() | |
58 elif self.path.endswith('.md'): | |
nodir
2015/09/22 16:38:18
self.path.lower()... JIC
Dirk Pranke
2015/09/22 21:16:27
Done, though I worry about what other sorts of wei
| |
59 self._do_md() | |
60 else: | |
61 self._do_unknown() | |
62 | |
63 def _do_md(self): | |
64 extensions = [ | |
65 'markdown.extensions.fenced_code', | |
66 'markdown.extensions.tables', | |
67 'markdown.extensions.toc', | |
68 ] | |
69 | |
70 contents = self._read(self.path[1:]) | |
scottmg
2015/09/22 04:58:01
it seems like this is already stripping the leadin
Dirk Pranke
2015/09/22 21:16:27
Made things more consistent.
| |
71 md_fragment = markdown.markdown(contents, | |
72 extensions=extensions, | |
73 output_format='html4').encode('utf-8') | |
74 try: | |
75 self._write_file('header.html') | |
76 self.wfile.write(md_fragment) | |
77 self._write_file('footer.html') | |
78 except: | |
79 raise | |
80 | |
81 def _do_not_found(self): | |
82 self.wfile.write('<html><body>%s not found</body></html>' % self.path) | |
83 | |
84 def _do_unknown(self): | |
85 self.wfile.write('<html><body>I do not know how to serve %s.</body>' | |
86 '</html>' % self.path) | |
87 | |
88 def _read(self, path): | |
89 if not path.startswith('/'): | |
nodir
2015/09/22 16:38:18
this if is unnecessary: os.path.join('/foo', '/bar
Dirk Pranke
2015/09/22 21:16:27
true, but the code was confusing regardless. Made
| |
90 path = os.path.join(self.server.top_level, path) | |
91 return codecs.open(path, mode='r', encoding='utf-8').read() | |
nodir
2015/09/22 16:38:18
mode='r' is unnecessary, it is default
nodir
2015/09/22 16:38:18
This seems to leave the fd open?
Shouldn't you
wi
Dirk Pranke
2015/09/22 21:16:27
Done, and good catch on the fd.
| |
92 | |
93 def _write_file(self, path): | |
94 assert os.sep not in path | |
95 contents = self._read(os.path.join(SRC_DIR, 'tools', 'md_browser', | |
nodir
2015/09/22 16:38:18
nit: I think moving the line break to the position
Dirk Pranke
2015/09/22 21:16:27
Once I switch to 2-space indents the whole thing f
| |
96 path)) | |
97 self.wfile.write(contents.encode('utf-8')) | |
98 | |
99 | |
100 if __name__ == '__main__': | |
101 sys.exit(main(sys.argv[1:])) | |
OLD | NEW |