Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ fa10bdc5

History | View | Annotate | Download (17.8 kB)

1 a43f68dc Michael Hanselmann
#
2 a43f68dc Michael Hanselmann
#
3 a43f68dc Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
4 a43f68dc Michael Hanselmann
# it under the terms of the GNU General Public License as published by
5 a43f68dc Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
6 a43f68dc Michael Hanselmann
# (at your option) any later version.
7 a43f68dc Michael Hanselmann
#
8 a43f68dc Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
9 a43f68dc Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
10 a43f68dc Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 a43f68dc Michael Hanselmann
# General Public License for more details.
12 a43f68dc Michael Hanselmann
#
13 a43f68dc Michael Hanselmann
# You should have received a copy of the GNU General Public License
14 a43f68dc Michael Hanselmann
# along with this program; if not, write to the Free Software
15 a43f68dc Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 a43f68dc Michael Hanselmann
# 02110-1301, USA.
17 a43f68dc Michael Hanselmann
18 a43f68dc Michael Hanselmann
"""HTTP server module.
19 a43f68dc Michael Hanselmann

20 a43f68dc Michael Hanselmann
"""
21 a43f68dc Michael Hanselmann
22 a43f68dc Michael Hanselmann
import BaseHTTPServer
23 42242313 Michael Hanselmann
import cgi
24 42242313 Michael Hanselmann
import logging
25 42242313 Michael Hanselmann
import mimetools
26 a43f68dc Michael Hanselmann
import OpenSSL
27 42242313 Michael Hanselmann
import os
28 42242313 Michael Hanselmann
import select
29 42242313 Michael Hanselmann
import socket
30 42242313 Michael Hanselmann
import sys
31 a43f68dc Michael Hanselmann
import time
32 42242313 Michael Hanselmann
import signal
33 a43f68dc Michael Hanselmann
34 42242313 Michael Hanselmann
from ganeti import constants
35 a43f68dc Michael Hanselmann
from ganeti import logger
36 a43f68dc Michael Hanselmann
from ganeti import serializer
37 a43f68dc Michael Hanselmann
38 a43f68dc Michael Hanselmann
39 42242313 Michael Hanselmann
WEEKDAYNAME = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
40 42242313 Michael Hanselmann
MONTHNAME = [None,
41 42242313 Michael Hanselmann
             'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
42 42242313 Michael Hanselmann
             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
43 42242313 Michael Hanselmann
44 42242313 Michael Hanselmann
# Default error message
45 42242313 Michael Hanselmann
DEFAULT_ERROR_CONTENT_TYPE = "text/html"
46 42242313 Michael Hanselmann
DEFAULT_ERROR_MESSAGE = """\
47 42242313 Michael Hanselmann
<head>
48 42242313 Michael Hanselmann
<title>Error response</title>
49 42242313 Michael Hanselmann
</head>
50 42242313 Michael Hanselmann
<body>
51 42242313 Michael Hanselmann
<h1>Error response</h1>
52 42242313 Michael Hanselmann
<p>Error code %(code)d.
53 42242313 Michael Hanselmann
<p>Message: %(message)s.
54 42242313 Michael Hanselmann
<p>Error code explanation: %(code)s = %(explain)s.
55 42242313 Michael Hanselmann
</body>
56 42242313 Michael Hanselmann
"""
57 42242313 Michael Hanselmann
58 42242313 Michael Hanselmann
HTTP_OK = 200
59 42242313 Michael Hanselmann
HTTP_NO_CONTENT = 204
60 42242313 Michael Hanselmann
HTTP_NOT_MODIFIED = 304
61 42242313 Michael Hanselmann
62 42242313 Michael Hanselmann
HTTP_0_9 = "HTTP/0.9"
63 42242313 Michael Hanselmann
HTTP_1_0 = "HTTP/1.0"
64 42242313 Michael Hanselmann
HTTP_1_1 = "HTTP/1.1"
65 42242313 Michael Hanselmann
66 42242313 Michael Hanselmann
HTTP_GET = "GET"
67 42242313 Michael Hanselmann
HTTP_HEAD = "HEAD"
68 713faea6 Oleksiy Mishchenko
HTTP_ETAG = "ETag"
69 42242313 Michael Hanselmann
70 42242313 Michael Hanselmann
71 42242313 Michael Hanselmann
class SocketClosed(socket.error):
72 42242313 Michael Hanselmann
  pass
73 42242313 Michael Hanselmann
74 42242313 Michael Hanselmann
75 a43f68dc Michael Hanselmann
class HTTPException(Exception):
76 a43f68dc Michael Hanselmann
  code = None
77 a43f68dc Michael Hanselmann
  message = None
78 a43f68dc Michael Hanselmann
79 a43f68dc Michael Hanselmann
  def __init__(self, message=None):
80 42242313 Michael Hanselmann
    Exception.__init__(self)
81 a43f68dc Michael Hanselmann
    if message is not None:
82 a43f68dc Michael Hanselmann
      self.message = message
83 a43f68dc Michael Hanselmann
84 a43f68dc Michael Hanselmann
85 a43f68dc Michael Hanselmann
class HTTPBadRequest(HTTPException):
86 a43f68dc Michael Hanselmann
  code = 400
87 a43f68dc Michael Hanselmann
88 a43f68dc Michael Hanselmann
89 a43f68dc Michael Hanselmann
class HTTPForbidden(HTTPException):
90 a43f68dc Michael Hanselmann
  code = 403
91 a43f68dc Michael Hanselmann
92 a43f68dc Michael Hanselmann
93 a43f68dc Michael Hanselmann
class HTTPNotFound(HTTPException):
94 a43f68dc Michael Hanselmann
  code = 404
95 a43f68dc Michael Hanselmann
96 a43f68dc Michael Hanselmann
97 a43f68dc Michael Hanselmann
class HTTPGone(HTTPException):
98 a43f68dc Michael Hanselmann
  code = 410
99 a43f68dc Michael Hanselmann
100 a43f68dc Michael Hanselmann
101 a43f68dc Michael Hanselmann
class HTTPLengthRequired(HTTPException):
102 a43f68dc Michael Hanselmann
  code = 411
103 a43f68dc Michael Hanselmann
104 a43f68dc Michael Hanselmann
105 a43f68dc Michael Hanselmann
class HTTPInternalError(HTTPException):
106 a43f68dc Michael Hanselmann
  code = 500
107 a43f68dc Michael Hanselmann
108 a43f68dc Michael Hanselmann
109 a43f68dc Michael Hanselmann
class HTTPNotImplemented(HTTPException):
110 a43f68dc Michael Hanselmann
  code = 501
111 a43f68dc Michael Hanselmann
112 a43f68dc Michael Hanselmann
113 a43f68dc Michael Hanselmann
class HTTPServiceUnavailable(HTTPException):
114 a43f68dc Michael Hanselmann
  code = 503
115 a43f68dc Michael Hanselmann
116 a43f68dc Michael Hanselmann
117 42242313 Michael Hanselmann
class HTTPVersionNotSupported(HTTPException):
118 42242313 Michael Hanselmann
  code = 505
119 42242313 Michael Hanselmann
120 42242313 Michael Hanselmann
121 a43f68dc Michael Hanselmann
class ApacheLogfile:
122 a43f68dc Michael Hanselmann
  """Utility class to write HTTP server log files.
123 a43f68dc Michael Hanselmann

124 a43f68dc Michael Hanselmann
  The written format is the "Common Log Format" as defined by Apache:
125 a43f68dc Michael Hanselmann
  http://httpd.apache.org/docs/2.2/mod/mod_log_config.html#examples
126 a43f68dc Michael Hanselmann

127 a43f68dc Michael Hanselmann
  """
128 a43f68dc Michael Hanselmann
  def __init__(self, fd):
129 a43f68dc Michael Hanselmann
    """Constructor for ApacheLogfile class.
130 a43f68dc Michael Hanselmann

131 a43f68dc Michael Hanselmann
    Args:
132 a43f68dc Michael Hanselmann
    - fd: Open file object
133 a43f68dc Michael Hanselmann

134 a43f68dc Michael Hanselmann
    """
135 a43f68dc Michael Hanselmann
    self._fd = fd
136 a43f68dc Michael Hanselmann
137 a43f68dc Michael Hanselmann
  def LogRequest(self, request, format, *args):
138 a43f68dc Michael Hanselmann
    self._fd.write("%s %s %s [%s] %s\n" % (
139 a43f68dc Michael Hanselmann
      # Remote host address
140 a43f68dc Michael Hanselmann
      request.address_string(),
141 a43f68dc Michael Hanselmann
142 a43f68dc Michael Hanselmann
      # RFC1413 identity (identd)
143 a43f68dc Michael Hanselmann
      "-",
144 a43f68dc Michael Hanselmann
145 a43f68dc Michael Hanselmann
      # Remote user
146 a43f68dc Michael Hanselmann
      "-",
147 a43f68dc Michael Hanselmann
148 a43f68dc Michael Hanselmann
      # Request time
149 a43f68dc Michael Hanselmann
      self._FormatCurrentTime(),
150 a43f68dc Michael Hanselmann
151 a43f68dc Michael Hanselmann
      # Message
152 a43f68dc Michael Hanselmann
      format % args,
153 a43f68dc Michael Hanselmann
      ))
154 a0638838 Oleksiy Mishchenko
    self._fd.flush()
155 a43f68dc Michael Hanselmann
156 a43f68dc Michael Hanselmann
  def _FormatCurrentTime(self):
157 a43f68dc Michael Hanselmann
    """Formats current time in Common Log Format.
158 a43f68dc Michael Hanselmann

159 a43f68dc Michael Hanselmann
    """
160 a43f68dc Michael Hanselmann
    return self._FormatLogTime(time.time())
161 a43f68dc Michael Hanselmann
162 a43f68dc Michael Hanselmann
  def _FormatLogTime(self, seconds):
163 a43f68dc Michael Hanselmann
    """Formats time for Common Log Format.
164 a43f68dc Michael Hanselmann

165 a43f68dc Michael Hanselmann
    All timestamps are logged in the UTC timezone.
166 a43f68dc Michael Hanselmann

167 a43f68dc Michael Hanselmann
    Args:
168 a43f68dc Michael Hanselmann
    - seconds: Time in seconds since the epoch
169 a43f68dc Michael Hanselmann

170 a43f68dc Michael Hanselmann
    """
171 a43f68dc Michael Hanselmann
    (_, month, _, _, _, _, _, _, _) = tm = time.gmtime(seconds)
172 42242313 Michael Hanselmann
    format = "%d/" + MONTHNAME[month] + "/%Y:%H:%M:%S +0000"
173 a43f68dc Michael Hanselmann
    return time.strftime(format, tm)
174 a43f68dc Michael Hanselmann
175 a43f68dc Michael Hanselmann
176 a43f68dc Michael Hanselmann
class HTTPJsonConverter:
177 a43f68dc Michael Hanselmann
  CONTENT_TYPE = "application/json"
178 a43f68dc Michael Hanselmann
179 a43f68dc Michael Hanselmann
  def Encode(self, data):
180 a43f68dc Michael Hanselmann
    return serializer.DumpJson(data)
181 a43f68dc Michael Hanselmann
182 a43f68dc Michael Hanselmann
  def Decode(self, data):
183 a43f68dc Michael Hanselmann
    return serializer.LoadJson(data)
184 a43f68dc Michael Hanselmann
185 a43f68dc Michael Hanselmann
186 42242313 Michael Hanselmann
class _HttpConnectionHandler(object):
187 42242313 Michael Hanselmann
  """Implements server side of HTTP
188 42242313 Michael Hanselmann

189 42242313 Michael Hanselmann
  This class implements the server side of HTTP. It's based on code of Python's
190 42242313 Michael Hanselmann
  BaseHTTPServer, from both version 2.4 and 3k. It does not support non-ASCII
191 42242313 Michael Hanselmann
  character encodings. Keep-alive connections are not supported.
192 42242313 Michael Hanselmann

193 42242313 Michael Hanselmann
  """
194 42242313 Michael Hanselmann
  # String for "Server" header
195 42242313 Michael Hanselmann
  server_version = "Ganeti %s" % constants.RELEASE_VERSION
196 42242313 Michael Hanselmann
197 42242313 Michael Hanselmann
  # The default request version.  This only affects responses up until
198 42242313 Michael Hanselmann
  # the point where the request line is parsed, so it mainly decides what
199 42242313 Michael Hanselmann
  # the client gets back when sending a malformed request line.
200 42242313 Michael Hanselmann
  # Most web servers default to HTTP 0.9, i.e. don't send a status line.
201 42242313 Michael Hanselmann
  default_request_version = HTTP_0_9
202 42242313 Michael Hanselmann
203 42242313 Michael Hanselmann
  # Error message settings
204 42242313 Michael Hanselmann
  error_message_format = DEFAULT_ERROR_MESSAGE
205 42242313 Michael Hanselmann
  error_content_type = DEFAULT_ERROR_CONTENT_TYPE
206 42242313 Michael Hanselmann
207 42242313 Michael Hanselmann
  responses = BaseHTTPServer.BaseHTTPRequestHandler.responses
208 42242313 Michael Hanselmann
209 42242313 Michael Hanselmann
  def __init__(self, server, conn, client_addr, fileio_class):
210 42242313 Michael Hanselmann
    """Initializes this class.
211 42242313 Michael Hanselmann

212 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
213 42242313 Michael Hanselmann
    data sent by the client.
214 42242313 Michael Hanselmann

215 42242313 Michael Hanselmann
    """
216 42242313 Michael Hanselmann
    self._server = server
217 42242313 Michael Hanselmann
218 42242313 Michael Hanselmann
    # We default rfile to buffered because otherwise it could be
219 42242313 Michael Hanselmann
    # really slow for large data (a getc() call per byte); we make
220 42242313 Michael Hanselmann
    # wfile unbuffered because (a) often after a write() we want to
221 42242313 Michael Hanselmann
    # read and we need to flush the line; (b) big writes to unbuffered
222 42242313 Michael Hanselmann
    # files are typically optimized by stdio even when big reads
223 42242313 Michael Hanselmann
    # aren't.
224 42242313 Michael Hanselmann
    self.rfile = fileio_class(conn, mode="rb", bufsize=-1)
225 42242313 Michael Hanselmann
    self.wfile = fileio_class(conn, mode="wb", bufsize=0)
226 42242313 Michael Hanselmann
227 42242313 Michael Hanselmann
    self.client_addr = client_addr
228 42242313 Michael Hanselmann
229 42242313 Michael Hanselmann
    self.request_headers = None
230 42242313 Michael Hanselmann
    self.request_method = None
231 42242313 Michael Hanselmann
    self.request_path = None
232 42242313 Michael Hanselmann
    self.request_requestline = None
233 42242313 Michael Hanselmann
    self.request_version = self.default_request_version
234 42242313 Michael Hanselmann
235 42242313 Michael Hanselmann
    self.response_body = None
236 42242313 Michael Hanselmann
    self.response_code = HTTP_OK
237 42242313 Michael Hanselmann
    self.response_content_type = None
238 713faea6 Oleksiy Mishchenko
    self.response_headers = {}
239 42242313 Michael Hanselmann
240 42242313 Michael Hanselmann
    self.should_fork = False
241 42242313 Michael Hanselmann
242 42242313 Michael Hanselmann
    try:
243 42242313 Michael Hanselmann
      self._ReadRequest()
244 42242313 Michael Hanselmann
      self._ReadPostData()
245 42242313 Michael Hanselmann
246 42242313 Michael Hanselmann
      self.should_fork = self._server.ForkForRequest(self)
247 42242313 Michael Hanselmann
    except HTTPException, err:
248 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
249 42242313 Michael Hanselmann
250 42242313 Michael Hanselmann
  def Close(self):
251 42242313 Michael Hanselmann
    if not self.wfile.closed:
252 42242313 Michael Hanselmann
      self.wfile.flush()
253 42242313 Michael Hanselmann
    self.wfile.close()
254 42242313 Michael Hanselmann
    self.rfile.close()
255 42242313 Michael Hanselmann
256 42242313 Michael Hanselmann
  def _DateTimeHeader(self):
257 42242313 Michael Hanselmann
    """Return the current date and time formatted for a message header.
258 42242313 Michael Hanselmann

259 42242313 Michael Hanselmann
    """
260 42242313 Michael Hanselmann
    (year, month, day, hh, mm, ss, wd, _, _) = time.gmtime()
261 42242313 Michael Hanselmann
    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
262 42242313 Michael Hanselmann
            (WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
263 42242313 Michael Hanselmann
264 42242313 Michael Hanselmann
  def _SetErrorStatus(self, err):
265 42242313 Michael Hanselmann
    """Sets the response code and body from a HTTPException.
266 42242313 Michael Hanselmann

267 42242313 Michael Hanselmann
    @type err: HTTPException
268 42242313 Michael Hanselmann
    @param err: Exception instance
269 42242313 Michael Hanselmann

270 42242313 Michael Hanselmann
    """
271 42242313 Michael Hanselmann
    try:
272 42242313 Michael Hanselmann
      (shortmsg, longmsg) = self.responses[err.code]
273 42242313 Michael Hanselmann
    except KeyError:
274 42242313 Michael Hanselmann
      shortmsg = longmsg = "Unknown"
275 42242313 Michael Hanselmann
276 42242313 Michael Hanselmann
    if err.message:
277 42242313 Michael Hanselmann
      message = err.message
278 42242313 Michael Hanselmann
    else:
279 42242313 Michael Hanselmann
      message = shortmsg
280 42242313 Michael Hanselmann
281 42242313 Michael Hanselmann
    values = {
282 42242313 Michael Hanselmann
      "code": err.code,
283 42242313 Michael Hanselmann
      "message": cgi.escape(message),
284 42242313 Michael Hanselmann
      "explain": longmsg,
285 42242313 Michael Hanselmann
      }
286 42242313 Michael Hanselmann
287 42242313 Michael Hanselmann
    self.response_code = err.code
288 42242313 Michael Hanselmann
    self.response_content_type = self.error_content_type
289 42242313 Michael Hanselmann
    self.response_body = self.error_message_format % values
290 42242313 Michael Hanselmann
291 42242313 Michael Hanselmann
  def HandleRequest(self):
292 42242313 Michael Hanselmann
    """Handle the actual request.
293 42242313 Michael Hanselmann

294 42242313 Michael Hanselmann
    Calls the actual handler function and converts exceptions into HTTP errors.
295 42242313 Michael Hanselmann

296 42242313 Michael Hanselmann
    """
297 42242313 Michael Hanselmann
    # Don't do anything if there's already been a problem
298 42242313 Michael Hanselmann
    if self.response_code != HTTP_OK:
299 42242313 Michael Hanselmann
      return
300 42242313 Michael Hanselmann
301 42242313 Michael Hanselmann
    assert self.request_method, "Status code %s requires a method" % HTTP_OK
302 42242313 Michael Hanselmann
303 42242313 Michael Hanselmann
    # Check whether client is still there
304 42242313 Michael Hanselmann
    self.rfile.read(0)
305 42242313 Michael Hanselmann
306 42242313 Michael Hanselmann
    try:
307 42242313 Michael Hanselmann
      try:
308 42242313 Michael Hanselmann
        result = self._server.HandleRequest(self)
309 42242313 Michael Hanselmann
310 42242313 Michael Hanselmann
        # TODO: Content-type
311 42242313 Michael Hanselmann
        encoder = HTTPJsonConverter()
312 42242313 Michael Hanselmann
        body = encoder.Encode(result)
313 42242313 Michael Hanselmann
314 42242313 Michael Hanselmann
        self.response_content_type = encoder.CONTENT_TYPE
315 42242313 Michael Hanselmann
        self.response_body = body
316 42242313 Michael Hanselmann
      except (HTTPException, KeyboardInterrupt, SystemExit):
317 42242313 Michael Hanselmann
        raise
318 42242313 Michael Hanselmann
      except Exception, err:
319 42242313 Michael Hanselmann
        logging.exception("Caught exception")
320 42242313 Michael Hanselmann
        raise HTTPInternalError(message=str(err))
321 42242313 Michael Hanselmann
      except:
322 42242313 Michael Hanselmann
        logging.exception("Unknown exception")
323 42242313 Michael Hanselmann
        raise HTTPInternalError(message="Unknown error")
324 42242313 Michael Hanselmann
325 42242313 Michael Hanselmann
    except HTTPException, err:
326 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
327 42242313 Michael Hanselmann
328 42242313 Michael Hanselmann
  def SendResponse(self):
329 42242313 Michael Hanselmann
    """Sends response to the client.
330 42242313 Michael Hanselmann

331 42242313 Michael Hanselmann
    """
332 42242313 Michael Hanselmann
    # Check whether client is still there
333 42242313 Michael Hanselmann
    self.rfile.read(0)
334 42242313 Michael Hanselmann
335 42242313 Michael Hanselmann
    logging.info("%s:%s %s %s", self.client_addr[0], self.client_addr[1],
336 42242313 Michael Hanselmann
                 self.request_requestline, self.response_code)
337 42242313 Michael Hanselmann
338 42242313 Michael Hanselmann
    if self.response_code in self.responses:
339 42242313 Michael Hanselmann
      response_message = self.responses[self.response_code][0]
340 42242313 Michael Hanselmann
    else:
341 42242313 Michael Hanselmann
      response_message = ""
342 42242313 Michael Hanselmann
343 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
344 42242313 Michael Hanselmann
      self.wfile.write("%s %d %s\r\n" %
345 42242313 Michael Hanselmann
                       (self.request_version, self.response_code,
346 42242313 Michael Hanselmann
                        response_message))
347 42242313 Michael Hanselmann
      self._SendHeader("Server", self.server_version)
348 42242313 Michael Hanselmann
      self._SendHeader("Date", self._DateTimeHeader())
349 42242313 Michael Hanselmann
      self._SendHeader("Content-Type", self.response_content_type)
350 42242313 Michael Hanselmann
      self._SendHeader("Content-Length", str(len(self.response_body)))
351 713faea6 Oleksiy Mishchenko
      for key, val in self.response_headers.iteritems():
352 713faea6 Oleksiy Mishchenko
        self._SendHeader(key, val)
353 713faea6 Oleksiy Mishchenko
354 42242313 Michael Hanselmann
      # We don't support keep-alive at this time
355 42242313 Michael Hanselmann
      self._SendHeader("Connection", "close")
356 42242313 Michael Hanselmann
      self.wfile.write("\r\n")
357 42242313 Michael Hanselmann
358 42242313 Michael Hanselmann
    if (self.request_method != HTTP_HEAD and
359 42242313 Michael Hanselmann
        self.response_code >= HTTP_OK and
360 42242313 Michael Hanselmann
        self.response_code not in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED)):
361 42242313 Michael Hanselmann
      self.wfile.write(self.response_body)
362 42242313 Michael Hanselmann
363 42242313 Michael Hanselmann
  def _SendHeader(self, name, value):
364 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
365 42242313 Michael Hanselmann
      self.wfile.write("%s: %s\r\n" % (name, value))
366 42242313 Michael Hanselmann
367 42242313 Michael Hanselmann
  def _ReadRequest(self):
368 42242313 Michael Hanselmann
    """Reads and parses request line
369 42242313 Michael Hanselmann

370 42242313 Michael Hanselmann
    """
371 42242313 Michael Hanselmann
    raw_requestline = self.rfile.readline()
372 42242313 Michael Hanselmann
373 42242313 Michael Hanselmann
    requestline = raw_requestline
374 42242313 Michael Hanselmann
    if requestline[-2:] == '\r\n':
375 42242313 Michael Hanselmann
      requestline = requestline[:-2]
376 42242313 Michael Hanselmann
    elif requestline[-1:] == '\n':
377 42242313 Michael Hanselmann
      requestline = requestline[:-1]
378 42242313 Michael Hanselmann
379 42242313 Michael Hanselmann
    if not requestline:
380 42242313 Michael Hanselmann
      raise HTTPBadRequest("Empty request line")
381 42242313 Michael Hanselmann
382 42242313 Michael Hanselmann
    self.request_requestline = requestline
383 42242313 Michael Hanselmann
384 42242313 Michael Hanselmann
    logging.debug("HTTP request: %s", raw_requestline.rstrip("\r\n"))
385 42242313 Michael Hanselmann
386 42242313 Michael Hanselmann
    words = requestline.split()
387 42242313 Michael Hanselmann
388 42242313 Michael Hanselmann
    if len(words) == 3:
389 42242313 Michael Hanselmann
      [method, path, version] = words
390 42242313 Michael Hanselmann
      if version[:5] != 'HTTP/':
391 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
392 42242313 Michael Hanselmann
393 42242313 Michael Hanselmann
      try:
394 42242313 Michael Hanselmann
        base_version_number = version.split('/', 1)[1]
395 42242313 Michael Hanselmann
        version_number = base_version_number.split(".")
396 42242313 Michael Hanselmann
397 42242313 Michael Hanselmann
        # RFC 2145 section 3.1 says there can be only one "." and
398 42242313 Michael Hanselmann
        #   - major and minor numbers MUST be treated as
399 42242313 Michael Hanselmann
        #      separate integers;
400 42242313 Michael Hanselmann
        #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
401 42242313 Michael Hanselmann
        #      turn is lower than HTTP/12.3;
402 42242313 Michael Hanselmann
        #   - Leading zeros MUST be ignored by recipients.
403 42242313 Michael Hanselmann
        if len(version_number) != 2:
404 42242313 Michael Hanselmann
          raise HTTPBadRequest("Bad request version (%r)" % version)
405 42242313 Michael Hanselmann
406 42242313 Michael Hanselmann
        version_number = int(version_number[0]), int(version_number[1])
407 42242313 Michael Hanselmann
      except (ValueError, IndexError):
408 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
409 42242313 Michael Hanselmann
410 42242313 Michael Hanselmann
      if version_number >= (2, 0):
411 42242313 Michael Hanselmann
        raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
412 42242313 Michael Hanselmann
                                      base_version_number)
