Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ 686d7433

History | View | Annotate | Download (21.7 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 42242313 Michael Hanselmann
69 42242313 Michael Hanselmann
70 42242313 Michael Hanselmann
class SocketClosed(socket.error):
71 42242313 Michael Hanselmann
  pass
72 42242313 Michael Hanselmann
73 42242313 Michael Hanselmann
74 a43f68dc Michael Hanselmann
class HTTPException(Exception):
75 a43f68dc Michael Hanselmann
  code = None
76 a43f68dc Michael Hanselmann
  message = None
77 a43f68dc Michael Hanselmann
78 a43f68dc Michael Hanselmann
  def __init__(self, message=None):
79 42242313 Michael Hanselmann
    Exception.__init__(self)
80 a43f68dc Michael Hanselmann
    if message is not None:
81 a43f68dc Michael Hanselmann
      self.message = message
82 a43f68dc Michael Hanselmann
83 a43f68dc Michael Hanselmann
84 a43f68dc Michael Hanselmann
class HTTPBadRequest(HTTPException):
85 a43f68dc Michael Hanselmann
  code = 400
86 a43f68dc Michael Hanselmann
87 a43f68dc Michael Hanselmann
88 a43f68dc Michael Hanselmann
class HTTPForbidden(HTTPException):
89 a43f68dc Michael Hanselmann
  code = 403
90 a43f68dc Michael Hanselmann
91 a43f68dc Michael Hanselmann
92 a43f68dc Michael Hanselmann
class HTTPNotFound(HTTPException):
93 a43f68dc Michael Hanselmann
  code = 404
94 a43f68dc Michael Hanselmann
95 a43f68dc Michael Hanselmann
96 a43f68dc Michael Hanselmann
class HTTPGone(HTTPException):
97 a43f68dc Michael Hanselmann
  code = 410
98 a43f68dc Michael Hanselmann
99 a43f68dc Michael Hanselmann
100 a43f68dc Michael Hanselmann
class HTTPLengthRequired(HTTPException):
101 a43f68dc Michael Hanselmann
  code = 411
102 a43f68dc Michael Hanselmann
103 a43f68dc Michael Hanselmann
104 a43f68dc Michael Hanselmann
class HTTPInternalError(HTTPException):
105 a43f68dc Michael Hanselmann
  code = 500
106 a43f68dc Michael Hanselmann
107 a43f68dc Michael Hanselmann
108 a43f68dc Michael Hanselmann
class HTTPNotImplemented(HTTPException):
109 a43f68dc Michael Hanselmann
  code = 501
110 a43f68dc Michael Hanselmann
111 a43f68dc Michael Hanselmann
112 a43f68dc Michael Hanselmann
class HTTPServiceUnavailable(HTTPException):
113 a43f68dc Michael Hanselmann
  code = 503
114 a43f68dc Michael Hanselmann
115 a43f68dc Michael Hanselmann
116 42242313 Michael Hanselmann
class HTTPVersionNotSupported(HTTPException):
117 42242313 Michael Hanselmann
  code = 505
118 42242313 Michael Hanselmann
119 42242313 Michael Hanselmann
120 a43f68dc Michael Hanselmann
class ApacheLogfile:
121 a43f68dc Michael Hanselmann
  """Utility class to write HTTP server log files.
122 a43f68dc Michael Hanselmann

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

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

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

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

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

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

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

169 a43f68dc Michael Hanselmann
    """
170 a43f68dc Michael Hanselmann
    (_, month, _, _, _, _, _, _, _) = tm = time.gmtime(seconds)
171 42242313 Michael Hanselmann
    format = "%d/" + MONTHNAME[month] + "/%Y:%H:%M:%S +0000"
172 a43f68dc Michael Hanselmann
    return time.strftime(format, tm)
173 a43f68dc Michael Hanselmann
174 a43f68dc Michael Hanselmann
175 a43f68dc Michael Hanselmann
class HTTPServer(BaseHTTPServer.HTTPServer, object):
176 a43f68dc Michael Hanselmann
  """Class to provide an HTTP/HTTPS server.
177 a43f68dc Michael Hanselmann

178 a43f68dc Michael Hanselmann
  """
179 a43f68dc Michael Hanselmann
  allow_reuse_address = True
180 a43f68dc Michael Hanselmann
181 a43f68dc Michael Hanselmann
  def __init__(self, server_address, HandlerClass, httplog=None,
182 a43f68dc Michael Hanselmann
               enable_ssl=False, ssl_key=None, ssl_cert=None):
183 a43f68dc Michael Hanselmann
    """Server constructor.
184 a43f68dc Michael Hanselmann

185 a43f68dc Michael Hanselmann
    Args:
186 a43f68dc Michael Hanselmann
      server_address: a touple containing:
187 a43f68dc Michael Hanselmann
        ip: a string with IP address, localhost if empty string
188 a43f68dc Michael Hanselmann
        port: port number, integer
189 a43f68dc Michael Hanselmann
      HandlerClass: HTTPRequestHandler object
190 a43f68dc Michael Hanselmann
      httplog: Access log object
191 a43f68dc Michael Hanselmann
      enable_ssl: Whether to enable SSL
192 a43f68dc Michael Hanselmann
      ssl_key: SSL key file
193 a43f68dc Michael Hanselmann
      ssl_cert: SSL certificate key
194 a43f68dc Michael Hanselmann

195 a43f68dc Michael Hanselmann
    """
196 a43f68dc Michael Hanselmann
    BaseHTTPServer.HTTPServer.__init__(self, server_address, HandlerClass)
197 a43f68dc Michael Hanselmann
198 a43f68dc Michael Hanselmann
    self.httplog = httplog
199 a43f68dc Michael Hanselmann
200 a43f68dc Michael Hanselmann
    if enable_ssl:
201 a43f68dc Michael Hanselmann
      # Set up SSL
202 a43f68dc Michael Hanselmann
      context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
203 a43f68dc Michael Hanselmann
      context.use_privatekey_file(ssl_key)
204 a43f68dc Michael Hanselmann
      context.use_certificate_file(ssl_cert)
205 a43f68dc Michael Hanselmann
      self.socket = OpenSSL.SSL.Connection(context,
206 a43f68dc Michael Hanselmann
                                           socket.socket(self.address_family,
207 a43f68dc Michael Hanselmann
                                           self.socket_type))
208 a43f68dc Michael Hanselmann
    else:
209 a43f68dc Michael Hanselmann
      self.socket = socket.socket(self.address_family, self.socket_type)
210 a43f68dc Michael Hanselmann
211 a43f68dc Michael Hanselmann
    self.server_bind()
212 a43f68dc Michael Hanselmann
    self.server_activate()
213 a43f68dc Michael Hanselmann
214 a43f68dc Michael Hanselmann
215 a43f68dc Michael Hanselmann
class HTTPJsonConverter:
216 a43f68dc Michael Hanselmann
  CONTENT_TYPE = "application/json"
217 a43f68dc Michael Hanselmann
218 a43f68dc Michael Hanselmann
  def Encode(self, data):
219 a43f68dc Michael Hanselmann
    return serializer.DumpJson(data)
220 a43f68dc Michael Hanselmann
221 a43f68dc Michael Hanselmann
  def Decode(self, data):
222 a43f68dc Michael Hanselmann
    return serializer.LoadJson(data)
223 a43f68dc Michael Hanselmann
224 a43f68dc Michael Hanselmann
225 a43f68dc Michael Hanselmann
class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler, object):
226 a43f68dc Michael Hanselmann
  """Request handler class.
227 a43f68dc Michael Hanselmann

228 a43f68dc Michael Hanselmann
  """
