summaryrefslogtreecommitdiff
path: root/Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py')
-rw-r--r--Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py146
1 files changed, 146 insertions, 0 deletions
diff --git a/Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py b/Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py
new file mode 100644
index 000000000..db118afa6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/servers/reflectionhandler.py
@@ -0,0 +1,146 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from __future__ import with_statement
+
+try:
+ import json
+except ImportError:
+ # python 2.5 compatibility
+ import webkitpy.thirdparty.simplejson as json
+
+import BaseHTTPServer
+
+import cgi
+import codecs
+import datetime
+import fnmatch
+import mimetypes
+import os
+import os.path
+import shutil
+import threading
+import time
+import urlparse
+import wsgiref.handlers
+import BaseHTTPServer
+
+class ReflectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ # Subclasses should override.
+ STATIC_FILE_NAMES = None
+ STATIC_FILE_DIRECTORY = None
+
+ # Setting this flag to True causes the server to send
+ # Access-Control-Allow-Origin: *
+ # with every response.
+ allow_cross_origin_requests = False
+
+ def do_GET(self):
+ self._handle_request()
+
+ def do_POST(self):
+ self._handle_request()
+
+ def _read_entity_body(self):
+ length = int(self.headers.getheader('content-length'))
+ return self.rfile.read(length)
+
+ def _read_entity_body_as_json(self):
+ return json.loads(self._read_entity_body())
+
+ def _handle_request(self):
+ if "?" in self.path:
+ path, query_string = self.path.split("?", 1)
+ self.query = cgi.parse_qs(query_string)
+ else:
+ path = self.path
+ self.query = {}
+ function_or_file_name = path[1:] or "index.html"
+
+ if function_or_file_name in self.STATIC_FILE_NAMES:
+ self._serve_static_file(function_or_file_name)
+ return
+
+ function_name = function_or_file_name.replace(".", "_")
+ if not hasattr(self, function_name):
+ self.send_error(404, "Unknown function %s" % function_name)
+ return
+ if function_name[0] == "_":
+ self.send_error(401, "Not allowed to invoke private or protected methods")
+ return
+ function = getattr(self, function_name)
+ function()
+
+ def _serve_static_file(self, static_path):
+ self._serve_file(os.path.join(self.STATIC_FILE_DIRECTORY, static_path))
+
+ def quitquitquit(self):
+ self._serve_text("Server quit.\n")
+ # Shutdown has to happen on another thread from the server's thread,
+ # otherwise there's a deadlock
+ threading.Thread(target=lambda: self.server.shutdown()).start()
+
+ def _send_access_control_header(self):
+ if self.allow_cross_origin_requests:
+ self.send_header('Access-Control-Allow-Origin', '*')
+
+ def _serve_text(self, text):
+ self.send_response(200)
+ self._send_access_control_header()
+ self.send_header("Content-type", "text/plain")
+ self.end_headers()
+ self.wfile.write(text)
+
+ def _serve_json(self, json_object):
+ self.send_response(200)
+ self._send_access_control_header()
+ self.send_header('Content-type', 'application/json')
+ self.end_headers()
+ json.dump(json_object, self.wfile)
+
+ def _serve_file(self, file_path, cacheable_seconds=0):
+ if not os.path.exists(file_path):
+ self.send_error(404, "File not found")
+ return
+ with codecs.open(file_path, "rb") as static_file:
+ self.send_response(200)
+ self._send_access_control_header()
+ self.send_header("Content-Length", os.path.getsize(file_path))
+ mime_type, encoding = mimetypes.guess_type(file_path)
+ if mime_type:
+ self.send_header("Content-type", mime_type)
+
+ if cacheable_seconds:
+ expires_time = (datetime.datetime.now() +
+ datetime.timedelta(0, cacheable_seconds))
+ expires_formatted = wsgiref.handlers.format_date_time(
+ time.mktime(expires_time.timetuple()))
+ self.send_header("Expires", expires_formatted)
+ self.end_headers()
+
+ shutil.copyfileobj(static_file, self.wfile)