| 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 |