229 a43f68dc Michael Hanselmann
  def setup(self):
230 a43f68dc Michael Hanselmann
    """Setup secure read and write file objects.
231 a43f68dc Michael Hanselmann

232 a43f68dc Michael Hanselmann
    """
233 a43f68dc Michael Hanselmann
    self.connection = self.request
234 a43f68dc Michael Hanselmann
    self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
235 a43f68dc Michael Hanselmann
    self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
236 a43f68dc Michael Hanselmann
237 a43f68dc Michael Hanselmann
  def handle_one_request(self):
238 a43f68dc Michael Hanselmann
    """Parses a request and calls the handler function.
239 a43f68dc Michael Hanselmann

240 a43f68dc Michael Hanselmann
    """
241 a43f68dc Michael Hanselmann
    self.raw_requestline = None
242 a43f68dc Michael Hanselmann
    try:
243 a43f68dc Michael Hanselmann
      self.raw_requestline = self.rfile.readline()
244 a43f68dc Michael Hanselmann
    except OpenSSL.SSL.Error, ex:
245 a43f68dc Michael Hanselmann
      logger.Error("Error in SSL: %s" % str(ex))
246 a43f68dc Michael Hanselmann
    if not self.raw_requestline:
247 a43f68dc Michael Hanselmann
      self.close_connection = 1
248 a43f68dc Michael Hanselmann
      return
249 a43f68dc Michael Hanselmann
    if not self.parse_request(): # An error code has been sent, just exit
250 a43f68dc Michael Hanselmann
      return
251 a43f68dc Michael Hanselmann
    logging.debug("HTTP request: %s", self.raw_requestline.rstrip("\r\n"))
252 a43f68dc Michael Hanselmann
253 a43f68dc Michael Hanselmann
    try:
254 a43f68dc Michael Hanselmann
      self._ReadPostData()
255 a43f68dc Michael Hanselmann
256 a43f68dc Michael Hanselmann
      result = self.HandleRequest()
257 a43f68dc Michael Hanselmann
258 a43f68dc Michael Hanselmann
      # TODO: Content-type
259 a43f68dc Michael Hanselmann
      encoder = HTTPJsonConverter()
260 a43f68dc Michael Hanselmann
      encoded_result = encoder.Encode(result)
261 a43f68dc Michael Hanselmann
262 a43f68dc Michael Hanselmann
      self.send_response(200)
263 a43f68dc Michael Hanselmann
      self.send_header("Content-Type", encoder.CONTENT_TYPE)
264 a43f68dc Michael Hanselmann
      self.send_header("Content-Length", str(len(encoded_result)))
265 a43f68dc Michael Hanselmann
      self.end_headers()
266 a43f68dc Michael Hanselmann
267 a43f68dc Michael Hanselmann
      self.wfile.write(encoded_result)
268 a43f68dc Michael Hanselmann
269 a43f68dc Michael Hanselmann
    except HTTPException, err:
270 a43f68dc Michael Hanselmann
      self.send_error(err.code, message=err.message)
271 a43f68dc Michael Hanselmann
272 a43f68dc Michael Hanselmann
    except Exception, err:
273 a43f68dc Michael Hanselmann
      self.send_error(HTTPInternalError.code, message=str(err))
274 a43f68dc Michael Hanselmann
275 a43f68dc Michael Hanselmann
    except:
276 a43f68dc Michael Hanselmann
      self.send_error(HTTPInternalError.code, message="Unknown error")
277 a43f68dc Michael Hanselmann
278 a43f68dc Michael Hanselmann
  def _ReadPostData(self):
