Chromium Code Reviews| 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 """A server to allow events to be passed from one task to another. | |
| 6 | |
| 7 This server supports getting, setting, and deleting of arbitrary event names. | |
| 8 This is a "pull" style of server, so its on the producer and consumer to | |
| 9 proactively get, set, and delete the events. | |
| 10 | |
| 11 | |
| 12 Operation | Url | Action | |
| 13 ------------------------------------------------------------------------------- | |
| 14 GET | /events/<NAME> | Returns 200 for an event that is set. | |
| 15 | | Returns 404 for an event that is not set | |
| 16 ------------------------------------------------------------------------------- | |
| 17 PUT | /events/<NAME> | Sets the event and returns 200. | |
|
M-A Ruel
2016/01/15 14:07:13
You test for POST, not PUT.
Mike Meade
2016/01/18 20:25:51
Done.
| |
| 18 ------------------------------------------------------------------------------- | |
| 19 DELETE | /events/<NAME> | Deletes the event and returns 200. | |
| 20 ------------------------------------------------------------------------------- | |
| 21 | |
| 22 Errors | |
| 23 Error | Action | Reason | |
| 24 ------------------------------------------------------------------------------- | |
| 25 403 | GET | Category is not specified | |
| 26 ------------------------------------------------------------------------------- | |
| 27 404 | GET | Event doesn't exist or isn't set | |
| 28 ------------------------------------------------------------------------------- | |
| 29 501 | All | Incorrect URL format (must be events/<NAME>) | |
| 30 ------------------------------------------------------------------------------- | |
| 31 """ | |
| 32 | |
| 33 import BaseHTTPServer | |
| 34 import httplib | |
| 35 import re | |
| 36 import SimpleHTTPServer | |
| 37 import SocketServer | |
| 38 import threading | |
| 39 | |
| 40 from legion.lib import common_lib | |
| 41 | |
| 42 | |
| 43 class ThreadedServer(SocketServer.ThreadingMixIn, | |
| 44 BaseHTTPServer.HTTPServer): | |
| 45 """An extension of the HTTPServer class which handles requests in threads.""" | |
| 46 | |
| 47 def __init__(self, address=''): | |
| 48 self._port = common_lib.GetUnusedPort() | |
| 49 self._address = address | |
| 50 BaseHTTPServer.HTTPServer.__init__(self, | |
| 51 (self._address, self._port), | |
| 52 HttpRequestHandler) | |
| 53 | |
| 54 @property | |
| 55 def port(self): | |
| 56 return self._port | |
| 57 | |
| 58 @property | |
| 59 def address(self): | |
| 60 return self._address | |
| 61 | |
| 62 def start(self): | |
| 63 """Starts the server in another thread. | |
| 64 | |
| 65 The thread will stay active until shutdown() is called. There is no reason | |
| 66 to hold a reference to the thread object. | |
| 67 """ | |
| 68 threading.Thread(target=self.serve_forever).start() | |
| 69 | |
| 70 | |
| 71 class EventHandler(object): | |
| 72 """Handles event set/get/delete operations.""" | |
| 73 | |
| 74 _REGEX = re.compile('^/events/(?P<name>[a-zA-Z0-9]*)') | |
| 75 _events = {} | |
| 76 _event_lock = threading.Lock() | |
| 77 | |
| 78 def _GetName(self, request): | |
| 79 """Gets the event name from the URL.""" | |
| 80 match = self._REGEX.match(request.path) | |
| 81 if not match: | |
| 82 return None | |
| 83 return match.group('name') | |
| 84 | |
| 85 | |
| 86 def do_GET(self, request): | |
| 87 """Handles GET requests.""" | |
| 88 name = self._GetName(request) | |
| 89 if not name: | |
| 90 return request.send_error(501, 'Event name required') | |
| 91 with self._event_lock: | |
| 92 if name not in self._events: | |
| 93 return request.send_error(404, 'Event: %s not found' % name) | |
| 94 else: | |
| 95 return request.send_response(200) | |
| 96 | |
| 97 def do_POST(self, request): | |
| 98 """Handles POST requests.""" | |
| 99 name = self._GetName(request) | |
| 100 if not name: | |
| 101 return request.send_error(501, 'Event name required') | |
| 102 with self._event_lock: | |
| 103 self._events[name] = 1 | |
| 104 return request.send_response(200) | |
| 105 | |
| 106 def do_DELETE(self, request): | |
| 107 """Handles DELETE requests.""" | |
| 108 name = self._GetName(request) | |
| 109 if not name: | |
| 110 return request.send_error(501, 'Event name required') | |
| 111 with self._event_lock: | |
| 112 if name in self._events: | |
| 113 del self._events[name] | |
| 114 return request.send_response(200) | |
| 115 else: | |
| 116 return request.send_error(404, 'Event not found') | |
| 117 | |
| 118 | |
| 119 class HttpRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | |
| 120 """Request handler which dispatches requests to the correct subhandler. | |
| 121 | |
| 122 To extend this functionality implement a class that handles do_GET, do_POST, | |
| 123 and do_DELETE methods, then add the name/class to the _HANDLERS dict. | |
| 124 """ | |
| 125 | |
| 126 _REGEX = re.compile('/(?P<category>[a-zA-Z0-9]*)') | |
| 127 | |
| 128 _HANDLERS = { | |
| 129 'events': EventHandler, | |
| 130 } | |
| 131 | |
| 132 def log_message(self, *args, **kwargs): | |
| 133 """Silence those pesky server-side print statements.""" | |
| 134 pass | |
| 135 | |
| 136 def _GetCategoryName(self): | |
| 137 """Extracts and returns the category name.""" | |
| 138 match = self._REGEX.match(self.path) | |
| 139 if not match: | |
| 140 return | |
| 141 return match.group('category') | |
| 142 | |
| 143 def _GetHandler(self): | |
| 144 """Returns the category handler object if it exists.""" | |
| 145 category = self._GetCategoryName() | |
| 146 if not category: | |
| 147 return self.send_error(403, 'Category must be supplied') | |
| 148 handler = self._HANDLERS.get(category) | |
| 149 if not handler: | |
| 150 return self.send_error(501, '/%s is not supported' % category) | |
| 151 return handler() | |
| 152 | |
| 153 def do_GET(self): | |
| 154 """Handles GET requests.""" | |
| 155 handler = self._GetHandler() | |
| 156 if handler: | |
| 157 handler.do_GET(self) | |
| 158 | |
| 159 def do_POST(self): | |
| 160 """Handles POST requests.""" | |
| 161 handler = self._GetHandler() | |
| 162 if handler: | |
| 163 handler.do_POST(self) | |
| 164 | |
| 165 def do_DELETE(self): | |
| 166 """Handles DELETE requests.""" | |
| 167 handler = self._GetHandler() | |
| 168 if handler: | |
| 169 handler.do_DELETE(self) | |
| OLD | NEW |