413 42242313 Michael Hanselmann
414 42242313 Michael Hanselmann
    elif len(words) == 2:
415 42242313 Michael Hanselmann
      version = HTTP_0_9
416 42242313 Michael Hanselmann
      [method, path] = words
417 42242313 Michael Hanselmann
      if method != HTTP_GET:
418 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
419 42242313 Michael Hanselmann
420 42242313 Michael Hanselmann
    else:
421 42242313 Michael Hanselmann
      raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
422 42242313 Michael Hanselmann
423 42242313 Michael Hanselmann
    # Examine the headers and look for a Connection directive
424 42242313 Michael Hanselmann
    headers = mimetools.Message(self.rfile, 0)
425 42242313 Michael Hanselmann
426 42242313 Michael Hanselmann
    self.request_method = method
427 42242313 Michael Hanselmann
    self.request_path = path
428 42242313 Michael Hanselmann
    self.request_version = version
429 42242313 Michael Hanselmann
    self.request_headers = headers
430 42242313 Michael Hanselmann
431 42242313 Michael Hanselmann
  def _ReadPostData(self):
432 42242313 Michael Hanselmann
    """Reads POST/PUT data
433 42242313 Michael Hanselmann

434 42242313 Michael Hanselmann
    """
435 42242313 Michael Hanselmann
    if not self.request_method or self.request_method.upper() not in ("POST", "PUT"):
