initial import
[vuplus_webkit] / Tools / Scripts / webkitpy / tool / servers / reflectionhandler.py
1 # Copyright (c) 2011 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #     * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #     * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 from __future__ import with_statement
30
31 try:
32     import json
33 except ImportError:
34     # python 2.5 compatibility
35     import webkitpy.thirdparty.simplejson as json
36
37 import BaseHTTPServer
38
39 import cgi
40 import codecs
41 import datetime
42 import fnmatch
43 import mimetypes
44 import os
45 import os.path
46 import shutil
47 import threading
48 import time
49 import urlparse
50 import BaseHTTPServer
51
52
53 class ReflectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):
54     # Subclasses should override.
55     STATIC_FILE_NAMES = None
56     STATIC_FILE_DIRECTORY = None
57
58     # Setting this flag to True causes the server to send
59     #   Access-Control-Allow-Origin: *
60     # with every response.
61     allow_cross_origin_requests = False
62
63     def do_GET(self):
64         self._handle_request()
65
66     def do_POST(self):
67         self._handle_request()
68
69     def _read_entity_body(self):
70         length = int(self.headers.getheader('content-length'))
71         return self.rfile.read(length)
72
73     def _read_entity_body_as_json(self):
74         return json.loads(self._read_entity_body())
75
76     def _handle_request(self):
77         if "?" in self.path:
78             path, query_string = self.path.split("?", 1)
79             self.query = cgi.parse_qs(query_string)
80         else:
81             path = self.path
82             self.query = {}
83         function_or_file_name = path[1:] or "index.html"
84
85         if function_or_file_name in self.STATIC_FILE_NAMES:
86             self._serve_static_file(function_or_file_name)
87             return
88
89         function_name = function_or_file_name.replace(".", "_")
90         if not hasattr(self, function_name):
91             self.send_error(404, "Unknown function %s" % function_name)
92             return
93         if function_name[0] == "_":
94             self.send_error(401, "Not allowed to invoke private or protected methods")
95             return
96         function = getattr(self, function_name)
97         function()
98
99     def _serve_static_file(self, static_path):
100         self._serve_file(os.path.join(self.STATIC_FILE_DIRECTORY, static_path))
101
102     def quitquitquit(self):
103         self._serve_text("Server quit.\n")
104         # Shutdown has to happen on another thread from the server's thread,
105         # otherwise there's a deadlock
106         threading.Thread(target=lambda: self.server.shutdown()).start()
107
108     def _send_access_control_header(self):
109         if self.allow_cross_origin_requests:
110             self.send_header('Access-Control-Allow-Origin', '*')
111
112     def _serve_text(self, text):
113         self.send_response(200)
114         self._send_access_control_header()
115         self.send_header("Content-type", "text/plain")
116         self.end_headers()
117         self.wfile.write(text)
118
119     def _serve_json(self, json_object):
120         self.send_response(200)
121         self._send_access_control_header()
122         self.send_header('Content-type', 'application/json')
123         self.end_headers()
124         json.dump(json_object, self.wfile)
125
126     def _serve_file(self, file_path, cacheable_seconds=0):
127         if not os.path.exists(file_path):
128             self.send_error(404, "File not found")
129             return
130         with codecs.open(file_path, "rb") as static_file:
131             self.send_response(200)
132             self._send_access_control_header()
133             self.send_header("Content-Length", os.path.getsize(file_path))
134             mime_type, encoding = mimetypes.guess_type(file_path)
135             if mime_type:
136                 self.send_header("Content-type", mime_type)
137
138             if cacheable_seconds:
139                 expires_time = (datetime.datetime.now() +
140                     datetime.timedelta(0, cacheable_seconds))
141                 expires_formatted = format_date_time(
142                     time.mktime(expires_time.timetuple()))
143                 self.send_header("Expires", expires_formatted)
144             self.end_headers()
145
146             shutil.copyfileobj(static_file, self.wfile)