279 a43f68dc Michael Hanselmann
    if self.command.upper() not in ("POST", "PUT"):
280 a43f68dc Michael Hanselmann
      self.post_data = None
281 a43f68dc Michael Hanselmann
      return
282 a43f68dc Michael Hanselmann
283 a43f68dc Michael Hanselmann
    # TODO: Decide what to do when Content-Length header was not sent
284 a43f68dc Michael Hanselmann
    try:
285 a43f68dc Michael Hanselmann
      content_length = int(self.headers.get('Content-Length', 0))
286 a43f68dc Michael Hanselmann
    except ValueError:
287 a43f68dc Michael Hanselmann
      raise HTTPBadRequest("No Content-Length header or invalid format")
288 a43f68dc Michael Hanselmann
289 a43f68dc Michael Hanselmann
    try:
290 a43f68dc Michael Hanselmann
      data = self.rfile.read(content_length)
291 a43f68dc Michael Hanselmann
    except socket.error, err:
292 a43f68dc Michael Hanselmann
      logger.Error("Socket error while reading: %s" % str(err))
293 a43f68dc Michael Hanselmann
      return
294 a43f68dc Michael Hanselmann
295 a43f68dc Michael Hanselmann
    # TODO: Content-type, error handling
296 a43f68dc Michael Hanselmann
    self.post_data = HTTPJsonConverter().Decode(data)
297 a43f68dc Michael Hanselmann
298 a43f68dc Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.post_data)
299 a43f68dc Michael Hanselmann
300 a43f68dc Michael Hanselmann
  def HandleRequest(self):
301 a43f68dc Michael Hanselmann
    """Handles a request.
302 a43f68dc Michael Hanselmann

303 a43f68dc Michael Hanselmann
    """
304 a43f68dc Michael Hanselmann
    raise NotImplementedError()
305 a43f68dc Michael Hanselmann
306 a43f68dc Michael Hanselmann
  def log_message(self, format, *args):
307 a43f68dc Michael Hanselmann
    """Log an arbitrary message.
308 a43f68dc Michael Hanselmann

309 a43f68dc Michael Hanselmann
    This is used by all other logging functions.
310 a43f68dc Michael Hanselmann

311 a43f68dc Michael Hanselmann
    The first argument, FORMAT, is a format string for the
312 a43f68dc Michael Hanselmann
    message to be logged.  If the format string contains
313 a43f68dc Michael Hanselmann
    any % escapes requiring parameters, they should be
314 a43f68dc Michael Hanselmann
    specified as subsequent arguments (it's just like
315 a43f68dc Michael Hanselmann
    printf!).
316 a43f68dc Michael Hanselmann

317 a43f68dc Michael Hanselmann
    """
318 a43f68dc Michael Hanselmann
    logging.debug("Handled request: %s", format % args)
319 a43f68dc Michael Hanselmann
    if self.server.httplog:
320 a43f68dc Michael Hanselmann
      self.server.httplog.LogRequest(self, format, *args)
321 42242313 Michael Hanselmann
322 42242313 Michael Hanselmann
323 42242313 Michael Hanselmann
class _HttpConnectionHandler(object):
324 42242313 Michael Hanselmann
  """Implements server side of HTTP
325 42242313 Michael Hanselmann

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

330 42242313 Michael Hanselmann
  """
331 42242313 Michael Hanselmann
  # String for "Server" header
332 42242313 Michael Hanselmann
  server_version = "Ganeti %s" % constants.RELEASE_VERSION
333 42242313 Michael Hanselmann
334 42242313 Michael Hanselmann
  # The default request version.  This only affects responses up until
335 42242313 Michael Hanselmann
  # the point where the request line is parsed, so it mainly decides what
336 42242313 Michael Hanselmann
  # the client gets back when sending a malformed request line.
337 42242313 Michael Hanselmann
  # Most web servers default to HTTP 0.9, i.e. don't send a status line.
338 42242313 Michael Hanselmann
  default_request_version = HTTP_0_9
339 42242313 Michael Hanselmann
340 42242313 Michael Hanselmann
  # Error message settings
341 42242313 Michael Hanselmann
  error_message_format = DEFAULT_ERROR_MESSAGE
342 42242313 Michael Hanselmann
  error_content_type = DEFAULT_ERROR_CONTENT_TYPE
343 42242313 Michael Hanselmann
344 42242313 Michael Hanselmann
  responses = BaseHTTPServer.BaseHTTPRequestHandler.responses
345 42242313 Michael Hanselmann
346 42242313 Michael Hanselmann
  def __init__(self, server, conn, client_addr, fileio_class):
347 42242313 Michael Hanselmann
    """Initializes this class.
348 42242313 Michael Hanselmann

349 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
350 42242313 Michael Hanselmann
    data sent by the client.
351 42242313 Michael Hanselmann

352 42242313 Michael Hanselmann
    """
353 42242313 Michael Hanselmann
    self._server = server
354 42242313 Michael Hanselmann
355 42242313 Michael Hanselmann
    # We default rfile to buffered because otherwise it could be
356 42242313 Michael Hanselmann
    # really slow for large data (a getc() call per byte); we make
357 42242313 Michael Hanselmann
    # wfile unbuffered because (a) often after a write() we want to
358 42242313 Michael Hanselmann
    # read and we need to flush the line; (b) big writes to unbuffered
359 42242313 Michael Hanselmann
    # files are typically optimized by stdio even when big reads
360 42242313 Michael Hanselmann
    # aren't.
361 42242313 Michael Hanselmann
    self.rfile = fileio_class(conn, mode="rb", bufsize=-1)