436 42242313 Michael Hanselmann
      self.request_post_data = None
437 42242313 Michael Hanselmann
      return
438 42242313 Michael Hanselmann
439 42242313 Michael Hanselmann
    # TODO: Decide what to do when Content-Length header was not sent
440 42242313 Michael Hanselmann
    try:
441 42242313 Michael Hanselmann
      content_length = int(self.request_headers.get('Content-Length', 0))
442 42242313 Michael Hanselmann
    except ValueError:
443 42242313 Michael Hanselmann
      raise HTTPBadRequest("No Content-Length header or invalid format")
444 42242313 Michael Hanselmann
445 42242313 Michael Hanselmann
    data = self.rfile.read(content_length)
446 42242313 Michael Hanselmann
447 42242313 Michael Hanselmann
    # TODO: Content-type, error handling
448 42242313 Michael Hanselmann
    self.request_post_data = HTTPJsonConverter().Decode(data)
449 42242313 Michael Hanselmann
450 42242313 Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.request_post_data)
451 42242313 Michael Hanselmann
452 42242313 Michael Hanselmann
453 42242313 Michael Hanselmann
class HttpServer(object):
454 42242313 Michael Hanselmann
  """Generic HTTP server class
455 42242313 Michael Hanselmann

456 42242313 Michael Hanselmann
  Users of this class must subclass it and override the HandleRequest function.
457 42242313 Michael Hanselmann
  Optionally, the ForkForRequest function can be overriden.
458 42242313 Michael Hanselmann

459 42242313 Michael Hanselmann
  """
