OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import BaseHTTPServer | 5 import BaseHTTPServer |
6 import os | 6 import os |
7 import threading | 7 import threading |
8 | 8 |
9 | 9 |
10 class Responder(object): | 10 class Responder(object): |
(...skipping 30 matching lines...) Expand all Loading... |
41 | 41 |
42 class Request(object): | 42 class Request(object): |
43 """An HTTP request.""" | 43 """An HTTP request.""" |
44 | 44 |
45 def __init__(self, handler): | 45 def __init__(self, handler): |
46 self._handler = handler | 46 self._handler = handler |
47 | 47 |
48 def GetPath(self): | 48 def GetPath(self): |
49 return self._handler.path | 49 return self._handler.path |
50 | 50 |
| 51 def GetHeader(self, name): |
| 52 return self._handler.headers.getheader(name) |
| 53 |
51 | 54 |
52 class _BaseServer(BaseHTTPServer.HTTPServer): | 55 class _BaseServer(BaseHTTPServer.HTTPServer): |
53 """Internal server that throws if timed out waiting for a request.""" | 56 """Internal server that throws if timed out waiting for a request.""" |
54 | 57 |
55 def __init__(self, on_request, server_cert_and_key_path=None): | 58 def __init__(self, on_request, server_cert_and_key_path=None): |
56 """Starts the server. | 59 """Starts the server. |
57 | 60 |
58 It is an HTTP server if parameter server_cert_and_key_path is not provided. | 61 It is an HTTP server if parameter server_cert_and_key_path is not provided. |
59 Otherwise, it is an HTTPS server. | 62 Otherwise, it is an HTTPS server. |
60 | 63 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 root_dir: root path to serve files from. This parameter is required. | 116 root_dir: root path to serve files from. This parameter is required. |
114 server_cert_and_key_path: path to a PEM file containing the cert and key. | 117 server_cert_and_key_path: path to a PEM file containing the cert and key. |
115 if it is None, start the server as an HTTP one. | 118 if it is None, start the server as an HTTP one. |
116 """ | 119 """ |
117 self._root_dir = os.path.abspath(root_dir) | 120 self._root_dir = os.path.abspath(root_dir) |
118 self._server = _BaseServer(self._OnRequest, server_cert_and_key_path) | 121 self._server = _BaseServer(self._OnRequest, server_cert_and_key_path) |
119 self._thread = threading.Thread(target=self._server.serve_forever) | 122 self._thread = threading.Thread(target=self._server.serve_forever) |
120 self._thread.daemon = True | 123 self._thread.daemon = True |
121 self._thread.start() | 124 self._thread.start() |
122 self._path_data_map = {} | 125 self._path_data_map = {} |
123 self._path_data_lock = threading.Lock() | 126 self._path_callback_map = {} |
| 127 self._path_maps_lock = threading.Lock() |
124 | 128 |
125 def _OnRequest(self, request, responder): | 129 def _OnRequest(self, request, responder): |
126 path = request.GetPath().split('?')[0] | 130 path = request.GetPath().split('?')[0] |
127 | 131 |
128 # Serve from path -> data map. | 132 # Serve from path -> callback and data maps. |
129 self._path_data_lock.acquire() | 133 self._path_maps_lock.acquire() |
130 try: | 134 try: |
| 135 if path in self._path_callback_map: |
| 136 body = self._path_callback_map[path](request) |
| 137 if body: |
| 138 responder.SendResponse(body) |
| 139 else: |
| 140 responder.SendError(503) |
| 141 return |
| 142 |
131 if path in self._path_data_map: | 143 if path in self._path_data_map: |
132 responder.SendResponse(self._path_data_map[path]) | 144 responder.SendResponse(self._path_data_map[path]) |
133 return | 145 return |
134 finally: | 146 finally: |
135 self._path_data_lock.release() | 147 self._path_maps_lock.release() |
136 | 148 |
137 # Serve from file. | 149 # Serve from file. |
138 path = os.path.normpath( | 150 path = os.path.normpath( |
139 os.path.join(self._root_dir, *path.split('/'))) | 151 os.path.join(self._root_dir, *path.split('/'))) |
140 if not path.startswith(self._root_dir): | 152 if not path.startswith(self._root_dir): |
141 responder.SendError(403) | 153 responder.SendError(403) |
142 return | 154 return |
143 if not os.path.exists(path): | 155 if not os.path.exists(path): |
144 responder.SendError(404) | 156 responder.SendError(404) |
145 return | 157 return |
146 responder.SendResponseFromFile(path) | 158 responder.SendResponseFromFile(path) |
147 | 159 |
148 def SetDataForPath(self, path, data): | 160 def SetDataForPath(self, path, data): |
149 self._path_data_lock.acquire() | 161 self._path_maps_lock.acquire() |
150 try: | 162 try: |
151 self._path_data_map[path] = data | 163 self._path_data_map[path] = data |
152 finally: | 164 finally: |
153 self._path_data_lock.release() | 165 self._path_maps_lock.release() |
| 166 |
| 167 def SetCallbackForPath(self, path, func): |
| 168 self._path_maps_lock.acquire() |
| 169 try: |
| 170 self._path_callback_map[path] = func |
| 171 finally: |
| 172 self._path_maps_lock.release() |
| 173 |
154 | 174 |
155 def GetUrl(self): | 175 def GetUrl(self): |
156 """Returns the base URL of the server.""" | 176 """Returns the base URL of the server.""" |
157 return self._server.GetUrl() | 177 return self._server.GetUrl() |
158 | 178 |
159 def Shutdown(self): | 179 def Shutdown(self): |
160 """Shuts down the server synchronously.""" | 180 """Shuts down the server synchronously.""" |
161 self._server.shutdown() | 181 self._server.shutdown() |
162 self._thread.join() | 182 self._thread.join() |
163 | 183 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 self._server.handle_request() | 216 self._server.handle_request() |
197 | 217 |
198 def RespondWithContent(self, content): | 218 def RespondWithContent(self, content): |
199 """Blocks until request comes in, then handles it with the given content.""" | 219 """Blocks until request comes in, then handles it with the given content.""" |
200 def SendContent(responder): | 220 def SendContent(responder): |
201 responder.SendResponse(content) | 221 responder.SendResponse(content) |
202 self.Respond(SendContent) | 222 self.Respond(SendContent) |
203 | 223 |
204 def GetUrl(self): | 224 def GetUrl(self): |
205 return self._server.GetUrl() | 225 return self._server.GetUrl() |
OLD | NEW |