362 42242313 Michael Hanselmann
    self.wfile = fileio_class(conn, mode="wb", bufsize=0)
363 42242313 Michael Hanselmann
364 42242313 Michael Hanselmann
    self.client_addr = client_addr
365 42242313 Michael Hanselmann
366 42242313 Michael Hanselmann
    self.request_headers = None
367 42242313 Michael Hanselmann
    self.request_method = None
368 42242313 Michael Hanselmann
    self.request_path = None
369 42242313 Michael Hanselmann
    self.request_requestline = None
370 42242313 Michael Hanselmann
    self.request_version = self.default_request_version
371 42242313 Michael Hanselmann
372 42242313 Michael Hanselmann
    self.response_body = None
373 42242313 Michael Hanselmann
    self.response_code = HTTP_OK
374 42242313 Michael Hanselmann
    self.response_content_type = None
375 42242313 Michael Hanselmann
376 42242313 Michael Hanselmann
    self.should_fork = False
377 42242313 Michael Hanselmann
378 42242313 Michael Hanselmann
    try:
379 42242313 Michael Hanselmann
      self._ReadRequest()
380 42242313 Michael Hanselmann
      self._ReadPostData()
381 42242313 Michael Hanselmann
382 42242313 Michael Hanselmann
      self.should_fork = self._server.ForkForRequest(self)
383 42242313 Michael Hanselmann
    except HTTPException, err:
384 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
385 42242313 Michael Hanselmann
386 42242313 Michael Hanselmann
  def Close(self):
387 42242313 Michael Hanselmann
    if not self.wfile.closed:
388 42242313 Michael Hanselmann
      self.wfile.flush()
389 42242313 Michael Hanselmann
    self.wfile.close()
390 42242313 Michael Hanselmann
    self.rfile.close()
391 42242313 Michael Hanselmann
392 42242313 Michael Hanselmann
  def _DateTimeHeader(self):
393 42242313 Michael Hanselmann
    """Return the current date and time formatted for a message header.
394 42242313 Michael Hanselmann

395 42242313 Michael Hanselmann
    """
396 42242313 Michael Hanselmann
    (year, month, day, hh, mm, ss, wd, _, _) = time.gmtime()
397 42242313 Michael Hanselmann
    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
398 42242313 Michael Hanselmann
            (WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
399 42242313 Michael Hanselmann
400 42242313 Michael Hanselmann
  def _SetErrorStatus(self, err):
401 42242313 Michael Hanselmann
    """Sets the response code and body from a HTTPException.
402 42242313 Michael Hanselmann

403 42242313 Michael Hanselmann
    @type err: HTTPException
404 42242313 Michael Hanselmann
    @param err: Exception instance
405 42242313 Michael Hanselmann

406 42242313 Michael Hanselmann
    """
407 42242313 Michael Hanselmann
    try:
408 42242313 Michael Hanselmann
      (shortmsg, longmsg) = self.responses[err.code]
409 42242313 Michael Hanselmann
    except KeyError:
410 42242313 Michael Hanselmann
      shortmsg = longmsg = "Unknown"
411 42242313 Michael Hanselmann
412 42242313 Michael Hanselmann
    if err.message:
413 42242313 Michael Hanselmann
      message = err.message
414 42242313 Michael Hanselmann
    else:
415 42242313 Michael Hanselmann
      message = shortmsg
416 42242313 Michael Hanselmann
417 42242313 Michael Hanselmann
    values = {
418 42242313 Michael Hanselmann
      "code": err.code,
419 42242313 Michael Hanselmann
      "message": cgi.escape(message),
420 42242313 Michael Hanselmann
      "explain": longmsg,
421 42242313 Michael Hanselmann
      }
422 42242313 Michael Hanselmann
423 42242313 Michael Hanselmann
    self.response_code = err.code
424 42242313 Michael Hanselmann
    self.response_content_type = self.error_content_type
425 42242313 Michael Hanselmann
    self.response_body = self.error_message_format % values
426 42242313 Michael Hanselmann
427 42242313 Michael Hanselmann
  def HandleRequest(self):
428 42242313 Michael Hanselmann
    """Handle the actual request.
429 42242313 Michael Hanselmann

430 42242313 Michael Hanselmann
    Calls the actual handler function and converts exceptions into HTTP errors.
431 42242313 Michael Hanselmann

432 42242313 Michael Hanselmann
    """
433 42242313 Michael Hanselmann
    # Don't do anything if there's already been a problem
434 42242313 Michael Hanselmann
    if self.response_code != HTTP_OK:
435 42242313 Michael Hanselmann
      return
436 42242313 Michael Hanselmann
437 42242313 Michael Hanselmann
    assert self.request_method, "Status code %s requires a method" % HTTP_OK
438 42242313 Michael Hanselmann
439 42242313 Michael Hanselmann
    # Check whether client is still there
440 42242313 Michael Hanselmann
    self.rfile.read(0)
441 42242313 Michael Hanselmann
442 42242313 Michael Hanselmann
    try:
443 42242313 Michael Hanselmann
      try:
444 42242313 Michael Hanselmann
        result = self._server.HandleRequest(self)
445 42242313 Michael Hanselmann
446 42242313 Michael Hanselmann
        # TODO: Content-type
447 42242313 Michael Hanselmann
        encoder = HTTPJsonConverter()
448 42242313 Michael Hanselmann
        body = encoder.Encode(result)
449 42242313 Michael Hanselmann
450 42242313 Michael Hanselmann
        self.response_content_type = encoder.CONTENT_TYPE
451 42242313 Michael Hanselmann
        self.response_body = body
452 42242313 Michael Hanselmann
      except (HTTPException, KeyboardInterrupt, SystemExit):
453 42242313 Michael Hanselmann
        raise
454 42242313 Michael Hanselmann
      except Exception, err:
455 42242313 Michael Hanselmann
        logging.exception("Caught exception")
456 42242313 Michael Hanselmann
        raise HTTPInternalError(message=str(err))
457 42242313 Michael Hanselmann
      except:
458 42242313 Michael Hanselmann
        logging.exception("Unknown exception")
459 42242313 Michael Hanselmann
        raise HTTPInternalError(message="Unknown error")
460 42242313 Michael Hanselmann
461 42242313 Michael Hanselmann
    except HTTPException, err:
462 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
463 42242313 Michael Hanselmann
464 42242313 Michael Hanselmann
  def SendResponse(self):
465 42242313 Michael Hanselmann
    """Sends response to the client.
466 42242313 Michael Hanselmann

467 42242313 Michael Hanselmann
    """
468 42242313 Michael Hanselmann
    # Check whether client is still there
469 42242313 Michael Hanselmann
    self.rfile.read(0)
470 42242313 Michael Hanselmann
471 42242313 Michael Hanselmann
    logging.info("%s:%s %s %s", self.client_addr[0], self.client_addr[1],
472 42242313 Michael Hanselmann
                 self.request_requestline, self.response_code)
473 42242313 Michael Hanselmann
474 42242313 Michael Hanselmann
    if self.response_code in self.responses:
475 42242313 Michael Hanselmann
      response_message = self.responses[self.response_code][0]
476 42242313 Michael Hanselmann
    else:
477 42242313 Michael Hanselmann
      response_message = ""
478 42242313 Michael Hanselmann
479 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
480 42242313 Michael Hanselmann
      self.wfile.write("%s %d %s\r\n" %
481 42242313 Michael Hanselmann
                       (self.request_version, self.response_code,
482 42242313 Michael Hanselmann
                        response_message))
483 42242313 Michael Hanselmann
      self._SendHeader("Server", self.server_version)
484 42242313 Michael Hanselmann
      self._SendHeader("Date", self._DateTimeHeader())
485 42242313 Michael Hanselmann
      self._SendHeader("Content-Type", self.response_content_type)
486 42242313 Michael Hanselmann
      self._SendHeader("Content-Length", str(len(self.response_body)))
487 42242313 Michael Hanselmann
      # We don't support keep-alive at this time
488 42242313 Michael Hanselmann
      self._SendHeader("Connection", "close")
489 42242313 Michael Hanselmann
      self.wfile.write("\r\n")
490 42242313 Michael Hanselmann
491 42242313 Michael Hanselmann
    if (self.request_method != HTTP_HEAD and
492 42242313 Michael Hanselmann
        self.response_code >= HTTP_OK and
493 42242313 Michael Hanselmann
        self.response_code not in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED)):