460 42242313 Michael Hanselmann
  MAX_CHILDREN = 20
461 42242313 Michael Hanselmann
462 42242313 Michael Hanselmann
  def __init__(self, mainloop, server_address):
463 42242313 Michael Hanselmann
    self.mainloop = mainloop
464 42242313 Michael Hanselmann
    self.server_address = server_address
465 42242313 Michael Hanselmann
466 42242313 Michael Hanselmann
    # TODO: SSL support
467 42242313 Michael Hanselmann
    self.ssl_cert = None
468 42242313 Michael Hanselmann
    self.ssl_key = self.ssl_cert
469 42242313 Michael Hanselmann
470 42242313 Michael Hanselmann
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
471 42242313 Michael Hanselmann
472 42242313 Michael Hanselmann
    if self.ssl_cert and self.ssl_key:
473 42242313 Michael Hanselmann
      ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
474 42242313 Michael Hanselmann
      ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
475 42242313 Michael Hanselmann
476 42242313 Michael Hanselmann
      ctx.use_certificate_file(self.ssl_cert)
477 42242313 Michael Hanselmann
      ctx.use_privatekey_file(self.ssl_key)
478 42242313 Michael Hanselmann
479 42242313 Michael Hanselmann
      self.socket = OpenSSL.SSL.Connection(ctx, sock)
