blob: 04413283e8b93fb0c26ca94c36fc83feb75f7779 [file] [log] [blame]
# 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')