494 42242313 Michael Hanselmann
      self.wfile.write(self.response_body)
495 42242313 Michael Hanselmann
496 42242313 Michael Hanselmann
  def _SendHeader(self, name, value):
497 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
498 42242313 Michael Hanselmann
      self.wfile.write("%s: %s\r\n" % (name, value))
499 42242313 Michael Hanselmann
500 42242313 Michael Hanselmann
  def _ReadRequest(self):
501 42242313 Michael Hanselmann
    """Reads and parses request line
502 42242313 Michael Hanselmann

503 42242313 Michael Hanselmann
    """
504 42242313 Michael Hanselmann
    raw_requestline = self.rfile.readline()
505 42242313 Michael Hanselmann
506 42242313 Michael Hanselmann
    requestline = raw_requestline
507 42242313 Michael Hanselmann
    if requestline[-2:] == '\r\n':
508 42242313 Michael Hanselmann
      requestline = requestline[:-2]
509 42242313 Michael Hanselmann
    elif requestline[-1:] == '\n':
510 42242313 Michael Hanselmann
      requestline = requestline[:-1]
511 42242313 Michael Hanselmann
512 42242313 Michael Hanselmann
    if not requestline:
513 42242313 Michael Hanselmann
      raise HTTPBadRequest("Empty request line")
514 42242313 Michael Hanselmann
515 42242313 Michael Hanselmann
    self.request_requestline = requestline
516 42242313 Michael Hanselmann
517 42242313 Michael Hanselmann
    logging.debug("HTTP request: %s", raw_requestline.rstrip("\r\n"))
518 42242313 Michael Hanselmann
519 42242313 Michael Hanselmann
    words = requestline.split()
520 42242313 Michael Hanselmann
521 42242313 Michael Hanselmann
    if len(words) == 3:
522 42242313 Michael Hanselmann
      [method, path, version] = words
523 42242313 Michael Hanselmann
      if version[:5] != 'HTTP/':
524 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
525 42242313 Michael Hanselmann
526 42242313 Michael Hanselmann
      try:
527 42242313 Michael Hanselmann
        base_version_number = version.split('/', 1)[1]
528 42242313 Michael Hanselmann
        version_number = base_version_number.split(".")
529 42242313 Michael Hanselmann
530 42242313 Michael Hanselmann
        # RFC 2145 section 3.1 says there can be only one "." and
531 42242313 Michael Hanselmann
        #   - major and minor numbers MUST be treated as
532 42242313 Michael Hanselmann
        #      separate integers;
533 42242313 Michael Hanselmann
        #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
534 42242313 Michael Hanselmann
        #      turn is lower than HTTP/12.3;
535 42242313 Michael Hanselmann
        #   - Leading zeros MUST be ignored by recipients.
536 42242313 Michael Hanselmann
        if len(version_number) != 2:
537 42242313 Michael Hanselmann
          raise HTTPBadRequest("Bad request version (%r)" % version)
538 42242313 Michael Hanselmann
539 42242313 Michael Hanselmann
        version_number = int(version_number[0]), int(version_number[1])
540 42242313 Michael Hanselmann
      except (ValueError, IndexError):
541 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
542 42242313 Michael Hanselmann
543 42242313 Michael Hanselmann
      if version_number >= (2, 0):
544 42242313 Michael Hanselmann
        raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
545 42242313 Michael Hanselmann
                                      base_version_number)
546 42242313 Michael Hanselmann
547 42242313 Michael Hanselmann
    elif len(words) == 2:
548 42242313 Michael Hanselmann
      version = HTTP_0_9
549 42242313 Michael Hanselmann
      [method, path] = words
550 42242313 Michael Hanselmann
      if method != HTTP_GET:
551 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
552 42242313 Michael Hanselmann
553 42242313 Michael Hanselmann
    else:
554 42242313 Michael Hanselmann
      raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
555 42242313 Michael Hanselmann
556 42242313 Michael Hanselmann
    # Examine the headers and look for a Connection directive
557 42242313 Michael Hanselmann
    headers = mimetools.Message(self.rfile, 0)
558 42242313 Michael Hanselmann
559 42242313 Michael Hanselmann
    self.request_method = method
560 42242313 Michael Hanselmann
    self.request_path = path
561 42242313 Michael Hanselmann
    self.request_version = version
562 42242313 Michael Hanselmann
    self.request_headers = headers
563 42242313 Michael Hanselmann
564 42242313 Michael Hanselmann
  def _ReadPostData(self):
565 42242313 Michael Hanselmann
    """Reads POST/PUT data
566 42242313 Michael Hanselmann

567 42242313 Michael Hanselmann
    """
568 42242313 Michael Hanselmann
    if not self.request_method or self.request_method.upper() not in ("POST", "PUT"):
569 42242313 Michael Hanselmann
      self.request_post_data = None
570 42242313 Michael Hanselmann
      return
571 42242313 Michael Hanselmann
572 42242313 Michael Hanselmann
    # TODO: Decide what to do when Content-Length header was not sent
573 42242313 Michael Hanselmann
    try:
574 42242313 Michael Hanselmann
      content_length = int(self.request_headers.get('Content-Length', 0))
575 42242313 Michael Hanselmann
    except ValueError:
576 42242313 Michael Hanselmann
      raise HTTPBadRequest("No Content-Length header or invalid format")
577 42242313 Michael Hanselmann
578 42242313 Michael Hanselmann
    data = self.rfile.read(content_length)
579 42242313 Michael Hanselmann
580 42242313 Michael Hanselmann
    # TODO: Content-type, error handling
581 42242313 Michael Hanselmann
    self.request_post_data = HTTPJsonConverter().Decode(data)
582 42242313 Michael Hanselmann
583 42242313 Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.request_post_data)
584 42242313 Michael Hanselmann
585 42242313 Michael Hanselmann
586 42242313 Michael Hanselmann
class HttpServer(object):
587 42242313 Michael Hanselmann
  """Generic HTTP server class
588 42242313 Michael Hanselmann

589 42242313 Michael Hanselmann
  Users of this class must subclass it and override the HandleRequest function.
590 42242313 Michael Hanselmann
  Optionally, the ForkForRequest function can be overriden.
591 42242313 Michael Hanselmann

592 42242313 Michael Hanselmann
  """
593 42242313 Michael Hanselmann
  MAX_CHILDREN = 20
594 42242313 Michael Hanselmann
595 42242313 Michael Hanselmann
  def __init__(self, mainloop, server_address):
596 42242313 Michael Hanselmann
    self.mainloop = mainloop
597 42242313 Michael Hanselmann
    self.server_address = server_address
598 42242313 Michael Hanselmann
599 42242313 Michael Hanselmann
    # TODO: SSL support
600 42242313 Michael Hanselmann
    self.ssl_cert = None
601 42242313 Michael Hanselmann
    self.ssl_key = self.ssl_cert
602 42242313 Michael Hanselmann
603 42242313 Michael Hanselmann
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
604 42242313 Michael Hanselmann
605 42242313 Michael Hanselmann
    if self.ssl_cert and self.ssl_key:
606 42242313 Michael Hanselmann
      ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
607 42242313 Michael Hanselmann
      ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
608 42242313 Michael Hanselmann
609 42242313 Michael Hanselmann
      ctx.use_certificate_file(self.ssl_cert)
610 42242313 Michael Hanselmann
      ctx.use_privatekey_file(self.ssl_key)
611 42242313 Michael Hanselmann
612 42242313 Michael Hanselmann
      self.socket = OpenSSL.SSL.Connection(ctx, sock)
613 42242313 Michael Hanselmann
      self._fileio_class = _SSLFileObject
614 42242313 Michael Hanselmann
    else:
615 42242313 Michael Hanselmann
      self.socket = sock
616 42242313 Michael Hanselmann
      self._fileio_class = socket._fileobject
617 42242313 Michael Hanselmann
618 42242313 Michael Hanselmann
    # Allow port to be reused
619 42242313 Michael Hanselmann
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
620 42242313 Michael Hanselmann
621 42242313 Michael Hanselmann
    self._children = []
622 42242313 Michael Hanselmann
623 42242313 Michael Hanselmann
    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
624 42242313 Michael Hanselmann
    mainloop.RegisterSignal(self)
625 42242313 Michael Hanselmann
626 42242313 Michael Hanselmann
  def Start(self):