480 42242313 Michael Hanselmann
      self._fileio_class = _SSLFileObject
481 42242313 Michael Hanselmann
    else:
482 42242313 Michael Hanselmann
      self.socket = sock
483 42242313 Michael Hanselmann
      self._fileio_class = socket._fileobject
484 42242313 Michael Hanselmann
485 42242313 Michael Hanselmann
    # Allow port to be reused
486 42242313 Michael Hanselmann
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
487 42242313 Michael Hanselmann
488 42242313 Michael Hanselmann
    self._children = []
489 42242313 Michael Hanselmann
490 42242313 Michael Hanselmann
    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
491 42242313 Michael Hanselmann
    mainloop.RegisterSignal(self)
492 42242313 Michael Hanselmann
493 42242313 Michael Hanselmann
  def Start(self):
494 42242313 Michael Hanselmann
    self.socket.bind(self.server_address)
495 42242313 Michael Hanselmann
    self.socket.listen(5)
496 42242313 Michael Hanselmann
497 42242313 Michael Hanselmann
  def Stop(self):
498 42242313 Michael Hanselmann
    self.socket.close()
499 42242313 Michael Hanselmann
500 42242313 Michael Hanselmann
  def OnIO(self, fd, condition):
501 42242313 Michael Hanselmann
    if condition & select.POLLIN:
