| # Copyright 2016 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Defines the handler for /messages/<NAME> paths. |
| |
| The name of the message is expected to follow the /messages/ portion of the |
| path. The body of the request will contain the message, both when uploading |
| the message as well as retrieving it. The message will remain on the server |
| until the calling code does an explicit DELETE call to remove it. |
| |
| The message is optional. This allows the caller to use this as a simple signal |
| server. The return code can always be used to tell if a message with that name |
| exists on the server (200 exists, 404 doesn't exist). |
| |
| When uploading a body ensure the content-length header is passed correctly. |
| If the content-length isn't passed no data is read from the body. If its set |
| too low only part of the message will be read. If its set too high the server |
| will block waiting for more data to be uploaded. |
| """ |
| |
| import re |
| import threading |
| |
| from legion.lib.comm_server import base_handler |
| |
| |
| class MessageHandler(base_handler.BaseHandler): |
| """Handles /messages/<NAME> requests.""" |
| |
| _REGEX = '/messages/(?P<name>[a-zA-Z0-9_.-~]+)' |
| _messages = {} |
| _message_lock = threading.Lock() |
| |
| def _GetName(self, request): |
| """Gets the message name from the URL.""" |
| match = re.match(self._REGEX, request.path) |
| if not match: |
| return None |
| return match.group('name') |
| |
| def do_PUT(self, request): |
| """Handles PUT requests.""" |
| name = self._GetName(request) |
| if not name: |
| return request.send_error(405, 'Key name required') |
| with self._message_lock: |
| self._messages[name] = request.rfile.read( |
| int(request.headers.getheader('content-length', 0))) |
| return request.send_response(200) |
| |
| def do_GET(self, request): |
| """Handles GET requests.""" |
| name = self._GetName(request) |
| if not name: |
| return request.send_error(405, 'Key name required') |
| elif name not in self._messages: |
| return request.send_error(404, 'Key not found') |
| with self._message_lock: |
| request.send_response(200) |
| request.send_header('Content-type', 'text/plain') |
| request.send_header('Content-Length', str(len(self._messages[name]))) |
| request.end_headers() |
| request.wfile.write(self._messages[name]) |
| |
| def do_DELETE(self, request): |
| """Handles DELETE requests.""" |
| name = self._GetName(request) |
| if not name: |
| return request.send_error(405, 'Key name required') |
| with self._message_lock: |
| if name in self._messages: |
| del self._messages[name] |
| return request.send_response(200) |
| else: |
| return request.send_error(404, 'Key not found') |