627 42242313 Michael Hanselmann
    self.socket.bind(self.server_address)
628 42242313 Michael Hanselmann
    self.socket.listen(5)
629 42242313 Michael Hanselmann
630 42242313 Michael Hanselmann
  def Stop(self):
631 42242313 Michael Hanselmann
    self.socket.close()
632 42242313 Michael Hanselmann
633 42242313 Michael Hanselmann
  def OnIO(self, fd, condition):
634 42242313 Michael Hanselmann
    if condition & select.POLLIN:
635 42242313 Michael Hanselmann
      self._IncomingConnection()
636 42242313 Michael Hanselmann
637 42242313 Michael Hanselmann
  def OnSignal(self, signum):
638 42242313 Michael Hanselmann
    if signum == signal.SIGCHLD:
639 42242313 Michael Hanselmann
      self._CollectChildren(True)
640 42242313 Michael Hanselmann
641 42242313 Michael Hanselmann
  def _CollectChildren(self, quick):
642 42242313 Michael Hanselmann
    """Checks whether any child processes are done
643 42242313 Michael Hanselmann

644 42242313 Michael Hanselmann
    @type quick: bool
645 42242313 Michael Hanselmann
    @param quick: Whether to only use non-blocking functions
646 42242313 Michael Hanselmann

647 42242313 Michael Hanselmann
    """
648 42242313 Michael Hanselmann
    if not quick:
649 42242313 Michael Hanselmann
      # Don't wait for other processes if it should be a quick check
650 42242313 Michael Hanselmann
      while len(self._children) > self.MAX_CHILDREN:
651 42242313 Michael Hanselmann
        try:
652 42242313 Michael Hanselmann
          pid, status = os.waitpid(0, 0)
653 42242313 Michael Hanselmann
        except os.error:
654 42242313 Michael Hanselmann
          pid = None
655 42242313 Michael Hanselmann
        if pid and pid in self._children:
656 42242313 Michael Hanselmann
          self._children.remove(pid)
657 42242313 Michael Hanselmann
658 42242313 Michael Hanselmann
    for child in self._children:
659 42242313 Michael Hanselmann
      try:
660 42242313 Michael Hanselmann
        pid, status = os.waitpid(child, os.WNOHANG)
661 42242313 Michael Hanselmann
      except os.error:
662 42242313 Michael Hanselmann
        pid = None
663 42242313 Michael Hanselmann
      if pid and pid in self._children:
664 42242313 Michael Hanselmann
        self._children.remove(pid)
665 42242313 Michael Hanselmann
666 42242313 Michael Hanselmann
  def _IncomingConnection(self):
667 42242313 Michael Hanselmann
    connection, client_addr = self.socket.accept()
668 42242313 Michael Hanselmann
    logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
669 42242313 Michael Hanselmann
    try:
670 42242313 Michael Hanselmann
      handler = _HttpConnectionHandler(self, connection, client_addr, self._fileio_class)
671 42242313 Michael Hanselmann
    except (socket.error, SocketClosed):
672 42242313 Michael Hanselmann
      return
673 42242313 Michael Hanselmann
674 42242313 Michael Hanselmann
    def FinishRequest():
675 42242313 Michael Hanselmann
      try:
676 42242313 Michael Hanselmann
        try:
677 42242313 Michael Hanselmann
          try:
678 42242313 Michael Hanselmann
            handler.HandleRequest()
679 42242313 Michael Hanselmann
          finally:
680 42242313 Michael Hanselmann
            # Try to send a response
681 42242313 Michael Hanselmann
            handler.SendResponse()
682 42242313 Michael Hanselmann
            handler.Close()
683 42242313 Michael Hanselmann
        except SocketClosed:
684 42242313 Michael Hanselmann
          pass
685 42242313 Michael Hanselmann
      finally:
686 42242313 Michael Hanselmann
        logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
687 42242313 Michael Hanselmann
688 42242313 Michael Hanselmann
    # Check whether we should fork or not
689 42242313 Michael Hanselmann
    if not handler.should_fork:
690 42242313 Michael Hanselmann
      FinishRequest()
691 42242313 Michael Hanselmann
      return
692 42242313 Michael Hanselmann
693 42242313 Michael Hanselmann
    self._CollectChildren(False)
694 42242313 Michael Hanselmann
695 42242313 Michael Hanselmann
    pid = os.fork()
696 42242313 Michael Hanselmann
    if pid == 0:
697 42242313 Michael Hanselmann
      # Child process
698 42242313 Michael Hanselmann
      try:
699 42242313 Michael Hanselmann
        FinishRequest()
700 42242313 Michael Hanselmann
      except:
701 42242313 Michael Hanselmann
        logging.exception("Error while handling request from %s:%s",
702 42242313 Michael Hanselmann
                          client_addr[0], client_addr[1])
703 42242313 Michael Hanselmann
        os._exit(1)
704 42242313 Michael Hanselmann
      os._exit(0)
705 42242313 Michael Hanselmann
    else:
706 42242313 Michael Hanselmann
      self._children.append(pid)
707 42242313 Michael Hanselmann
708 42242313 Michael Hanselmann
  def HandleRequest(self, req):
709 42242313 Michael Hanselmann
    raise NotImplementedError()
710 42242313 Michael Hanselmann
711 42242313 Michael Hanselmann
  def ForkForRequest(self, req):
712 42242313 Michael Hanselmann
    return True
713 42242313 Michael Hanselmann
714 42242313 Michael Hanselmann
715 42242313 Michael Hanselmann
class _SSLFileObject(object):
716 42242313 Michael Hanselmann
  """Wrapper around socket._fileobject
717 42242313 Michael Hanselmann

718 42242313 Michael Hanselmann
  This wrapper is required to handle OpenSSL exceptions.
719 42242313 Michael Hanselmann

720 42242313 Michael Hanselmann
  """