502 42242313 Michael Hanselmann
      self._IncomingConnection()
503 42242313 Michael Hanselmann
504 42242313 Michael Hanselmann
  def OnSignal(self, signum):
505 42242313 Michael Hanselmann
    if signum == signal.SIGCHLD:
506 42242313 Michael Hanselmann
      self._CollectChildren(True)
507 42242313 Michael Hanselmann
508 42242313 Michael Hanselmann
  def _CollectChildren(self, quick):
509 42242313 Michael Hanselmann
    """Checks whether any child processes are done
510 42242313 Michael Hanselmann

511 42242313 Michael Hanselmann
    @type quick: bool
512 42242313 Michael Hanselmann
    @param quick: Whether to only use non-blocking functions
513 42242313 Michael Hanselmann

514 42242313 Michael Hanselmann
    """
515 42242313 Michael Hanselmann
    if not quick:
516 42242313 Michael Hanselmann
      # Don't wait for other processes if it should be a quick check
517 42242313 Michael Hanselmann
      while len(self._children) > self.MAX_CHILDREN:
518 42242313 Michael Hanselmann
        try:
519 42242313 Michael Hanselmann
          pid, status = os.waitpid(0, 0)
520 42242313 Michael Hanselmann
        except os.error:
521 42242313 Michael Hanselmann
          pid = None