721 42242313 Michael Hanselmann
  def _RequireOpenSocket(fn):
722 42242313 Michael Hanselmann
    def wrapper(self, *args, **kwargs):
723 42242313 Michael Hanselmann
      if self.closed:
724 42242313 Michael Hanselmann
        raise SocketClosed("Socket is closed")
725 42242313 Michael Hanselmann
      return fn(self, *args, **kwargs)
726 42242313 Michael Hanselmann
    return wrapper
727 42242313 Michael Hanselmann
728 42242313 Michael Hanselmann
  def __init__(self, sock, mode='rb', bufsize=-1):
729 42242313 Michael Hanselmann
    self._base = socket._fileobject(sock, mode=mode, bufsize=bufsize)
730 42242313 Michael Hanselmann
731 42242313 Michael Hanselmann
  def _ConnectionLost(self):
732 42242313 Michael Hanselmann
    self._base = None
733 42242313 Michael Hanselmann
734 42242313 Michael Hanselmann
  def _getclosed(self):
735 42242313 Michael Hanselmann
    return self._base is None or self._base.closed
736 42242313 Michael Hanselmann
  closed = property(_getclosed, doc="True if the file is closed")
737 42242313 Michael Hanselmann
738 42242313 Michael Hanselmann
  @_RequireOpenSocket
739 42242313 Michael Hanselmann
  def close(self):
740 42242313 Michael Hanselmann
    return self._base.close()
741 42242313 Michael Hanselmann
742 42242313 Michael Hanselmann
  @_RequireOpenSocket
743 42242313 Michael Hanselmann
  def flush(self):
744 42242313 Michael Hanselmann
    return self._base.flush()
745 42242313 Michael Hanselmann
746 42242313 Michael Hanselmann
  @_RequireOpenSocket
747 42242313 Michael Hanselmann
  def fileno(self):
748 42242313 Michael Hanselmann
    return self._base.fileno()
749 42242313 Michael Hanselmann
750 42242313 Michael Hanselmann
  @_RequireOpenSocket
751 42242313 Michael Hanselmann
  def read(self, size=-1):
752 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.read, size=size)
753 42242313 Michael Hanselmann
754 42242313 Michael Hanselmann
  @_RequireOpenSocket
755 42242313 Michael Hanselmann
  def readline(self, size=-1):
756 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.readline, size=size)
757 42242313 Michael Hanselmann
758 42242313 Michael Hanselmann
  def _ReadWrapper(self, fn, *args, **kwargs):
759 42242313 Michael Hanselmann
    while True:
760 42242313 Michael Hanselmann
      try:
761 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
762 42242313 Michael Hanselmann
763 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
764 42242313 Michael Hanselmann
        self._ConnectionLost()
765 42242313 Michael Hanselmann
        return ""
766 42242313 Michael Hanselmann
767 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantReadError:
768 42242313 Michael Hanselmann
        continue
769 42242313 Michael Hanselmann
770 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantWriteError:
771 42242313 Michael Hanselmann
      # TODO
772 42242313 Michael Hanselmann
773 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, (retval, desc):
774 42242313 Michael Hanselmann
        if ((retval == -1 and desc == "Unexpected EOF")
775 42242313 Michael Hanselmann
            or retval > 0):
776 42242313 Michael Hanselmann
          self._ConnectionLost()
777 42242313 Michael Hanselmann
          return ""
778 42242313 Michael Hanselmann
779 42242313 Michael Hanselmann
        logging.exception("Error in OpenSSL")
780 42242313 Michael Hanselmann
        self._ConnectionLost()
781 42242313 Michael Hanselmann
        raise socket.error(err.args)
782 42242313 Michael Hanselmann
783 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
784 42242313 Michael Hanselmann
        self._ConnectionLost()
785 42242313 Michael Hanselmann
        raise socket.error(err.args)
786 42242313 Michael Hanselmann
787 42242313 Michael Hanselmann
  @_RequireOpenSocket
788 42242313 Michael Hanselmann
  def write(self, data):
789 42242313 Michael Hanselmann
    return self._WriteWrapper(self._base.write, data)
790 42242313 Michael Hanselmann
791 42242313 Michael Hanselmann
  def _WriteWrapper(self, fn, *args, **kwargs):
792 42242313 Michael Hanselmann
    while True:
793 42242313 Michael Hanselmann
      try:
794 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
795 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
796 42242313 Michael Hanselmann
        self._ConnectionLost()
797 42242313 Michael Hanselmann
        return 0
798 42242313 Michael Hanselmann
799 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantWriteError:
800 42242313 Michael Hanselmann
        continue
801 42242313 Michael Hanselmann
802 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantReadError:
803 42242313 Michael Hanselmann
      # TODO
804 42242313 Michael Hanselmann
805 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, err:
806 42242313 Michael Hanselmann
        if err.args[0] == -1 and data == "":
807 42242313 Michael Hanselmann
          # errors when writing empty strings are expected
808 42242313 Michael Hanselmann
          # and can be ignored
809 42242313 Michael Hanselmann
          return 0
810 42242313 Michael Hanselmann
811 42242313 Michael Hanselmann
        self._ConnectionLost()
812 42242313 Michael Hanselmann
        raise socket.error(err.args)
813 42242313 Michael Hanselmann
814 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
815 42242313 Michael Hanselmann
        self._ConnectionLost()
816 42242313 Michael Hanselmann
        raise socket.error(err.args)