522 42242313 Michael Hanselmann
        if pid and pid in self._children:
523 42242313 Michael Hanselmann
          self._children.remove(pid)
524 42242313 Michael Hanselmann
525 42242313 Michael Hanselmann
    for child in self._children:
526 42242313 Michael Hanselmann
      try:
527 42242313 Michael Hanselmann
        pid, status = os.waitpid(child, os.WNOHANG)
528 42242313 Michael Hanselmann
      except os.error:
529 42242313 Michael Hanselmann
        pid = None
530 42242313 Michael Hanselmann
      if pid and pid in self._children:
531 42242313 Michael Hanselmann
        self._children.remove(pid)
532 42242313 Michael Hanselmann
533 42242313 Michael Hanselmann
  def _IncomingConnection(self):
534 42242313 Michael Hanselmann
    connection, client_addr = self.socket.accept()
535 42242313 Michael Hanselmann
    logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
536 42242313 Michael Hanselmann
    try:
537 42242313 Michael Hanselmann
      handler = _HttpConnectionHandler(self, connection, client_addr, self._fileio_class)
538 42242313 Michael Hanselmann
    except (socket.error, SocketClosed):
539 42242313 Michael Hanselmann
      return
540 42242313 Michael Hanselmann
541 42242313 Michael Hanselmann
    def FinishRequest():
542 42242313 Michael Hanselmann
      try:
543 42242313 Michael Hanselmann
        try:
544 42242313 Michael Hanselmann
          try:
545 42242313 Michael Hanselmann
            handler.HandleRequest()
546 42242313 Michael Hanselmann
          finally:
547 42242313 Michael Hanselmann
            # Try to send a response
548 42242313 Michael Hanselmann
            handler.SendResponse()
549 42242313 Michael Hanselmann
            handler.Close()
550 42242313 Michael Hanselmann
        except SocketClosed:
551 42242313 Michael Hanselmann
          pass
552 42242313 Michael Hanselmann
      finally:
553 42242313 Michael Hanselmann
        logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
554 42242313 Michael Hanselmann
555 42242313 Michael Hanselmann
    # Check whether we should fork or not
556 42242313 Michael Hanselmann
    if not handler.should_fork:
557 42242313 Michael Hanselmann
      FinishRequest()
558 42242313 Michael Hanselmann
      return
559 42242313 Michael Hanselmann
560 42242313 Michael Hanselmann
    self._CollectChildren(False)
561 42242313 Michael Hanselmann
562 42242313 Michael Hanselmann
    pid = os.fork()
563 42242313 Michael Hanselmann
    if pid == 0:
564 42242313 Michael Hanselmann
      # Child process
565 42242313 Michael Hanselmann
      try:
566 42242313 Michael Hanselmann
        FinishRequest()
567 42242313 Michael Hanselmann
      except:
568 42242313 Michael Hanselmann
        logging.exception("Error while handling request from %s:%s",
569 42242313 Michael Hanselmann
                          client_addr[0], client_addr[1])
570 42242313 Michael Hanselmann
        os._exit(1)
571 42242313 Michael Hanselmann
      os._exit(0)
572 42242313 Michael Hanselmann
    else:
573 42242313 Michael Hanselmann
      self._children.append(pid)
574 42242313 Michael Hanselmann
575 42242313 Michael Hanselmann
  def HandleRequest(self, req):
576 42242313 Michael Hanselmann
    raise NotImplementedError()
577 42242313 Michael Hanselmann
578 42242313 Michael Hanselmann
  def ForkForRequest(self, req):
579 42242313 Michael Hanselmann
    return True
580 42242313 Michael Hanselmann
581 42242313 Michael Hanselmann
582 42242313 Michael Hanselmann
class _SSLFileObject(object):
583 42242313 Michael Hanselmann
  """Wrapper around socket._fileobject
584 42242313 Michael Hanselmann

585 42242313 Michael Hanselmann
  This wrapper is required to handle OpenSSL exceptions.
586 42242313 Michael Hanselmann

587 42242313 Michael Hanselmann
  """
588 42242313 Michael Hanselmann
  def _RequireOpenSocket(fn):
589 42242313 Michael Hanselmann
    def wrapper(self, *args, **kwargs):
590 42242313 Michael Hanselmann
      if self.closed:
591 42242313 Michael Hanselmann
        raise SocketClosed("Socket is closed")
592 42242313 Michael Hanselmann
      return fn(self, *args, **kwargs)
593 42242313 Michael Hanselmann
    return wrapper
594 42242313 Michael Hanselmann
595 42242313 Michael Hanselmann
  def __init__(self, sock, mode='rb', bufsize=-1):
596 42242313 Michael Hanselmann
    self._base = socket._fileobject(sock, mode=mode, bufsize=bufsize)
597 42242313 Michael Hanselmann
598 42242313 Michael Hanselmann
  def _ConnectionLost(self):
599 42242313 Michael Hanselmann
    self._base = None
600 42242313 Michael Hanselmann
601 42242313 Michael Hanselmann
  def _getclosed(self):
602 42242313 Michael Hanselmann
    return self._base is None or self._base.closed
603 42242313 Michael Hanselmann
  closed = property(_getclosed, doc="True if the file is closed")
604 42242313 Michael Hanselmann
605 42242313 Michael Hanselmann
  @_RequireOpenSocket
606 42242313 Michael Hanselmann
  def close(self):
607 42242313 Michael Hanselmann
    return self._base.close()
608 42242313 Michael Hanselmann
609 42242313 Michael Hanselmann
  @_RequireOpenSocket
610 42242313 Michael Hanselmann
  def flush(self):
611 42242313 Michael Hanselmann
    return self._base.flush()
612 42242313 Michael Hanselmann
613 42242313 Michael Hanselmann
  @_RequireOpenSocket
614 42242313 Michael Hanselmann
  def fileno(self):
615 42242313 Michael Hanselmann
    return self._base.fileno()
616 42242313 Michael Hanselmann
617 42242313 Michael Hanselmann
  @_RequireOpenSocket
618 42242313 Michael Hanselmann
  def read(self, size=-1):
619 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.read, size=size)
620 42242313 Michael Hanselmann
621 42242313 Michael Hanselmann
  @_RequireOpenSocket
622 42242313 Michael Hanselmann
  def readline(self, size=-1):
623 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.readline, size=size)
624 42242313 Michael Hanselmann
625 42242313 Michael Hanselmann
  def _ReadWrapper(self, fn, *args, **kwargs):
626 42242313 Michael Hanselmann
    while True:
627 42242313 Michael Hanselmann
      try:
628 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
629 42242313 Michael Hanselmann
630 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
631 42242313 Michael Hanselmann
        self._ConnectionLost()
632 42242313 Michael Hanselmann
        return ""
633 42242313 Michael Hanselmann
634 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantReadError:
635 42242313 Michael Hanselmann
        continue
636 42242313 Michael Hanselmann
637 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantWriteError:
638 42242313 Michael Hanselmann
      # TODO
639 42242313 Michael Hanselmann
640 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, (retval, desc):
641 42242313 Michael Hanselmann
        if ((retval == -1 and desc == "Unexpected EOF")
642 42242313 Michael Hanselmann
            or retval > 0):
643 42242313 Michael Hanselmann
          self._ConnectionLost()
644 42242313 Michael Hanselmann
          return ""
645 42242313 Michael Hanselmann
646 42242313 Michael Hanselmann
        logging.exception("Error in OpenSSL")
647 42242313 Michael Hanselmann
        self._ConnectionLost()
648 42242313 Michael Hanselmann
        raise socket.error(err.args)
649 42242313 Michael Hanselmann
650 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
651 42242313 Michael Hanselmann
        self._ConnectionLost()
652 42242313 Michael Hanselmann
        raise socket.error(err.args)
653 42242313 Michael Hanselmann
654 42242313 Michael Hanselmann
  @_RequireOpenSocket
655 42242313 Michael Hanselmann
  def write(self, data):
656 42242313 Michael Hanselmann
    return self._WriteWrapper(self._base.write, data)
657 42242313 Michael Hanselmann
658 42242313 Michael Hanselmann
  def _WriteWrapper(self, fn, *args, **kwargs):
659 42242313 Michael Hanselmann
    while True:
660 42242313 Michael Hanselmann
      try:
661 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
662 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
663 42242313 Michael Hanselmann
        self._ConnectionLost()
664 42242313 Michael Hanselmann
        return 0
665 42242313 Michael Hanselmann
666 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantWriteError:
667 42242313 Michael Hanselmann
        continue
668 42242313 Michael Hanselmann
669 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantReadError:
670 42242313 Michael Hanselmann
      # TODO
671 42242313 Michael Hanselmann
672 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, err:
673 42242313 Michael Hanselmann
        if err.args[0] == -1 and data == "":
674 42242313 Michael Hanselmann
          # errors when writing empty strings are expected
675 42242313 Michael Hanselmann
          # and can be ignored
676 42242313 Michael Hanselmann
          return 0
677 42242313 Michael Hanselmann
678 42242313 Michael Hanselmann
        self._ConnectionLost()
679 42242313 Michael Hanselmann
        raise socket.error(err.args)
680 42242313 Michael Hanselmann
681 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
682 42242313 Michael Hanselmann
        self._ConnectionLost()
683 42242313 Michael Hanselmann
        raise socket.error(err.args)