Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ eb1742d5

History | View | Annotate | Download (40.5 kB)

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

23 a43f68dc Michael Hanselmann
"""
24 a43f68dc Michael Hanselmann
25 a43f68dc Michael Hanselmann
import BaseHTTPServer
26 42242313 Michael Hanselmann
import cgi
27 42242313 Michael Hanselmann
import logging
28 42242313 Michael Hanselmann
import mimetools
29 a43f68dc Michael Hanselmann
import OpenSSL
30 42242313 Michael Hanselmann
import os
31 42242313 Michael Hanselmann
import select
32 42242313 Michael Hanselmann
import socket
33 42242313 Michael Hanselmann
import sys
34 a43f68dc Michael Hanselmann
import time
35 42242313 Michael Hanselmann
import signal
36 263ab7cf Iustin Pop
import logging
37 8a0b06d2 Michael Hanselmann
import errno
38 33bbdbec Michael Hanselmann
import threading
39 8a0b06d2 Michael Hanselmann
40 8a0b06d2 Michael Hanselmann
from cStringIO import StringIO
41 a43f68dc Michael Hanselmann
42 42242313 Michael Hanselmann
from ganeti import constants
43 a43f68dc Michael Hanselmann
from ganeti import serializer
44 8a0b06d2 Michael Hanselmann
from ganeti import workerpool
45 f2a6fc9e Michael Hanselmann
from ganeti import utils
46 a43f68dc Michael Hanselmann
47 a43f68dc Michael Hanselmann
48 8a0b06d2 Michael Hanselmann
HTTP_CLIENT_THREADS = 10
49 8a0b06d2 Michael Hanselmann
50 8a9f9060 Michael Hanselmann
HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
51 8a9f9060 Michael Hanselmann
52 42242313 Michael Hanselmann
WEEKDAYNAME = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
53 42242313 Michael Hanselmann
MONTHNAME = [None,
54 42242313 Michael Hanselmann
             'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
55 42242313 Michael Hanselmann
             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
56 42242313 Michael Hanselmann
57 42242313 Michael Hanselmann
# Default error message
58 42242313 Michael Hanselmann
DEFAULT_ERROR_CONTENT_TYPE = "text/html"
59 42242313 Michael Hanselmann
DEFAULT_ERROR_MESSAGE = """\
60 42242313 Michael Hanselmann
<head>
61 42242313 Michael Hanselmann
<title>Error response</title>
62 42242313 Michael Hanselmann
</head>
63 42242313 Michael Hanselmann
<body>
64 42242313 Michael Hanselmann
<h1>Error response</h1>
65 42242313 Michael Hanselmann
<p>Error code %(code)d.
66 42242313 Michael Hanselmann
<p>Message: %(message)s.
67 42242313 Michael Hanselmann
<p>Error code explanation: %(code)s = %(explain)s.
68 42242313 Michael Hanselmann
</body>
69 42242313 Michael Hanselmann
"""
70 42242313 Michael Hanselmann
71 42242313 Michael Hanselmann
HTTP_OK = 200
72 42242313 Michael Hanselmann
HTTP_NO_CONTENT = 204
73 42242313 Michael Hanselmann
HTTP_NOT_MODIFIED = 304
74 42242313 Michael Hanselmann
75 42242313 Michael Hanselmann
HTTP_0_9 = "HTTP/0.9"
76 42242313 Michael Hanselmann
HTTP_1_0 = "HTTP/1.0"
77 42242313 Michael Hanselmann
HTTP_1_1 = "HTTP/1.1"
78 42242313 Michael Hanselmann
79 42242313 Michael Hanselmann
HTTP_GET = "GET"
80 42242313 Michael Hanselmann
HTTP_HEAD = "HEAD"
81 8a9f9060 Michael Hanselmann
HTTP_POST = "POST"
82 8a9f9060 Michael Hanselmann
HTTP_PUT = "PUT"
83 8a9f9060 Michael Hanselmann
84 713faea6 Oleksiy Mishchenko
HTTP_ETAG = "ETag"
85 8a9f9060 Michael Hanselmann
HTTP_HOST = "Host"
86 8a9f9060 Michael Hanselmann
HTTP_SERVER = "Server"
87 8a9f9060 Michael Hanselmann
HTTP_DATE = "Date"
88 8a9f9060 Michael Hanselmann
HTTP_USER_AGENT = "User-Agent"
89 8a9f9060 Michael Hanselmann
HTTP_CONTENT_TYPE = "Content-Type"
90 8a9f9060 Michael Hanselmann
HTTP_CONTENT_LENGTH = "Content-Length"
91 8a9f9060 Michael Hanselmann
HTTP_CONNECTION = "Connection"
92 8a9f9060 Michael Hanselmann
HTTP_KEEP_ALIVE = "Keep-Alive"
93 42242313 Michael Hanselmann
94 d7bace1b Michael Hanselmann
_SSL_UNEXPECTED_EOF = "Unexpected EOF"
95 d7bace1b Michael Hanselmann
96 73a59d9e Michael Hanselmann
# Socket operations
97 73a59d9e Michael Hanselmann
(SOCKOP_SEND,
98 73a59d9e Michael Hanselmann
 SOCKOP_RECV,
99 73a59d9e Michael Hanselmann
 SOCKOP_SHUTDOWN) = range(3)
100 73a59d9e Michael Hanselmann
101 42242313 Michael Hanselmann
102 42242313 Michael Hanselmann
class SocketClosed(socket.error):
103 42242313 Michael Hanselmann
  pass
104 42242313 Michael Hanselmann
105 42242313 Michael Hanselmann
106 438a366a Michael Hanselmann
class _HttpClientError(Exception):
107 438a366a Michael Hanselmann
  """Internal exception for HTTP client errors.
108 438a366a Michael Hanselmann

109 438a366a Michael Hanselmann
  This should only be used for internal error reporting.
110 438a366a Michael Hanselmann

111 438a366a Michael Hanselmann
  """
112 73a59d9e Michael Hanselmann
113 73a59d9e Michael Hanselmann
114 73a59d9e Michael Hanselmann
class _HttpSocketTimeout(Exception):
115 73a59d9e Michael Hanselmann
  """Internal exception for socket timeouts.
116 73a59d9e Michael Hanselmann

117 73a59d9e Michael Hanselmann
  This should only be used for internal error reporting.
118 73a59d9e Michael Hanselmann

119 73a59d9e Michael Hanselmann
  """
120 8a0b06d2 Michael Hanselmann
121 8a0b06d2 Michael Hanselmann
122 a43f68dc Michael Hanselmann
class HTTPException(Exception):
123 a43f68dc Michael Hanselmann
  code = None
124 a43f68dc Michael Hanselmann
  message = None
125 a43f68dc Michael Hanselmann
126 a43f68dc Michael Hanselmann
  def __init__(self, message=None):
127 42242313 Michael Hanselmann
    Exception.__init__(self)
128 a43f68dc Michael Hanselmann
    if message is not None:
129 a43f68dc Michael Hanselmann
      self.message = message
130 a43f68dc Michael Hanselmann
131 a43f68dc Michael Hanselmann
132 a43f68dc Michael Hanselmann
class HTTPBadRequest(HTTPException):
133 a43f68dc Michael Hanselmann
  code = 400
134 a43f68dc Michael Hanselmann
135 a43f68dc Michael Hanselmann
136 a43f68dc Michael Hanselmann
class HTTPForbidden(HTTPException):
137 a43f68dc Michael Hanselmann
  code = 403
138 a43f68dc Michael Hanselmann
139 a43f68dc Michael Hanselmann
140 a43f68dc Michael Hanselmann
class HTTPNotFound(HTTPException):
141 a43f68dc Michael Hanselmann
  code = 404
142 a43f68dc Michael Hanselmann
143 a43f68dc Michael Hanselmann
144 a43f68dc Michael Hanselmann
class HTTPGone(HTTPException):
145 a43f68dc Michael Hanselmann
  code = 410
146 a43f68dc Michael Hanselmann
147 a43f68dc Michael Hanselmann
148 a43f68dc Michael Hanselmann
class HTTPLengthRequired(HTTPException):
149 a43f68dc Michael Hanselmann
  code = 411
150 a43f68dc Michael Hanselmann
151 a43f68dc Michael Hanselmann
152 a43f68dc Michael Hanselmann
class HTTPInternalError(HTTPException):
153 a43f68dc Michael Hanselmann
  code = 500
154 a43f68dc Michael Hanselmann
155 a43f68dc Michael Hanselmann
156 a43f68dc Michael Hanselmann
class HTTPNotImplemented(HTTPException):
157 a43f68dc Michael Hanselmann
  code = 501
158 a43f68dc Michael Hanselmann
159 a43f68dc Michael Hanselmann
160 a43f68dc Michael Hanselmann
class HTTPServiceUnavailable(HTTPException):
161 a43f68dc Michael Hanselmann
  code = 503
162 a43f68dc Michael Hanselmann
163 a43f68dc Michael Hanselmann
164 42242313 Michael Hanselmann
class HTTPVersionNotSupported(HTTPException):
165 42242313 Michael Hanselmann
  code = 505
166 42242313 Michael Hanselmann
167 42242313 Michael Hanselmann
168 a43f68dc Michael Hanselmann
class HTTPJsonConverter:
169 a43f68dc Michael Hanselmann
  CONTENT_TYPE = "application/json"
170 a43f68dc Michael Hanselmann
171 a43f68dc Michael Hanselmann
  def Encode(self, data):
172 a43f68dc Michael Hanselmann
    return serializer.DumpJson(data)
173 a43f68dc Michael Hanselmann
174 a43f68dc Michael Hanselmann
  def Decode(self, data):
175 a43f68dc Michael Hanselmann
    return serializer.LoadJson(data)
176 a43f68dc Michael Hanselmann
177 a43f68dc Michael Hanselmann
178 73a59d9e Michael Hanselmann
def WaitForSocketCondition(poller, sock, event, timeout):
179 f22c1cea Michael Hanselmann
  """Waits for a condition to occur on the socket.
180 f22c1cea Michael Hanselmann

181 f22c1cea Michael Hanselmann
  @type poller: select.Poller
182 f22c1cea Michael Hanselmann
  @param poller: Poller object as created by select.poll()
183 73a59d9e Michael Hanselmann
  @type sock: socket
184 73a59d9e Michael Hanselmann
  @param socket: Wait for events on this socket
185 f22c1cea Michael Hanselmann
  @type event: int
186 f22c1cea Michael Hanselmann
  @param event: ORed condition (see select module)
187 f22c1cea Michael Hanselmann
  @type timeout: float or None
188 f22c1cea Michael Hanselmann
  @param timeout: Timeout in seconds
189 f22c1cea Michael Hanselmann
  @rtype: int or None
190 f22c1cea Michael Hanselmann
  @return: None for timeout, otherwise occured conditions
191 f22c1cea Michael Hanselmann

192 f22c1cea Michael Hanselmann
  """
193 f22c1cea Michael Hanselmann
  check = (event | select.POLLPRI |
194 f22c1cea Michael Hanselmann
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
195 f22c1cea Michael Hanselmann
196 f22c1cea Michael Hanselmann
  if timeout is not None:
197 f22c1cea Michael Hanselmann
    # Poller object expects milliseconds
198 f22c1cea Michael Hanselmann
    timeout *= 1000
199 f22c1cea Michael Hanselmann
200 f22c1cea Michael Hanselmann
  poller.register(sock, event)
201 f22c1cea Michael Hanselmann
  try:
202 f22c1cea Michael Hanselmann
    while True:
203 f22c1cea Michael Hanselmann
      # TODO: If the main thread receives a signal and we have no timeout, we
204 f22c1cea Michael Hanselmann
      # could wait forever. This should check a global "quit" flag or
205 f22c1cea Michael Hanselmann
      # something every so often.
206 f22c1cea Michael Hanselmann
      io_events = poller.poll(timeout)
207 f22c1cea Michael Hanselmann
      if not io_events:
208 f22c1cea Michael Hanselmann
        # Timeout
209 f22c1cea Michael Hanselmann
        return None
210 f22c1cea Michael Hanselmann
      for (evfd, evcond) in io_events:
211 f22c1cea Michael Hanselmann
        if evcond & check:
212 f22c1cea Michael Hanselmann
          return evcond
213 f22c1cea Michael Hanselmann
  finally:
214 f22c1cea Michael Hanselmann
    poller.unregister(sock)
215 f22c1cea Michael Hanselmann
216 f22c1cea Michael Hanselmann
217 73a59d9e Michael Hanselmann
def SocketOperation(poller, sock, op, arg1, timeout):
218 73a59d9e Michael Hanselmann
  """Wrapper around socket functions.
219 73a59d9e Michael Hanselmann

220 73a59d9e Michael Hanselmann
  This function abstracts error handling for socket operations, especially
221 73a59d9e Michael Hanselmann
  for the complicated interaction with OpenSSL.
222 73a59d9e Michael Hanselmann

223 73a59d9e Michael Hanselmann
  @type poller: select.Poller
224 73a59d9e Michael Hanselmann
  @param poller: Poller object as created by select.poll()
225 73a59d9e Michael Hanselmann
  @type sock: socket
226 73a59d9e Michael Hanselmann
  @param socket: Socket for the operation
227 73a59d9e Michael Hanselmann
  @type op: int
228 73a59d9e Michael Hanselmann
  @param op: Operation to execute (SOCKOP_* constants)
229 73a59d9e Michael Hanselmann
  @type arg1: any
230 73a59d9e Michael Hanselmann
  @param arg1: Parameter for function (if needed)
231 73a59d9e Michael Hanselmann
  @type timeout: None or float
232 73a59d9e Michael Hanselmann
  @param timeout: Timeout in seconds or None
233 73a59d9e Michael Hanselmann

234 73a59d9e Michael Hanselmann
  """
235 73a59d9e Michael Hanselmann
  # TODO: event_poll/event_check/override
236 73a59d9e Michael Hanselmann
  if op == SOCKOP_SEND:
237 73a59d9e Michael Hanselmann
    event_poll = select.POLLOUT
238 73a59d9e Michael Hanselmann
    event_check = select.POLLOUT
239 73a59d9e Michael Hanselmann
240 73a59d9e Michael Hanselmann
  elif op == SOCKOP_RECV:
241 73a59d9e Michael Hanselmann
    event_poll = select.POLLIN
242 73a59d9e Michael Hanselmann
    event_check = select.POLLIN | select.POLLPRI
243 73a59d9e Michael Hanselmann
244 73a59d9e Michael Hanselmann
  elif op == SOCKOP_SHUTDOWN:
245 73a59d9e Michael Hanselmann
    event_poll = None
246 73a59d9e Michael Hanselmann
    event_check = None
247 73a59d9e Michael Hanselmann
248 73a59d9e Michael Hanselmann
    # The timeout is only used when OpenSSL requests polling for a condition.
249 73a59d9e Michael Hanselmann
    # It is not advisable to have no timeout for shutdown.
250 73a59d9e Michael Hanselmann
    assert timeout
251 73a59d9e Michael Hanselmann
252 73a59d9e Michael Hanselmann
  else:
253 73a59d9e Michael Hanselmann
    raise AssertionError("Invalid socket operation")
254 73a59d9e Michael Hanselmann
255 73a59d9e Michael Hanselmann
  # No override by default
256 73a59d9e Michael Hanselmann
  event_override = 0
257 73a59d9e Michael Hanselmann
258 73a59d9e Michael Hanselmann
  while True:
259 73a59d9e Michael Hanselmann
    # Poll only for certain operations and when asked for by an override
260 73a59d9e Michael Hanselmann
    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV):
261 73a59d9e Michael Hanselmann
      if event_override:
262 73a59d9e Michael Hanselmann
        wait_for_event = event_override
263 73a59d9e Michael Hanselmann
      else:
264 73a59d9e Michael Hanselmann
        wait_for_event = event_poll
265 73a59d9e Michael Hanselmann
266 73a59d9e Michael Hanselmann
      event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
267 73a59d9e Michael Hanselmann
      if event is None:
268 73a59d9e Michael Hanselmann
        raise _HttpSocketTimeout()
269 73a59d9e Michael Hanselmann
270 73a59d9e Michael Hanselmann
      if (op == SOCKOP_RECV and
271 73a59d9e Michael Hanselmann
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
272 73a59d9e Michael Hanselmann
        return ""
273 73a59d9e Michael Hanselmann
274 73a59d9e Michael Hanselmann
      if not event & wait_for_event:
275 73a59d9e Michael Hanselmann
        continue
276 73a59d9e Michael Hanselmann
277 73a59d9e Michael Hanselmann
    # Reset override
278 73a59d9e Michael Hanselmann
    event_override = 0
279 73a59d9e Michael Hanselmann
280 73a59d9e Michael Hanselmann
    try:
281 73a59d9e Michael Hanselmann
      try:
282 73a59d9e Michael Hanselmann
        if op == SOCKOP_SEND:
283 73a59d9e Michael Hanselmann
          return sock.send(arg1)
284 73a59d9e Michael Hanselmann
285 73a59d9e Michael Hanselmann
        elif op == SOCKOP_RECV:
286 73a59d9e Michael Hanselmann
          return sock.recv(arg1)
287 73a59d9e Michael Hanselmann
288 73a59d9e Michael Hanselmann
        elif op == SOCKOP_SHUTDOWN:
289 73a59d9e Michael Hanselmann
          if isinstance(sock, OpenSSL.SSL.ConnectionType):
290 73a59d9e Michael Hanselmann
            # PyOpenSSL's shutdown() doesn't take arguments
291 73a59d9e Michael Hanselmann
            return sock.shutdown()
292 73a59d9e Michael Hanselmann
          else:
293 73a59d9e Michael Hanselmann
            return sock.shutdown(arg1)
294 73a59d9e Michael Hanselmann
295 73a59d9e Michael Hanselmann
      except OpenSSL.SSL.WantWriteError:
296 73a59d9e Michael Hanselmann
        # OpenSSL wants to write, poll for POLLOUT
297 73a59d9e Michael Hanselmann
        event_override = select.POLLOUT
298 73a59d9e Michael Hanselmann
        continue
299 73a59d9e Michael Hanselmann
300 73a59d9e Michael Hanselmann
      except OpenSSL.SSL.WantReadError:
301 73a59d9e Michael Hanselmann
        # OpenSSL wants to read, poll for POLLIN
302 73a59d9e Michael Hanselmann
        event_override = select.POLLIN | select.POLLPRI
303 73a59d9e Michael Hanselmann
        continue
304 73a59d9e Michael Hanselmann
305 73a59d9e Michael Hanselmann
      except OpenSSL.SSL.WantX509LookupError:
306 73a59d9e Michael Hanselmann
        continue
307 73a59d9e Michael Hanselmann
308 73a59d9e Michael Hanselmann
      except OpenSSL.SSL.SysCallError, err:
309 73a59d9e Michael Hanselmann
        if op == SOCKOP_SEND:
310 73a59d9e Michael Hanselmann
          # arg1 is the data when writing
311 73a59d9e Michael Hanselmann
          if err.args and err.args[0] == -1 and arg1 == "":
312 73a59d9e Michael Hanselmann
            # errors when writing empty strings are expected
313 73a59d9e Michael Hanselmann
            # and can be ignored
314 73a59d9e Michael Hanselmann
            return 0
315 73a59d9e Michael Hanselmann
316 73a59d9e Michael Hanselmann
        elif op == SOCKOP_RECV:
317 73a59d9e Michael Hanselmann
          if err.args == (-1, _SSL_UNEXPECTED_EOF):
318 73a59d9e Michael Hanselmann
            return ""
319 73a59d9e Michael Hanselmann
320 73a59d9e Michael Hanselmann
        raise socket.error(err.args)
321 73a59d9e Michael Hanselmann
322 73a59d9e Michael Hanselmann
      except OpenSSL.SSL.Error, err:
323 73a59d9e Michael Hanselmann
        raise socket.error(err.args)
324 73a59d9e Michael Hanselmann
325 73a59d9e Michael Hanselmann
    except socket.error, err:
326 73a59d9e Michael Hanselmann
      if err.args and err.args[0] == errno.EAGAIN:
327 73a59d9e Michael Hanselmann
        # Ignore EAGAIN
328 73a59d9e Michael Hanselmann
        continue
329 73a59d9e Michael Hanselmann
330 73a59d9e Michael Hanselmann
      raise
331 73a59d9e Michael Hanselmann
332 73a59d9e Michael Hanselmann
333 f20cbea2 Michael Hanselmann
class HttpSslParams(object):
334 f20cbea2 Michael Hanselmann
  """Data class for SSL key and certificate.
335 f20cbea2 Michael Hanselmann

336 f20cbea2 Michael Hanselmann
  """
337 f20cbea2 Michael Hanselmann
  def __init__(self, ssl_key_path, ssl_cert_path):
338 f20cbea2 Michael Hanselmann
    """Initializes this class.
339 f20cbea2 Michael Hanselmann

340 f20cbea2 Michael Hanselmann
    @type ssl_key_path: string
341 f20cbea2 Michael Hanselmann
    @param ssl_key_path: Path to file containing SSL key in PEM format
342 f20cbea2 Michael Hanselmann
    @type ssl_cert_path: string
343 f20cbea2 Michael Hanselmann
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
344 f20cbea2 Michael Hanselmann

345 f20cbea2 Michael Hanselmann
    """
346 65c6b8e0 Michael Hanselmann
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
347 65c6b8e0 Michael Hanselmann
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
348 f20cbea2 Michael Hanselmann
349 65c6b8e0 Michael Hanselmann
  def GetKey(self):
350 65c6b8e0 Michael Hanselmann
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
351 65c6b8e0 Michael Hanselmann
                                          self.ssl_key_pem)
352 65c6b8e0 Michael Hanselmann
353 65c6b8e0 Michael Hanselmann
  def GetCertificate(self):
354 65c6b8e0 Michael Hanselmann
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
355 65c6b8e0 Michael Hanselmann
                                           self.ssl_cert_pem)
356 f20cbea2 Michael Hanselmann
357 f20cbea2 Michael Hanselmann
358 b14f759e Michael Hanselmann
class _HttpSocketBase(object):
359 b14f759e Michael Hanselmann
  """Base class for HTTP server and client.
360 b14f759e Michael Hanselmann

361 b14f759e Michael Hanselmann
  """
362 b14f759e Michael Hanselmann
  def __init__(self):
363 b14f759e Michael Hanselmann
    self._using_ssl = None
364 f20cbea2 Michael Hanselmann
    self._ssl_params = None
365 65c6b8e0 Michael Hanselmann
    self._ssl_key = None
366 65c6b8e0 Michael Hanselmann
    self._ssl_cert = None
367 b14f759e Michael Hanselmann
368 f20cbea2 Michael Hanselmann
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
369 b14f759e Michael Hanselmann
    """Creates a TCP socket and initializes SSL if needed.
370 b14f759e Michael Hanselmann

371 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
372 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
373 b14f759e Michael Hanselmann
    @type ssl_verify_peer: bool
374 b14f759e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
375 b14f759e Michael Hanselmann
                            it with our certificate
376 b14f759e Michael Hanselmann

377 b14f759e Michael Hanselmann
    """
378 f20cbea2 Michael Hanselmann
    self._ssl_params = ssl_params
379 f20cbea2 Michael Hanselmann
380 b14f759e Michael Hanselmann
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
381 b14f759e Michael Hanselmann
382 b14f759e Michael Hanselmann
    # Should we enable SSL?
383 f20cbea2 Michael Hanselmann
    self._using_ssl = ssl_params is not None
384 b14f759e Michael Hanselmann
385 b14f759e Michael Hanselmann
    if not self._using_ssl:
386 b14f759e Michael Hanselmann
      return sock
387 b14f759e Michael Hanselmann
388 65c6b8e0 Michael Hanselmann
    self._ssl_key = ssl_params.GetKey()
389 65c6b8e0 Michael Hanselmann
    self._ssl_cert = ssl_params.GetCertificate()
390 65c6b8e0 Michael Hanselmann
391 b14f759e Michael Hanselmann
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
392 b14f759e Michael Hanselmann
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
393 b14f759e Michael Hanselmann
394 65c6b8e0 Michael Hanselmann
    ctx.use_privatekey(self._ssl_key)
395 65c6b8e0 Michael Hanselmann
    ctx.use_certificate(self._ssl_cert)
396 b14f759e Michael Hanselmann
    ctx.check_privatekey()
397 b14f759e Michael Hanselmann
398 b14f759e Michael Hanselmann
    if ssl_verify_peer:
399 b14f759e Michael Hanselmann
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
400 b14f759e Michael Hanselmann
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
401 b14f759e Michael Hanselmann
                     self._SSLVerifyCallback)
402 b14f759e Michael Hanselmann
403 b14f759e Michael Hanselmann
    return OpenSSL.SSL.Connection(ctx, sock)
404 b14f759e Michael Hanselmann
405 b14f759e Michael Hanselmann
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
406 b14f759e Michael Hanselmann
    """Verify the certificate provided by the peer
407 b14f759e Michael Hanselmann

408 b14f759e Michael Hanselmann
    We only compare fingerprints. The client must use the same certificate as
409 b14f759e Michael Hanselmann
    we do on our side.
410 b14f759e Michael Hanselmann

411 b14f759e Michael Hanselmann
    """
412 f20cbea2 Michael Hanselmann
    assert self._ssl_params, "SSL not initialized"
413 b14f759e Michael Hanselmann
414 65c6b8e0 Michael Hanselmann
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
415 65c6b8e0 Michael Hanselmann
            self._ssl_cert.digest("md5") == cert.digest("md5"))
416 b14f759e Michael Hanselmann
417 b14f759e Michael Hanselmann
418 b1d979cf Michael Hanselmann
class HttpServerRequestExecutor(object):
419 42242313 Michael Hanselmann
  """Implements server side of HTTP
420 42242313 Michael Hanselmann

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

425 42242313 Michael Hanselmann
  """
426 42242313 Michael Hanselmann
  # The default request version.  This only affects responses up until
427 42242313 Michael Hanselmann
  # the point where the request line is parsed, so it mainly decides what
428 42242313 Michael Hanselmann
  # the client gets back when sending a malformed request line.
429 42242313 Michael Hanselmann
  # Most web servers default to HTTP 0.9, i.e. don't send a status line.
430 42242313 Michael Hanselmann
  default_request_version = HTTP_0_9
431 42242313 Michael Hanselmann
432 42242313 Michael Hanselmann
  # Error message settings
433 42242313 Michael Hanselmann
  error_message_format = DEFAULT_ERROR_MESSAGE
434 42242313 Michael Hanselmann
  error_content_type = DEFAULT_ERROR_CONTENT_TYPE
435 42242313 Michael Hanselmann
436 42242313 Michael Hanselmann
  responses = BaseHTTPServer.BaseHTTPRequestHandler.responses
437 42242313 Michael Hanselmann
438 42242313 Michael Hanselmann
  def __init__(self, server, conn, client_addr, fileio_class):
439 42242313 Michael Hanselmann
    """Initializes this class.
440 42242313 Michael Hanselmann

441 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
442 42242313 Michael Hanselmann
    data sent by the client.
443 42242313 Michael Hanselmann

444 42242313 Michael Hanselmann
    """
445 42242313 Michael Hanselmann
    self._server = server
446 42242313 Michael Hanselmann
447 42242313 Michael Hanselmann
    # We default rfile to buffered because otherwise it could be
448 42242313 Michael Hanselmann
    # really slow for large data (a getc() call per byte); we make
449 42242313 Michael Hanselmann
    # wfile unbuffered because (a) often after a write() we want to
450 42242313 Michael Hanselmann
    # read and we need to flush the line; (b) big writes to unbuffered
451 42242313 Michael Hanselmann
    # files are typically optimized by stdio even when big reads
452 42242313 Michael Hanselmann
    # aren't.
453 42242313 Michael Hanselmann
    self.rfile = fileio_class(conn, mode="rb", bufsize=-1)
454 42242313 Michael Hanselmann
    self.wfile = fileio_class(conn, mode="wb", bufsize=0)
455 42242313 Michael Hanselmann
456 42242313 Michael Hanselmann
    self.client_addr = client_addr
457 42242313 Michael Hanselmann
458 42242313 Michael Hanselmann
    self.request_headers = None
459 42242313 Michael Hanselmann
    self.request_method = None
460 42242313 Michael Hanselmann
    self.request_path = None
461 42242313 Michael Hanselmann
    self.request_requestline = None
462 42242313 Michael Hanselmann
    self.request_version = self.default_request_version
463 42242313 Michael Hanselmann
464 42242313 Michael Hanselmann
    self.response_body = None
465 42242313 Michael Hanselmann
    self.response_code = HTTP_OK
466 42242313 Michael Hanselmann
    self.response_content_type = None
467 713faea6 Oleksiy Mishchenko
    self.response_headers = {}
468 42242313 Michael Hanselmann
469 b1d979cf Michael Hanselmann
    logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
470 42242313 Michael Hanselmann
    try:
471 b1d979cf Michael Hanselmann
      try:
472 b1d979cf Michael Hanselmann
        try:
473 b1d979cf Michael Hanselmann
          try:
474 b1d979cf Michael Hanselmann
            # Read, parse and handle request
475 b1d979cf Michael Hanselmann
            self._ReadRequest()
476 b1d979cf Michael Hanselmann
            self._ReadPostData()
477 b1d979cf Michael Hanselmann
            self._HandleRequest()
478 b1d979cf Michael Hanselmann
          except HTTPException, err:
479 b1d979cf Michael Hanselmann
            self._SetErrorStatus(err)
480 b1d979cf Michael Hanselmann
        finally:
481 b1d979cf Michael Hanselmann
          # Try to send a response
482 b1d979cf Michael Hanselmann
          self._SendResponse()
483 b1d979cf Michael Hanselmann
          self._Close()
484 b1d979cf Michael Hanselmann
      except SocketClosed:
485 b1d979cf Michael Hanselmann
        pass
486 b1d979cf Michael Hanselmann
    finally:
487 b1d979cf Michael Hanselmann
      logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
488 b1d979cf Michael Hanselmann
489 b1d979cf Michael Hanselmann
  def _Close(self):
490 42242313 Michael Hanselmann
    if not self.wfile.closed:
491 42242313 Michael Hanselmann
      self.wfile.flush()
492 42242313 Michael Hanselmann
    self.wfile.close()
493 42242313 Michael Hanselmann
    self.rfile.close()
494 42242313 Michael Hanselmann
495 42242313 Michael Hanselmann
  def _DateTimeHeader(self):
496 42242313 Michael Hanselmann
    """Return the current date and time formatted for a message header.
497 42242313 Michael Hanselmann

498 42242313 Michael Hanselmann
    """
499 42242313 Michael Hanselmann
    (year, month, day, hh, mm, ss, wd, _, _) = time.gmtime()
500 42242313 Michael Hanselmann
    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
501 42242313 Michael Hanselmann
            (WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
502 42242313 Michael Hanselmann
503 42242313 Michael Hanselmann
  def _SetErrorStatus(self, err):
504 42242313 Michael Hanselmann
    """Sets the response code and body from a HTTPException.
505 42242313 Michael Hanselmann

506 42242313 Michael Hanselmann
    @type err: HTTPException
507 42242313 Michael Hanselmann
    @param err: Exception instance
508 42242313 Michael Hanselmann

509 42242313 Michael Hanselmann
    """
510 42242313 Michael Hanselmann
    try:
511 42242313 Michael Hanselmann
      (shortmsg, longmsg) = self.responses[err.code]
512 42242313 Michael Hanselmann
    except KeyError:
513 42242313 Michael Hanselmann
      shortmsg = longmsg = "Unknown"
514 42242313 Michael Hanselmann
515 42242313 Michael Hanselmann
    if err.message:
516 42242313 Michael Hanselmann
      message = err.message
517 42242313 Michael Hanselmann
    else:
518 42242313 Michael Hanselmann
      message = shortmsg
519 42242313 Michael Hanselmann
520 42242313 Michael Hanselmann
    values = {
521 42242313 Michael Hanselmann
      "code": err.code,
522 42242313 Michael Hanselmann
      "message": cgi.escape(message),
523 42242313 Michael Hanselmann
      "explain": longmsg,
524 42242313 Michael Hanselmann
      }
525 42242313 Michael Hanselmann
526 42242313 Michael Hanselmann
    self.response_code = err.code
527 42242313 Michael Hanselmann
    self.response_content_type = self.error_content_type
528 42242313 Michael Hanselmann
    self.response_body = self.error_message_format % values
529 42242313 Michael Hanselmann
530 b1d979cf Michael Hanselmann
  def _HandleRequest(self):
531 42242313 Michael Hanselmann
    """Handle the actual request.
532 42242313 Michael Hanselmann

533 42242313 Michael Hanselmann
    Calls the actual handler function and converts exceptions into HTTP errors.
534 42242313 Michael Hanselmann

535 42242313 Michael Hanselmann
    """
536 42242313 Michael Hanselmann
    # Don't do anything if there's already been a problem
537 42242313 Michael Hanselmann
    if self.response_code != HTTP_OK:
538 42242313 Michael Hanselmann
      return
539 42242313 Michael Hanselmann
540 42242313 Michael Hanselmann
    assert self.request_method, "Status code %s requires a method" % HTTP_OK
541 42242313 Michael Hanselmann
542 42242313 Michael Hanselmann
    # Check whether client is still there
543 42242313 Michael Hanselmann
    self.rfile.read(0)
544 42242313 Michael Hanselmann
545 42242313 Michael Hanselmann
    try:
546 42242313 Michael Hanselmann
      try:
547 42242313 Michael Hanselmann
        result = self._server.HandleRequest(self)
548 42242313 Michael Hanselmann
549 42242313 Michael Hanselmann
        # TODO: Content-type
550 42242313 Michael Hanselmann
        encoder = HTTPJsonConverter()
551 42242313 Michael Hanselmann
        body = encoder.Encode(result)
552 42242313 Michael Hanselmann
553 42242313 Michael Hanselmann
        self.response_content_type = encoder.CONTENT_TYPE
554 42242313 Michael Hanselmann
        self.response_body = body
555 42242313 Michael Hanselmann
      except (HTTPException, KeyboardInterrupt, SystemExit):
556 42242313 Michael Hanselmann
        raise
557 42242313 Michael Hanselmann
      except Exception, err:
558 42242313 Michael Hanselmann
        logging.exception("Caught exception")
559 42242313 Michael Hanselmann
        raise HTTPInternalError(message=str(err))
560 42242313 Michael Hanselmann
      except:
561 42242313 Michael Hanselmann
        logging.exception("Unknown exception")
562 42242313 Michael Hanselmann
        raise HTTPInternalError(message="Unknown error")
563 42242313 Michael Hanselmann
564 42242313 Michael Hanselmann
    except HTTPException, err:
565 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
566 42242313 Michael Hanselmann
567 b1d979cf Michael Hanselmann
  def _SendResponse(self):
568 42242313 Michael Hanselmann
    """Sends response to the client.
569 42242313 Michael Hanselmann

570 42242313 Michael Hanselmann
    """
571 42242313 Michael Hanselmann
    # Check whether client is still there
572 42242313 Michael Hanselmann
    self.rfile.read(0)
573 42242313 Michael Hanselmann
574 42242313 Michael Hanselmann
    logging.info("%s:%s %s %s", self.client_addr[0], self.client_addr[1],
575 42242313 Michael Hanselmann
                 self.request_requestline, self.response_code)
576 42242313 Michael Hanselmann
577 42242313 Michael Hanselmann
    if self.response_code in self.responses:
578 42242313 Michael Hanselmann
      response_message = self.responses[self.response_code][0]
579 42242313 Michael Hanselmann
    else:
580 42242313 Michael Hanselmann
      response_message = ""
581 42242313 Michael Hanselmann
582 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
583 42242313 Michael Hanselmann
      self.wfile.write("%s %d %s\r\n" %
584 42242313 Michael Hanselmann
                       (self.request_version, self.response_code,
585 42242313 Michael Hanselmann
                        response_message))
586 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_SERVER, HTTP_GANETI_VERSION)
587 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_DATE, self._DateTimeHeader())
588 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_TYPE, self.response_content_type)
589 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_LENGTH, str(len(self.response_body)))
590 713faea6 Oleksiy Mishchenko
      for key, val in self.response_headers.iteritems():
591 713faea6 Oleksiy Mishchenko
        self._SendHeader(key, val)
592 713faea6 Oleksiy Mishchenko
593 42242313 Michael Hanselmann
      # We don't support keep-alive at this time
594 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONNECTION, "close")
595 42242313 Michael Hanselmann
      self.wfile.write("\r\n")
596 42242313 Michael Hanselmann
597 42242313 Michael Hanselmann
    if (self.request_method != HTTP_HEAD and
598 42242313 Michael Hanselmann
        self.response_code >= HTTP_OK and
599 42242313 Michael Hanselmann
        self.response_code not in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED)):
600 42242313 Michael Hanselmann
      self.wfile.write(self.response_body)
601 42242313 Michael Hanselmann
602 42242313 Michael Hanselmann
  def _SendHeader(self, name, value):
603 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
604 42242313 Michael Hanselmann
      self.wfile.write("%s: %s\r\n" % (name, value))
605 42242313 Michael Hanselmann
606 42242313 Michael Hanselmann
  def _ReadRequest(self):
607 42242313 Michael Hanselmann
    """Reads and parses request line
608 42242313 Michael Hanselmann

609 42242313 Michael Hanselmann
    """
610 42242313 Michael Hanselmann
    raw_requestline = self.rfile.readline()
611 42242313 Michael Hanselmann
612 42242313 Michael Hanselmann
    requestline = raw_requestline
613 42242313 Michael Hanselmann
    if requestline[-2:] == '\r\n':
614 42242313 Michael Hanselmann
      requestline = requestline[:-2]
615 42242313 Michael Hanselmann
    elif requestline[-1:] == '\n':
616 42242313 Michael Hanselmann
      requestline = requestline[:-1]
617 42242313 Michael Hanselmann
618 42242313 Michael Hanselmann
    if not requestline:
619 42242313 Michael Hanselmann
      raise HTTPBadRequest("Empty request line")
620 42242313 Michael Hanselmann
621 42242313 Michael Hanselmann
    self.request_requestline = requestline
622 42242313 Michael Hanselmann
623 42242313 Michael Hanselmann
    logging.debug("HTTP request: %s", raw_requestline.rstrip("\r\n"))
624 42242313 Michael Hanselmann
625 42242313 Michael Hanselmann
    words = requestline.split()
626 42242313 Michael Hanselmann
627 42242313 Michael Hanselmann
    if len(words) == 3:
628 42242313 Michael Hanselmann
      [method, path, version] = words
629 42242313 Michael Hanselmann
      if version[:5] != 'HTTP/':
630 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
631 42242313 Michael Hanselmann
632 42242313 Michael Hanselmann
      try:
633 42242313 Michael Hanselmann
        base_version_number = version.split('/', 1)[1]
634 42242313 Michael Hanselmann
        version_number = base_version_number.split(".")
635 42242313 Michael Hanselmann
636 42242313 Michael Hanselmann
        # RFC 2145 section 3.1 says there can be only one "." and
637 42242313 Michael Hanselmann
        #   - major and minor numbers MUST be treated as
638 42242313 Michael Hanselmann
        #      separate integers;
639 42242313 Michael Hanselmann
        #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
640 42242313 Michael Hanselmann
        #      turn is lower than HTTP/12.3;
641 42242313 Michael Hanselmann
        #   - Leading zeros MUST be ignored by recipients.
642 42242313 Michael Hanselmann
        if len(version_number) != 2:
643 42242313 Michael Hanselmann
          raise HTTPBadRequest("Bad request version (%r)" % version)
644 42242313 Michael Hanselmann
645 42242313 Michael Hanselmann
        version_number = int(version_number[0]), int(version_number[1])
646 42242313 Michael Hanselmann
      except (ValueError, IndexError):
647 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
648 42242313 Michael Hanselmann
649 42242313 Michael Hanselmann
      if version_number >= (2, 0):
650 42242313 Michael Hanselmann
        raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
651 42242313 Michael Hanselmann
                                      base_version_number)
652 42242313 Michael Hanselmann
653 42242313 Michael Hanselmann
    elif len(words) == 2:
654 42242313 Michael Hanselmann
      version = HTTP_0_9
655 42242313 Michael Hanselmann
      [method, path] = words
656 42242313 Michael Hanselmann
      if method != HTTP_GET:
657 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
658 42242313 Michael Hanselmann
659 42242313 Michael Hanselmann
    else:
660 42242313 Michael Hanselmann
      raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
661 42242313 Michael Hanselmann
662 42242313 Michael Hanselmann
    # Examine the headers and look for a Connection directive
663 42242313 Michael Hanselmann
    headers = mimetools.Message(self.rfile, 0)
664 42242313 Michael Hanselmann
665 42242313 Michael Hanselmann
    self.request_method = method
666 42242313 Michael Hanselmann
    self.request_path = path
667 42242313 Michael Hanselmann
    self.request_version = version
668 42242313 Michael Hanselmann
    self.request_headers = headers
669 42242313 Michael Hanselmann
670 42242313 Michael Hanselmann
  def _ReadPostData(self):
671 42242313 Michael Hanselmann
    """Reads POST/PUT data
672 42242313 Michael Hanselmann

673 64357ed8 Michael Hanselmann
    Quoting RFC1945, section 7.2 (HTTP/1.0): "The presence of an entity body in
674 64357ed8 Michael Hanselmann
    a request is signaled by the inclusion of a Content-Length header field in
675 64357ed8 Michael Hanselmann
    the request message headers. HTTP/1.0 requests containing an entity body
676 64357ed8 Michael Hanselmann
    must include a valid Content-Length header field."
677 64357ed8 Michael Hanselmann

678 42242313 Michael Hanselmann
    """
679 64357ed8 Michael Hanselmann
    # While not according to specification, we only support an entity body for
680 64357ed8 Michael Hanselmann
    # POST and PUT.
681 8a9f9060 Michael Hanselmann
    if (not self.request_method or
682 8a9f9060 Michael Hanselmann
        self.request_method.upper() not in (HTTP_POST, HTTP_PUT)):
683 42242313 Michael Hanselmann
      self.request_post_data = None
684 42242313 Michael Hanselmann
      return
685 42242313 Michael Hanselmann
686 64357ed8 Michael Hanselmann
    content_length = None
687 42242313 Michael Hanselmann
    try:
688 64357ed8 Michael Hanselmann
      if HTTP_CONTENT_LENGTH in self.request_headers:
689 64357ed8 Michael Hanselmann
        content_length = int(self.request_headers[HTTP_CONTENT_LENGTH])
690 64357ed8 Michael Hanselmann
    except TypeError:
691 64357ed8 Michael Hanselmann
      pass
692 42242313 Michael Hanselmann
    except ValueError:
693 64357ed8 Michael Hanselmann
      pass
694 64357ed8 Michael Hanselmann
695 64357ed8 Michael Hanselmann
    # 411 Length Required is specified in RFC2616, section 10.4.12 (HTTP/1.1)
696 64357ed8 Michael Hanselmann
    if content_length is None:
697 64357ed8 Michael Hanselmann
      raise HTTPLengthRequired("Missing Content-Length header or"
698 64357ed8 Michael Hanselmann
                               " invalid format")
699 42242313 Michael Hanselmann
700 42242313 Michael Hanselmann
    data = self.rfile.read(content_length)
701 42242313 Michael Hanselmann
702 42242313 Michael Hanselmann
    # TODO: Content-type, error handling
703 7c46aafd Oleksiy Mishchenko
    if data:
704 7c46aafd Oleksiy Mishchenko
      self.request_post_data = HTTPJsonConverter().Decode(data)
705 7c46aafd Oleksiy Mishchenko
    else:
706 7c46aafd Oleksiy Mishchenko
      self.request_post_data = None
707 42242313 Michael Hanselmann
708 42242313 Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.request_post_data)
709 42242313 Michael Hanselmann
710 42242313 Michael Hanselmann
711 b14f759e Michael Hanselmann
class HttpServer(_HttpSocketBase):
712 42242313 Michael Hanselmann
  """Generic HTTP server class
713 42242313 Michael Hanselmann

714 42242313 Michael Hanselmann
  Users of this class must subclass it and override the HandleRequest function.
715 42242313 Michael Hanselmann

716 42242313 Michael Hanselmann
  """
717 42242313 Michael Hanselmann
  MAX_CHILDREN = 20
718 42242313 Michael Hanselmann
719 f2a6fc9e Michael Hanselmann
  def __init__(self, mainloop, local_address, port,
720 f20cbea2 Michael Hanselmann
               ssl_params=None, ssl_verify_peer=False):
721 23e46494 Michael Hanselmann
    """Initializes the HTTP server
722 23e46494 Michael Hanselmann

723 23e46494 Michael Hanselmann
    @type mainloop: ganeti.daemon.Mainloop
724 23e46494 Michael Hanselmann
    @param mainloop: Mainloop used to poll for I/O events
725 23e46494 Michael Hanselmann
    @type local_addess: string
726 23e46494 Michael Hanselmann
    @param local_address: Local IP address to bind to
727 23e46494 Michael Hanselmann
    @type port: int
728 23e46494 Michael Hanselmann
    @param port: TCP port to listen on
729 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
730 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
731 f2a6fc9e Michael Hanselmann
    @type ssl_verify_peer: bool
732 f2a6fc9e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
733 f2a6fc9e Michael Hanselmann
                            it with our certificate
734 23e46494 Michael Hanselmann

735 23e46494 Michael Hanselmann
    """
736 b14f759e Michael Hanselmann
    _HttpSocketBase.__init__(self)
737 b14f759e Michael Hanselmann
738 42242313 Michael Hanselmann
    self.mainloop = mainloop
739 23e46494 Michael Hanselmann
    self.local_address = local_address
740 23e46494 Michael Hanselmann
    self.port = port
741 42242313 Michael Hanselmann
742 f20cbea2 Michael Hanselmann
    self.socket = self._CreateSocket(ssl_params, ssl_verify_peer)
743 f2a6fc9e Michael Hanselmann
744 b14f759e Michael Hanselmann
    # Allow port to be reused
745 b14f759e Michael Hanselmann
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
746 42242313 Michael Hanselmann
747 b14f759e Michael Hanselmann
    if self._using_ssl:
748 42242313 Michael Hanselmann
      self._fileio_class = _SSLFileObject
749 42242313 Michael Hanselmann
    else:
750 42242313 Michael Hanselmann
      self._fileio_class = socket._fileobject
751 42242313 Michael Hanselmann
752 42242313 Michael Hanselmann
    self._children = []
753 42242313 Michael Hanselmann
754 42242313 Michael Hanselmann
    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
755 42242313 Michael Hanselmann
    mainloop.RegisterSignal(self)
756 42242313 Michael Hanselmann
757 42242313 Michael Hanselmann
  def Start(self):
758 23e46494 Michael Hanselmann
    self.socket.bind((self.local_address, self.port))
759 42242313 Michael Hanselmann
    self.socket.listen(5)
760 42242313 Michael Hanselmann
761 42242313 Michael Hanselmann
  def Stop(self):
762 42242313 Michael Hanselmann
    self.socket.close()
763 42242313 Michael Hanselmann
764 42242313 Michael Hanselmann
  def OnIO(self, fd, condition):
765 42242313 Michael Hanselmann
    if condition & select.POLLIN:
766 42242313 Michael Hanselmann
      self._IncomingConnection()
767 42242313 Michael Hanselmann
768 42242313 Michael Hanselmann
  def OnSignal(self, signum):
769 42242313 Michael Hanselmann
    if signum == signal.SIGCHLD:
770 42242313 Michael Hanselmann
      self._CollectChildren(True)
771 42242313 Michael Hanselmann
772 42242313 Michael Hanselmann
  def _CollectChildren(self, quick):
773 42242313 Michael Hanselmann
    """Checks whether any child processes are done
774 42242313 Michael Hanselmann

775 42242313 Michael Hanselmann
    @type quick: bool
776 42242313 Michael Hanselmann
    @param quick: Whether to only use non-blocking functions
777 42242313 Michael Hanselmann

778 42242313 Michael Hanselmann
    """
779 42242313 Michael Hanselmann
    if not quick:
780 42242313 Michael Hanselmann
      # Don't wait for other processes if it should be a quick check
781 42242313 Michael Hanselmann
      while len(self._children) > self.MAX_CHILDREN:
782 42242313 Michael Hanselmann
        try:
783 6526ddcd Michael Hanselmann
          # Waiting without a timeout brings us into a potential DoS situation.
784 6526ddcd Michael Hanselmann
          # As soon as too many children run, we'll not respond to new
785 6526ddcd Michael Hanselmann
          # requests. The real solution would be to add a timeout for children
786 6526ddcd Michael Hanselmann
          # and killing them after some time.
787 42242313 Michael Hanselmann
          pid, status = os.waitpid(0, 0)
788 42242313 Michael Hanselmann
        except os.error:
789 42242313 Michael Hanselmann
          pid = None
790 42242313 Michael Hanselmann
        if pid and pid in self._children:
791 42242313 Michael Hanselmann
          self._children.remove(pid)
792 42242313 Michael Hanselmann
793 42242313 Michael Hanselmann
    for child in self._children:
794 42242313 Michael Hanselmann
      try:
795 42242313 Michael Hanselmann
        pid, status = os.waitpid(child, os.WNOHANG)
796 42242313 Michael Hanselmann
      except os.error:
797 42242313 Michael Hanselmann
        pid = None
798 42242313 Michael Hanselmann
      if pid and pid in self._children:
799 42242313 Michael Hanselmann
        self._children.remove(pid)
800 42242313 Michael Hanselmann
801 42242313 Michael Hanselmann
  def _IncomingConnection(self):
802 6526ddcd Michael Hanselmann
    """Called for each incoming connection
803 42242313 Michael Hanselmann

804 6526ddcd Michael Hanselmann
    """
805 6526ddcd Michael Hanselmann
    (connection, client_addr) = self.socket.accept()
806 42242313 Michael Hanselmann
807 42242313 Michael Hanselmann
    self._CollectChildren(False)
808 42242313 Michael Hanselmann
809 42242313 Michael Hanselmann
    pid = os.fork()
810 42242313 Michael Hanselmann
    if pid == 0:
811 42242313 Michael Hanselmann
      # Child process
812 42242313 Michael Hanselmann
      try:
813 b1d979cf Michael Hanselmann
        HttpServerRequestExecutor(self, connection, client_addr,
814 b1d979cf Michael Hanselmann
                                  self._fileio_class)
815 42242313 Michael Hanselmann
      except:
816 42242313 Michael Hanselmann
        logging.exception("Error while handling request from %s:%s",
817 42242313 Michael Hanselmann
                          client_addr[0], client_addr[1])
818 42242313 Michael Hanselmann
        os._exit(1)
819 42242313 Michael Hanselmann
      os._exit(0)
820 42242313 Michael Hanselmann
    else:
821 42242313 Michael Hanselmann
      self._children.append(pid)
822 42242313 Michael Hanselmann
823 42242313 Michael Hanselmann
  def HandleRequest(self, req):
824 42242313 Michael Hanselmann
    raise NotImplementedError()
825 42242313 Michael Hanselmann
826 42242313 Michael Hanselmann
827 8a0b06d2 Michael Hanselmann
class HttpClientRequest(object):
828 438a366a Michael Hanselmann
  def __init__(self, host, port, method, path, headers=None, post_data=None,
829 f20cbea2 Michael Hanselmann
               ssl_params=None, ssl_verify_peer=False):
830 8a0b06d2 Michael Hanselmann
    """Describes an HTTP request.
831 8a0b06d2 Michael Hanselmann

832 8a0b06d2 Michael Hanselmann
    @type host: string
833 8a0b06d2 Michael Hanselmann
    @param host: Hostname
834 8a0b06d2 Michael Hanselmann
    @type port: int
835 8a0b06d2 Michael Hanselmann
    @param port: Port
836 8a0b06d2 Michael Hanselmann
    @type method: string
837 8a0b06d2 Michael Hanselmann
    @param method: Method name
838 8a0b06d2 Michael Hanselmann
    @type path: string
839 8a0b06d2 Michael Hanselmann
    @param path: Request path
840 8a0b06d2 Michael Hanselmann
    @type headers: dict or None
841 8a0b06d2 Michael Hanselmann
    @param headers: Additional headers to send
842 8a0b06d2 Michael Hanselmann
    @type post_data: string or None
843 8a0b06d2 Michael Hanselmann
    @param post_data: Additional data to send
844 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
845 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
846 f20cbea2 Michael Hanselmann
    @type ssl_verify_peer: bool
847 f20cbea2 Michael Hanselmann
    @param ssl_verify_peer: Whether to compare our certificate with server's
848 f20cbea2 Michael Hanselmann
                            certificate
849 8a0b06d2 Michael Hanselmann

850 8a0b06d2 Michael Hanselmann
    """
851 8a0b06d2 Michael Hanselmann
    if post_data is not None:
852 8a0b06d2 Michael Hanselmann
      assert method.upper() in (HTTP_POST, HTTP_PUT), \
853 8a0b06d2 Michael Hanselmann
        "Only POST and GET requests support sending data"
854 8a0b06d2 Michael Hanselmann
855 8a0b06d2 Michael Hanselmann
    assert path.startswith("/"), "Path must start with slash (/)"
856 8a0b06d2 Michael Hanselmann
857 8a0b06d2 Michael Hanselmann
    self.host = host
858 8a0b06d2 Michael Hanselmann
    self.port = port
859 f20cbea2 Michael Hanselmann
    self.ssl_params = ssl_params
860 438a366a Michael Hanselmann
    self.ssl_verify_peer = ssl_verify_peer
861 8a0b06d2 Michael Hanselmann
    self.method = method
862 8a0b06d2 Michael Hanselmann
    self.path = path
863 8a0b06d2 Michael Hanselmann
    self.headers = headers
864 8a0b06d2 Michael Hanselmann
    self.post_data = post_data
865 8a0b06d2 Michael Hanselmann
866 8a0b06d2 Michael Hanselmann
    self.success = None
867 8a0b06d2 Michael Hanselmann
    self.error = None
868 8a0b06d2 Michael Hanselmann
869 8a0b06d2 Michael Hanselmann
    self.resp_status_line = None
870 8a0b06d2 Michael Hanselmann
    self.resp_version = None
871 8a0b06d2 Michael Hanselmann
    self.resp_status = None
872 8a0b06d2 Michael Hanselmann
    self.resp_reason = None
873 8a0b06d2 Michael Hanselmann
    self.resp_headers = None
874 8a0b06d2 Michael Hanselmann
    self.resp_body = None
875 8a0b06d2 Michael Hanselmann
876 8a0b06d2 Michael Hanselmann
877 438a366a Michael Hanselmann
class HttpClientRequestExecutor(_HttpSocketBase):
878 8a0b06d2 Michael Hanselmann
  # Default headers
879 8a0b06d2 Michael Hanselmann
  DEFAULT_HEADERS = {
880 8a0b06d2 Michael Hanselmann
    HTTP_USER_AGENT: HTTP_GANETI_VERSION,
881 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, don't send "Connection: close"
882 8a0b06d2 Michael Hanselmann
    HTTP_CONNECTION: "close",
883 8a0b06d2 Michael Hanselmann
    }
884 8a0b06d2 Michael Hanselmann
885 8a0b06d2 Michael Hanselmann
  # Length limits
886 8a0b06d2 Michael Hanselmann
  STATUS_LINE_LENGTH_MAX = 512
887 8a0b06d2 Michael Hanselmann
  HEADER_LENGTH_MAX = 4 * 1024
888 8a0b06d2 Michael Hanselmann
889 438a366a Michael Hanselmann
  # Timeouts in seconds for socket layer
890 8a0b06d2 Michael Hanselmann
  # TODO: Make read timeout configurable per OpCode
891 8a0b06d2 Michael Hanselmann
  CONNECT_TIMEOUT = 5.0
892 8a0b06d2 Michael Hanselmann
  WRITE_TIMEOUT = 10
893 8a0b06d2 Michael Hanselmann
  READ_TIMEOUT = None
894 8a0b06d2 Michael Hanselmann
  CLOSE_TIMEOUT = 1
895 8a0b06d2 Michael Hanselmann
896 8a0b06d2 Michael Hanselmann
  # Parser state machine
897 8a0b06d2 Michael Hanselmann
  PS_STATUS_LINE = "status-line"
898 8a0b06d2 Michael Hanselmann
  PS_HEADERS = "headers"
899 8a0b06d2 Michael Hanselmann
  PS_BODY = "body"
900 8a0b06d2 Michael Hanselmann
  PS_COMPLETE = "complete"
901 8a0b06d2 Michael Hanselmann
902 8a0b06d2 Michael Hanselmann
  def __init__(self, req):
903 8a0b06d2 Michael Hanselmann
    """Initializes the HttpClientRequestExecutor class.
904 8a0b06d2 Michael Hanselmann

905 8a0b06d2 Michael Hanselmann
    @type req: HttpClientRequest
906 8a0b06d2 Michael Hanselmann
    @param req: Request object
907 8a0b06d2 Michael Hanselmann

908 8a0b06d2 Michael Hanselmann
    """
909 438a366a Michael Hanselmann
    _HttpSocketBase.__init__(self)
910 438a366a Michael Hanselmann
911 8a0b06d2 Michael Hanselmann
    self.request = req
912 8a0b06d2 Michael Hanselmann
913 8a0b06d2 Michael Hanselmann
    self.parser_status = self.PS_STATUS_LINE
914 8a0b06d2 Michael Hanselmann
    self.header_buffer = StringIO()
915 8a0b06d2 Michael Hanselmann
    self.body_buffer = StringIO()
916 8a0b06d2 Michael Hanselmann
    self.content_length = None
917 8a0b06d2 Michael Hanselmann
    self.server_will_close = None
918 8a0b06d2 Michael Hanselmann
919 8a0b06d2 Michael Hanselmann
    self.poller = select.poll()
920 8a0b06d2 Michael Hanselmann
921 8a0b06d2 Michael Hanselmann
    try:
922 8a0b06d2 Michael Hanselmann
      # TODO: Implement connection caching/keep-alive
923 f20cbea2 Michael Hanselmann
      self.sock = self._CreateSocket(req.ssl_params,
924 438a366a Michael Hanselmann
                                     req.ssl_verify_peer)
925 8a0b06d2 Michael Hanselmann
926 8a0b06d2 Michael Hanselmann
      # Disable Python's timeout
927 8a0b06d2 Michael Hanselmann
      self.sock.settimeout(None)
928 8a0b06d2 Michael Hanselmann
929 8a0b06d2 Michael Hanselmann
      # Operate in non-blocking mode
930 8a0b06d2 Michael Hanselmann
      self.sock.setblocking(0)
931 8a0b06d2 Michael Hanselmann
932 8a0b06d2 Michael Hanselmann
      force_close = True
933 8a0b06d2 Michael Hanselmann
      self._Connect()
934 8a0b06d2 Michael Hanselmann
      try:
935 8a0b06d2 Michael Hanselmann
        self._SendRequest()
936 8a0b06d2 Michael Hanselmann
        self._ReadResponse()
937 8a0b06d2 Michael Hanselmann
938 8a0b06d2 Michael Hanselmann
        # Only wait for server to close if we didn't have any exception.
939 8a0b06d2 Michael Hanselmann
        force_close = False
940 8a0b06d2 Michael Hanselmann
      finally:
941 8a0b06d2 Michael Hanselmann
        self._CloseConnection(force_close)
942 8a0b06d2 Michael Hanselmann
943 8a0b06d2 Michael Hanselmann
      self.sock.close()
944 8a0b06d2 Michael Hanselmann
      self.sock = None
945 8a0b06d2 Michael Hanselmann
946 8a0b06d2 Michael Hanselmann
      req.resp_body = self.body_buffer.getvalue()
947 8a0b06d2 Michael Hanselmann
948 8a0b06d2 Michael Hanselmann
      req.success = True
949 8a0b06d2 Michael Hanselmann
      req.error = None
950 8a0b06d2 Michael Hanselmann
951 438a366a Michael Hanselmann
    except _HttpClientError, err:
952 8a0b06d2 Michael Hanselmann
      req.success = False
953 8a0b06d2 Michael Hanselmann
      req.error = str(err)
954 8a0b06d2 Michael Hanselmann
955 8a0b06d2 Michael Hanselmann
  def _BuildRequest(self):
956 8a0b06d2 Michael Hanselmann
    """Build HTTP request.
957 8a0b06d2 Michael Hanselmann

958 8a0b06d2 Michael Hanselmann
    @rtype: string
959 8a0b06d2 Michael Hanselmann
    @return: Complete request
960 8a0b06d2 Michael Hanselmann

961 8a0b06d2 Michael Hanselmann
    """
962 8a0b06d2 Michael Hanselmann
    # Headers
963 8a0b06d2 Michael Hanselmann
    send_headers = self.DEFAULT_HEADERS.copy()
964 8a0b06d2 Michael Hanselmann
965 8a0b06d2 Michael Hanselmann
    if self.request.headers:
966 33bbdbec Michael Hanselmann
      send_headers.update(self.request.headers)
967 8a0b06d2 Michael Hanselmann
968 8a0b06d2 Michael Hanselmann
    send_headers[HTTP_HOST] = "%s:%s" % (self.request.host, self.request.port)
969 8a0b06d2 Michael Hanselmann
970 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
971 8a0b06d2 Michael Hanselmann
      send_headers[HTTP_CONTENT_LENGTH] = len(self.request.post_data)
972 8a0b06d2 Michael Hanselmann
973 8a0b06d2 Michael Hanselmann
    buf = StringIO()
974 8a0b06d2 Michael Hanselmann
975 8a0b06d2 Michael Hanselmann
    # Add request line. We only support HTTP/1.0 (no chunked transfers and no
976 8a0b06d2 Michael Hanselmann
    # keep-alive).
977 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, change to HTTP/1.1
978 8a0b06d2 Michael Hanselmann
    buf.write("%s %s %s\r\n" % (self.request.method.upper(),
979 8a0b06d2 Michael Hanselmann
                                self.request.path, HTTP_1_0))
980 8a0b06d2 Michael Hanselmann
981 8a0b06d2 Michael Hanselmann
    # Add headers
982 8a0b06d2 Michael Hanselmann
    for name, value in send_headers.iteritems():
983 8a0b06d2 Michael Hanselmann
      buf.write("%s: %s\r\n" % (name, value))
984 8a0b06d2 Michael Hanselmann
985 8a0b06d2 Michael Hanselmann
    buf.write("\r\n")
986 8a0b06d2 Michael Hanselmann
987 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
988 8a0b06d2 Michael Hanselmann
      buf.write(self.request.post_data)
989 8a0b06d2 Michael Hanselmann
990 8a0b06d2 Michael Hanselmann
    return buf.getvalue()
991 8a0b06d2 Michael Hanselmann
992 8a0b06d2 Michael Hanselmann
  def _ParseStatusLine(self):
993 8a0b06d2 Michael Hanselmann
    """Parses the status line sent by the server.
994 8a0b06d2 Michael Hanselmann

995 8a0b06d2 Michael Hanselmann
    """
996 8a0b06d2 Michael Hanselmann
    line = self.request.resp_status_line
997 8a0b06d2 Michael Hanselmann
998 8a0b06d2 Michael Hanselmann
    if not line:
999 438a366a Michael Hanselmann
      raise _HttpClientError("Empty status line")
1000 8a0b06d2 Michael Hanselmann
1001 8a0b06d2 Michael Hanselmann
    try:
1002 8a0b06d2 Michael Hanselmann
      [version, status, reason] = line.split(None, 2)
1003 8a0b06d2 Michael Hanselmann
    except ValueError:
1004 8a0b06d2 Michael Hanselmann
      try:
1005 8a0b06d2 Michael Hanselmann
        [version, status] = line.split(None, 1)
1006 8a0b06d2 Michael Hanselmann
        reason = ""
1007 8a0b06d2 Michael Hanselmann
      except ValueError:
1008 8a0b06d2 Michael Hanselmann
        version = HTTP_9_0
1009 8a0b06d2 Michael Hanselmann
1010 8a0b06d2 Michael Hanselmann
    if version:
1011 8a0b06d2 Michael Hanselmann
      version = version.upper()
1012 8a0b06d2 Michael Hanselmann
1013 8a0b06d2 Michael Hanselmann
    if version not in (HTTP_1_0, HTTP_1_1):
1014 8a0b06d2 Michael Hanselmann
      # We do not support HTTP/0.9, despite the specification requiring it
1015 8a0b06d2 Michael Hanselmann
      # (RFC2616, section 19.6)
1016 438a366a Michael Hanselmann
      raise _HttpClientError("Only HTTP/1.0 and HTTP/1.1 are supported (%r)" %
1017 438a366a Michael Hanselmann
                             line)
1018 8a0b06d2 Michael Hanselmann
1019 8a0b06d2 Michael Hanselmann
    # The status code is a three-digit number
1020 8a0b06d2 Michael Hanselmann
    try:
1021 8a0b06d2 Michael Hanselmann
      status = int(status)
1022 8a0b06d2 Michael Hanselmann
      if status < 100 or status > 999:
1023 8a0b06d2 Michael Hanselmann
        status = -1
1024 8a0b06d2 Michael Hanselmann
    except ValueError:
1025 8a0b06d2 Michael Hanselmann
      status = -1
1026 8a0b06d2 Michael Hanselmann
1027 8a0b06d2 Michael Hanselmann
    if status == -1:
1028 438a366a Michael Hanselmann
      raise _HttpClientError("Invalid status code (%r)" % line)
1029 8a0b06d2 Michael Hanselmann
1030 8a0b06d2 Michael Hanselmann
    self.request.resp_version = version
1031 8a0b06d2 Michael Hanselmann
    self.request.resp_status = status
1032 8a0b06d2 Michael Hanselmann
    self.request.resp_reason = reason
1033 8a0b06d2 Michael Hanselmann
1034 8a0b06d2 Michael Hanselmann
  def _WillServerCloseConnection(self):
1035 8a0b06d2 Michael Hanselmann
    """Evaluate whether server will close the connection.
1036 8a0b06d2 Michael Hanselmann

1037 8a0b06d2 Michael Hanselmann
    @rtype: bool
1038 8a0b06d2 Michael Hanselmann
    @return: Whether server will close the connection
1039 8a0b06d2 Michael Hanselmann

1040 8a0b06d2 Michael Hanselmann
    """
1041 8a0b06d2 Michael Hanselmann
    hdr_connection = self.request.resp_headers.get(HTTP_CONNECTION, None)
1042 8a0b06d2 Michael Hanselmann
    if hdr_connection:
1043 8a0b06d2 Michael Hanselmann
      hdr_connection = hdr_connection.lower()
1044 8a0b06d2 Michael Hanselmann
1045 8a0b06d2 Michael Hanselmann
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
1046 8a0b06d2 Michael Hanselmann
    if self.request.resp_version == HTTP_1_1:
1047 8a0b06d2 Michael Hanselmann
      return (hdr_connection and "close" in hdr_connection)
1048 8a0b06d2 Michael Hanselmann
1049 8a0b06d2 Michael Hanselmann
    # Some HTTP/1.0 implementations have support for persistent connections,
1050 8a0b06d2 Michael Hanselmann
    # using rules different than HTTP/1.1.
1051 8a0b06d2 Michael Hanselmann
1052 8a0b06d2 Michael Hanselmann
    # For older HTTP, Keep-Alive indicates persistent connection.
1053 8a0b06d2 Michael Hanselmann
    if self.request.resp_headers.get(HTTP_KEEP_ALIVE):
1054 8a0b06d2 Michael Hanselmann
      return False
1055 8a0b06d2 Michael Hanselmann
1056 8a0b06d2 Michael Hanselmann
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
1057 8a0b06d2 Michael Hanselmann
    # supposed to be sent by the client.
1058 8a0b06d2 Michael Hanselmann
    if hdr_connection and "keep-alive" in hdr_connection:
1059 8a0b06d2 Michael Hanselmann
      return False
1060 8a0b06d2 Michael Hanselmann
1061 8a0b06d2 Michael Hanselmann
    return True
1062 8a0b06d2 Michael Hanselmann
1063 8a0b06d2 Michael Hanselmann
  def _ParseHeaders(self):
1064 8a0b06d2 Michael Hanselmann
    """Parses the headers sent by the server.
1065 8a0b06d2 Michael Hanselmann

1066 8a0b06d2 Michael Hanselmann
    This function also adjusts internal variables based on the header values.
1067 8a0b06d2 Michael Hanselmann

1068 8a0b06d2 Michael Hanselmann
    """
1069 8a0b06d2 Michael Hanselmann
    req = self.request
1070 8a0b06d2 Michael Hanselmann
1071 8a0b06d2 Michael Hanselmann
    # Parse headers
1072 8a0b06d2 Michael Hanselmann
    self.header_buffer.seek(0, 0)
1073 8a0b06d2 Michael Hanselmann
    req.resp_headers = mimetools.Message(self.header_buffer, 0)
1074 8a0b06d2 Michael Hanselmann
1075 8a0b06d2 Michael Hanselmann
    self.server_will_close = self._WillServerCloseConnection()
1076 8a0b06d2 Michael Hanselmann
1077 8a0b06d2 Michael Hanselmann
    # Do we have a Content-Length header?
1078 8a0b06d2 Michael Hanselmann
    hdr_content_length = req.resp_headers.get(HTTP_CONTENT_LENGTH, None)
1079 8a0b06d2 Michael Hanselmann
    if hdr_content_length:
1080 8a0b06d2 Michael Hanselmann
      try:
1081 8a0b06d2 Michael Hanselmann
        self.content_length = int(hdr_content_length)
1082 8a0b06d2 Michael Hanselmann
      except ValueError:
1083 8a0b06d2 Michael Hanselmann
        pass
1084 8a0b06d2 Michael Hanselmann
      if self.content_length is not None and self.content_length < 0:
1085 8a0b06d2 Michael Hanselmann
        self.content_length = None
1086 8a0b06d2 Michael Hanselmann
1087 8a0b06d2 Michael Hanselmann
    # does the body have a fixed length? (of zero)
1088 8a0b06d2 Michael Hanselmann
    if (req.resp_status in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED) or
1089 8a0b06d2 Michael Hanselmann
        100 <= req.resp_status < 200 or req.method == HTTP_HEAD):
1090 8a0b06d2 Michael Hanselmann
      self.content_length = 0
1091 8a0b06d2 Michael Hanselmann
1092 8a0b06d2 Michael Hanselmann
    # if the connection remains open and a content-length was not provided,
1093 8a0b06d2 Michael Hanselmann
    # then assume that the connection WILL close.
1094 8a0b06d2 Michael Hanselmann
    if self.content_length is None:
1095 8a0b06d2 Michael Hanselmann
      self.server_will_close = True
1096 8a0b06d2 Michael Hanselmann
1097 8a0b06d2 Michael Hanselmann
  def _CheckStatusLineLength(self, length):
1098 8a0b06d2 Michael Hanselmann
    if length > self.STATUS_LINE_LENGTH_MAX:
1099 438a366a Michael Hanselmann
      raise _HttpClientError("Status line longer than %d chars" %
1100 438a366a Michael Hanselmann
                             self.STATUS_LINE_LENGTH_MAX)
1101 8a0b06d2 Michael Hanselmann
1102 8a0b06d2 Michael Hanselmann
  def _CheckHeaderLength(self, length):
1103 8a0b06d2 Michael Hanselmann
    if length > self.HEADER_LENGTH_MAX:
1104 438a366a Michael Hanselmann
      raise _HttpClientError("Headers longer than %d chars" %
1105 438a366a Michael Hanselmann
                             self.HEADER_LENGTH_MAX)
1106 8a0b06d2 Michael Hanselmann
1107 8a0b06d2 Michael Hanselmann
  def _ParseBuffer(self, buf, eof):
1108 8a0b06d2 Michael Hanselmann
    """Main function for HTTP response state machine.
1109 8a0b06d2 Michael Hanselmann

1110 8a0b06d2 Michael Hanselmann
    @type buf: string
1111 8a0b06d2 Michael Hanselmann
    @param buf: Receive buffer
1112 8a0b06d2 Michael Hanselmann
    @type eof: bool
1113 8a0b06d2 Michael Hanselmann
    @param eof: Whether we've reached EOF on the socket
1114 8a0b06d2 Michael Hanselmann
    @rtype: string
1115 8a0b06d2 Michael Hanselmann
    @return: Updated receive buffer
1116 8a0b06d2 Michael Hanselmann

1117 8a0b06d2 Michael Hanselmann
    """
1118 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_STATUS_LINE:
1119 8a0b06d2 Michael Hanselmann
      # Expect status line
1120 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n")
1121 8a0b06d2 Michael Hanselmann
      if idx >= 0:
1122 8a0b06d2 Michael Hanselmann
        self.request.resp_status_line = buf[:idx]
1123 8a0b06d2 Michael Hanselmann
1124 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(self.request.resp_status_line))
1125 8a0b06d2 Michael Hanselmann
1126 8a0b06d2 Michael Hanselmann
        # Remove status line, including CRLF
1127 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 2:]
1128 8a0b06d2 Michael Hanselmann
1129 8a0b06d2 Michael Hanselmann
        self._ParseStatusLine()
1130 8a0b06d2 Michael Hanselmann
1131 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_HEADERS
1132 8a0b06d2 Michael Hanselmann
      else:
1133 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1134 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1135 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(buf))
1136 8a0b06d2 Michael Hanselmann
1137 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_HEADERS:
1138 8a0b06d2 Michael Hanselmann
      # Wait for header end
1139 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n\r\n")
1140 8a0b06d2 Michael Hanselmann
      if idx >= 0:
1141 8a0b06d2 Michael Hanselmann
        self.header_buffer.write(buf[:idx + 2])
1142 8a0b06d2 Michael Hanselmann
1143 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(self.header_buffer.tell())
1144 8a0b06d2 Michael Hanselmann
1145 8a0b06d2 Michael Hanselmann
        # Remove headers, including CRLF
1146 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 4:]
1147 8a0b06d2 Michael Hanselmann
1148 8a0b06d2 Michael Hanselmann
        self._ParseHeaders()
1149 8a0b06d2 Michael Hanselmann
1150 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_BODY
1151 8a0b06d2 Michael Hanselmann
      else:
1152 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1153 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1154 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(len(buf))
1155 8a0b06d2 Michael Hanselmann
1156 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_BODY:
1157 8a0b06d2 Michael Hanselmann
      self.body_buffer.write(buf)
1158 8a0b06d2 Michael Hanselmann
      buf = ""
1159 8a0b06d2 Michael Hanselmann
1160 8a0b06d2 Michael Hanselmann
      # Check whether we've read everything
1161 8a0b06d2 Michael Hanselmann
      if (eof or
1162 8a0b06d2 Michael Hanselmann
          (self.content_length is not None and
1163 8a0b06d2 Michael Hanselmann
           self.body_buffer.tell() >= self.content_length)):
1164 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_COMPLETE
1165 8a0b06d2 Michael Hanselmann
1166 8a0b06d2 Michael Hanselmann
    return buf
1167 8a0b06d2 Michael Hanselmann
1168 8a0b06d2 Michael Hanselmann
  def _Connect(self):
1169 8a0b06d2 Michael Hanselmann
    """Non-blocking connect to host with timeout.
1170 8a0b06d2 Michael Hanselmann

1171 8a0b06d2 Michael Hanselmann
    """
1172 8a0b06d2 Michael Hanselmann
    connected = False
1173 8a0b06d2 Michael Hanselmann
    while True:
1174 438a366a Michael Hanselmann
      try:
1175 438a366a Michael Hanselmann
        connect_error = self.sock.connect_ex((self.request.host,
1176 438a366a Michael Hanselmann
                                              self.request.port))
1177 438a366a Michael Hanselmann
      except socket.gaierror, err:
1178 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed: %s" % str(err))
1179 438a366a Michael Hanselmann
1180 8a0b06d2 Michael Hanselmann
      if connect_error == errno.EINTR:
1181 8a0b06d2 Michael Hanselmann
        # Mask signals
1182 8a0b06d2 Michael Hanselmann
        pass
1183 8a0b06d2 Michael Hanselmann
1184 8a0b06d2 Michael Hanselmann
      elif connect_error == 0:
1185 8a0b06d2 Michael Hanselmann
        # Connection established
1186 8a0b06d2 Michael Hanselmann
        connected = True
1187 8a0b06d2 Michael Hanselmann
        break
1188 8a0b06d2 Michael Hanselmann
1189 8a0b06d2 Michael Hanselmann
      elif connect_error == errno.EINPROGRESS:
1190 8a0b06d2 Michael Hanselmann
        # Connection started
1191 8a0b06d2 Michael Hanselmann
        break
1192 8a0b06d2 Michael Hanselmann
1193 438a366a Michael Hanselmann
      raise _HttpClientError("Connection failed (%s: %s)" %
1194 438a366a Michael Hanselmann
                             (connect_error, os.strerror(connect_error)))
1195 8a0b06d2 Michael Hanselmann
1196 8a0b06d2 Michael Hanselmann
    if not connected:
1197 8a0b06d2 Michael Hanselmann
      # Wait for connection
1198 73a59d9e Michael Hanselmann
      event = WaitForSocketCondition(self.poller, self.sock,
1199 f22c1cea Michael Hanselmann
                                     select.POLLOUT, self.CONNECT_TIMEOUT)
1200 8a0b06d2 Michael Hanselmann
      if event is None:
1201 438a366a Michael Hanselmann
        raise _HttpClientError("Timeout while connecting to server")
1202 8a0b06d2 Michael Hanselmann
1203 8a0b06d2 Michael Hanselmann
      # Get error code
1204 8a0b06d2 Michael Hanselmann
      connect_error = self.sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
1205 8a0b06d2 Michael Hanselmann
      if connect_error != 0:
1206 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed (%s: %s)" %
1207 438a366a Michael Hanselmann
                               (connect_error, os.strerror(connect_error)))
1208 8a0b06d2 Michael Hanselmann
1209 8a0b06d2 Michael Hanselmann
    # Enable TCP keep-alive
1210 8a0b06d2 Michael Hanselmann
    self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
1211 8a0b06d2 Michael Hanselmann
1212 8a0b06d2 Michael Hanselmann
    # If needed, Linux specific options are available to change the TCP
1213 8a0b06d2 Michael Hanselmann
    # keep-alive settings, see "man 7 tcp" for TCP_KEEPCNT, TCP_KEEPIDLE and
1214 8a0b06d2 Michael Hanselmann
    # TCP_KEEPINTVL.
1215 8a0b06d2 Michael Hanselmann
1216 8a0b06d2 Michael Hanselmann
  def _SendRequest(self):
1217 8a0b06d2 Michael Hanselmann
    """Sends request to server.
1218 8a0b06d2 Michael Hanselmann

1219 8a0b06d2 Michael Hanselmann
    """
1220 8a0b06d2 Michael Hanselmann
    buf = self._BuildRequest()
1221 8a0b06d2 Michael Hanselmann
1222 8a0b06d2 Michael Hanselmann
    while buf:
1223 438a366a Michael Hanselmann
      # Send only 4 KB at a time
1224 438a366a Michael Hanselmann
      data = buf[:4096]
1225 8a0b06d2 Michael Hanselmann
1226 73a59d9e Michael Hanselmann
      try:
1227 73a59d9e Michael Hanselmann
        sent = SocketOperation(self.poller, self.sock, SOCKOP_SEND, data,
1228 73a59d9e Michael Hanselmann
                               self.WRITE_TIMEOUT)
1229 73a59d9e Michael Hanselmann
      except _HttpSocketTimeout:
1230 73a59d9e Michael Hanselmann
        raise _HttpClientError("Timeout while sending request")
1231 73a59d9e Michael Hanselmann
      except socket.error, err:
1232 73a59d9e Michael Hanselmann
        raise _HttpClientError("Error sending request: %s" % err)
1233 8a0b06d2 Michael Hanselmann
1234 8a0b06d2 Michael Hanselmann
      # Remove sent bytes
1235 8a0b06d2 Michael Hanselmann
      buf = buf[sent:]
1236 8a0b06d2 Michael Hanselmann
1237 8a0b06d2 Michael Hanselmann
    assert not buf, "Request wasn't sent completely"
1238 8a0b06d2 Michael Hanselmann
1239 8a0b06d2 Michael Hanselmann
  def _ReadResponse(self):
1240 8a0b06d2 Michael Hanselmann
    """Read response from server.
1241 8a0b06d2 Michael Hanselmann

1242 8a0b06d2 Michael Hanselmann
    Calls the parser function after reading a chunk of data.
1243 8a0b06d2 Michael Hanselmann

1244 8a0b06d2 Michael Hanselmann
    """
1245 8a0b06d2 Michael Hanselmann
    buf = ""
1246 8a0b06d2 Michael Hanselmann
    eof = False
1247 8a0b06d2 Michael Hanselmann
    while self.parser_status != self.PS_COMPLETE:
1248 73a59d9e Michael Hanselmann
      try:
1249 73a59d9e Michael Hanselmann
        data = SocketOperation(self.poller, self.sock, SOCKOP_RECV, 4096,
1250 73a59d9e Michael Hanselmann
                               self.READ_TIMEOUT)
1251 73a59d9e Michael Hanselmann
      except _HttpSocketTimeout:
1252 73a59d9e Michael Hanselmann
        raise _HttpClientError("Timeout while reading response")
1253 73a59d9e Michael Hanselmann
      except socket.error, err:
1254 73a59d9e Michael Hanselmann
        raise _HttpClientError("Error while reading response: %s" % err)
1255 8a0b06d2 Michael Hanselmann
1256 438a366a Michael Hanselmann
      if data:
1257 438a366a Michael Hanselmann
        buf += data
1258 438a366a Michael Hanselmann
      else:
1259 8a0b06d2 Michael Hanselmann
        eof = True
1260 8a0b06d2 Michael Hanselmann
1261 8a0b06d2 Michael Hanselmann
      # Do some parsing and error checking while more data arrives
1262 8a0b06d2 Michael Hanselmann
      buf = self._ParseBuffer(buf, eof)
1263 8a0b06d2 Michael Hanselmann
1264 8a0b06d2 Michael Hanselmann
      # Must be done only after the buffer has been evaluated
1265 8a0b06d2 Michael Hanselmann
      if (eof and
1266 8a0b06d2 Michael Hanselmann
          self.parser_status in (self.PS_STATUS_LINE,
1267 8a0b06d2 Michael Hanselmann
                                 self.PS_HEADERS)):
1268 438a366a Michael Hanselmann
        raise _HttpClientError("Connection closed prematurely")
1269 8a0b06d2 Michael Hanselmann
1270 8a0b06d2 Michael Hanselmann
    # Parse rest
1271 8a0b06d2 Michael Hanselmann
    buf = self._ParseBuffer(buf, True)
1272 8a0b06d2 Michael Hanselmann
1273 8a0b06d2 Michael Hanselmann
    assert self.parser_status == self.PS_COMPLETE
1274 8a0b06d2 Michael Hanselmann
    assert not buf, "Parser didn't read full response"
1275 8a0b06d2 Michael Hanselmann
1276 8a0b06d2 Michael Hanselmann
  def _CloseConnection(self, force):
1277 8a0b06d2 Michael Hanselmann
    """Closes the connection.
1278 8a0b06d2 Michael Hanselmann

1279 8a0b06d2 Michael Hanselmann
    """
1280 8a0b06d2 Michael Hanselmann
    if self.server_will_close and not force:
1281 8a0b06d2 Michael Hanselmann
      # Wait for server to close
1282 438a366a Michael Hanselmann
      try:
1283 438a366a Michael Hanselmann
        # Check whether it's actually closed
1284 73a59d9e Michael Hanselmann
        if not SocketOperation(self.poller, self.sock, SOCKOP_RECV, 1,
1285 73a59d9e Michael Hanselmann
                               self.CLOSE_TIMEOUT):
1286 438a366a Michael Hanselmann
          return
1287 73a59d9e Michael Hanselmann
      except (socket.error, _HttpClientError, _HttpSocketTimeout):
1288 438a366a Michael Hanselmann
        # Ignore errors at this stage
1289 8a0b06d2 Michael Hanselmann
        pass
1290 8a0b06d2 Michael Hanselmann
1291 8a0b06d2 Michael Hanselmann
    # Close the connection from our side
1292 73a59d9e Michael Hanselmann
    try:
1293 73a59d9e Michael Hanselmann
      SocketOperation(self.poller, self.sock, SOCKOP_SHUTDOWN,
1294 73a59d9e Michael Hanselmann
                      socket.SHUT_RDWR, self.WRITE_TIMEOUT)
1295 73a59d9e Michael Hanselmann
    except _HttpSocketTimeout:
1296 73a59d9e Michael Hanselmann
      raise _HttpClientError("Timeout while shutting down connection")
1297 73a59d9e Michael Hanselmann
    except socket.error, err:
1298 73a59d9e Michael Hanselmann
      raise _HttpClientError("Error while shutting down connection: %s" % err)
1299 8a0b06d2 Michael Hanselmann
1300 8a0b06d2 Michael Hanselmann
1301 33bbdbec Michael Hanselmann
class _HttpClientPendingRequest(object):
1302 33bbdbec Michael Hanselmann
  """Data class for pending requests.
1303 33bbdbec Michael Hanselmann

1304 33bbdbec Michael Hanselmann
  """
1305 33bbdbec Michael Hanselmann
  def __init__(self, request):
1306 33bbdbec Michael Hanselmann
    self.request = request
1307 33bbdbec Michael Hanselmann
1308 33bbdbec Michael Hanselmann
    # Thread synchronization
1309 33bbdbec Michael Hanselmann
    self.done = threading.Event()
1310 33bbdbec Michael Hanselmann
1311 33bbdbec Michael Hanselmann
1312 8a0b06d2 Michael Hanselmann
class HttpClientWorker(workerpool.BaseWorker):
1313 8a0b06d2 Michael Hanselmann
  """HTTP client worker class.
1314 8a0b06d2 Michael Hanselmann

1315 8a0b06d2 Michael Hanselmann
  """
1316 33bbdbec Michael Hanselmann
  def RunTask(self, pend_req):
1317 33bbdbec Michael Hanselmann
    try:
1318 33bbdbec Michael Hanselmann
      HttpClientRequestExecutor(pend_req.request)
1319 33bbdbec Michael Hanselmann
    finally:
1320 33bbdbec Michael Hanselmann
      pend_req.done.set()
1321 8a0b06d2 Michael Hanselmann
1322 8a0b06d2 Michael Hanselmann
1323 8a0b06d2 Michael Hanselmann
class HttpClientWorkerPool(workerpool.WorkerPool):
1324 8a0b06d2 Michael Hanselmann
  def __init__(self, manager):
1325 8a0b06d2 Michael Hanselmann
    workerpool.WorkerPool.__init__(self, HTTP_CLIENT_THREADS,
1326 8a0b06d2 Michael Hanselmann
                                   HttpClientWorker)
1327 8a0b06d2 Michael Hanselmann
    self.manager = manager
1328 8a0b06d2 Michael Hanselmann
1329 8a0b06d2 Michael Hanselmann
1330 8a0b06d2 Michael Hanselmann
class HttpClientManager(object):
1331 33bbdbec Michael Hanselmann
  """Manages HTTP requests.
1332 33bbdbec Michael Hanselmann

1333 33bbdbec Michael Hanselmann
  """
1334 8a0b06d2 Michael Hanselmann
  def __init__(self):
1335 8a0b06d2 Michael Hanselmann
    self._wpool = HttpClientWorkerPool(self)
1336 8a0b06d2 Michael Hanselmann
1337 8a0b06d2 Michael Hanselmann
  def __del__(self):
1338 8a0b06d2 Michael Hanselmann
    self.Shutdown()
1339 8a0b06d2 Michael Hanselmann
1340 8a0b06d2 Michael Hanselmann
  def ExecRequests(self, requests):
1341 33bbdbec Michael Hanselmann
    """Execute HTTP requests.
1342 8a0b06d2 Michael Hanselmann

1343 33bbdbec Michael Hanselmann
    This function can be called from multiple threads at the same time.
1344 8a0b06d2 Michael Hanselmann

1345 33bbdbec Michael Hanselmann
    @type requests: List of HttpClientRequest instances
1346 33bbdbec Michael Hanselmann
    @param requests: The requests to execute
1347 33bbdbec Michael Hanselmann
    @rtype: List of HttpClientRequest instances
1348 33bbdbec Michael Hanselmann
    @returns: The list of requests passed in
1349 33bbdbec Michael Hanselmann

1350 33bbdbec Michael Hanselmann
    """
1351 33bbdbec Michael Hanselmann
    # _HttpClientPendingRequest is used for internal thread synchronization
1352 33bbdbec Michael Hanselmann
    pending = [_HttpClientPendingRequest(req) for req in requests]
1353 33bbdbec Michael Hanselmann
1354 33bbdbec Michael Hanselmann
    try:
1355 33bbdbec Michael Hanselmann
      # Add requests to queue
1356 33bbdbec Michael Hanselmann
      for pend_req in pending:
1357 33bbdbec Michael Hanselmann
        self._wpool.AddTask(pend_req)
1358 33bbdbec Michael Hanselmann
1359 33bbdbec Michael Hanselmann
    finally:
1360 33bbdbec Michael Hanselmann
      # In case of an exception we should still wait for the rest, otherwise
1361 33bbdbec Michael Hanselmann
      # another thread from the worker pool could modify the request object
1362 33bbdbec Michael Hanselmann
      # after we returned.
1363 33bbdbec Michael Hanselmann
1364 33bbdbec Michael Hanselmann
      # And wait for them to finish
1365 33bbdbec Michael Hanselmann
      for pend_req in pending:
1366 33bbdbec Michael Hanselmann
        pend_req.done.wait()
1367 33bbdbec Michael Hanselmann
1368 33bbdbec Michael Hanselmann
    # Return original list
1369 8a0b06d2 Michael Hanselmann
    return requests
1370 8a0b06d2 Michael Hanselmann
1371 8a0b06d2 Michael Hanselmann
  def Shutdown(self):
1372 33bbdbec Michael Hanselmann
    self._wpool.Quiesce()
1373 8a0b06d2 Michael Hanselmann
    self._wpool.TerminateWorkers()
1374 8a0b06d2 Michael Hanselmann
1375 8a0b06d2 Michael Hanselmann
1376 42242313 Michael Hanselmann
class _SSLFileObject(object):
1377 42242313 Michael Hanselmann
  """Wrapper around socket._fileobject
1378 42242313 Michael Hanselmann

1379 42242313 Michael Hanselmann
  This wrapper is required to handle OpenSSL exceptions.
1380 42242313 Michael Hanselmann

1381 42242313 Michael Hanselmann
  """
1382 42242313 Michael Hanselmann
  def _RequireOpenSocket(fn):
1383 42242313 Michael Hanselmann
    def wrapper(self, *args, **kwargs):
1384 42242313 Michael Hanselmann
      if self.closed:
1385 42242313 Michael Hanselmann
        raise SocketClosed("Socket is closed")
1386 42242313 Michael Hanselmann
      return fn(self, *args, **kwargs)
1387 42242313 Michael Hanselmann
    return wrapper
1388 42242313 Michael Hanselmann
1389 42242313 Michael Hanselmann
  def __init__(self, sock, mode='rb', bufsize=-1):
1390 42242313 Michael Hanselmann
    self._base = socket._fileobject(sock, mode=mode, bufsize=bufsize)
1391 42242313 Michael Hanselmann
1392 42242313 Michael Hanselmann
  def _ConnectionLost(self):
1393 42242313 Michael Hanselmann
    self._base = None
1394 42242313 Michael Hanselmann
1395 42242313 Michael Hanselmann
  def _getclosed(self):
1396 42242313 Michael Hanselmann
    return self._base is None or self._base.closed
1397 42242313 Michael Hanselmann
  closed = property(_getclosed, doc="True if the file is closed")
1398 42242313 Michael Hanselmann
1399 42242313 Michael Hanselmann
  @_RequireOpenSocket
1400 42242313 Michael Hanselmann
  def close(self):
1401 42242313 Michael Hanselmann
    return self._base.close()
1402 42242313 Michael Hanselmann
1403 42242313 Michael Hanselmann
  @_RequireOpenSocket
1404 42242313 Michael Hanselmann
  def flush(self):
1405 42242313 Michael Hanselmann
    return self._base.flush()
1406 42242313 Michael Hanselmann
1407 42242313 Michael Hanselmann
  @_RequireOpenSocket
1408 42242313 Michael Hanselmann
  def fileno(self):
1409 42242313 Michael Hanselmann
    return self._base.fileno()
1410 42242313 Michael Hanselmann
1411 42242313 Michael Hanselmann
  @_RequireOpenSocket
1412 42242313 Michael Hanselmann
  def read(self, size=-1):
1413 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.read, size=size)
1414 42242313 Michael Hanselmann
1415 42242313 Michael Hanselmann
  @_RequireOpenSocket
1416 42242313 Michael Hanselmann
  def readline(self, size=-1):
1417 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.readline, size=size)
1418 42242313 Michael Hanselmann
1419 42242313 Michael Hanselmann
  def _ReadWrapper(self, fn, *args, **kwargs):
1420 42242313 Michael Hanselmann
    while True:
1421 42242313 Michael Hanselmann
      try:
1422 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
1423 42242313 Michael Hanselmann
1424 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
1425 42242313 Michael Hanselmann
        self._ConnectionLost()
1426 42242313 Michael Hanselmann
        return ""
1427 42242313 Michael Hanselmann
1428 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantReadError:
1429 42242313 Michael Hanselmann
        continue
1430 42242313 Michael Hanselmann
1431 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantWriteError:
1432 42242313 Michael Hanselmann
      # TODO
1433 42242313 Michael Hanselmann
1434 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, (retval, desc):
1435 d7bace1b Michael Hanselmann
        if ((retval == -1 and desc == _SSL_UNEXPECTED_EOF)
1436 42242313 Michael Hanselmann
            or retval > 0):
1437 42242313 Michael Hanselmann
          self._ConnectionLost()
1438 42242313 Michael Hanselmann
          return ""
1439 42242313 Michael Hanselmann
1440 42242313 Michael Hanselmann
        logging.exception("Error in OpenSSL")
1441 42242313 Michael Hanselmann
        self._ConnectionLost()
1442 42242313 Michael Hanselmann
        raise socket.error(err.args)
1443 42242313 Michael Hanselmann
1444 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
1445 42242313 Michael Hanselmann
        self._ConnectionLost()
1446 42242313 Michael Hanselmann
        raise socket.error(err.args)
1447 42242313 Michael Hanselmann
1448 42242313 Michael Hanselmann
  @_RequireOpenSocket
1449 42242313 Michael Hanselmann
  def write(self, data):
1450 42242313 Michael Hanselmann
    return self._WriteWrapper(self._base.write, data)
1451 42242313 Michael Hanselmann
1452 42242313 Michael Hanselmann
  def _WriteWrapper(self, fn, *args, **kwargs):
1453 42242313 Michael Hanselmann
    while True:
1454 42242313 Michael Hanselmann
      try:
1455 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
1456 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
1457 42242313 Michael Hanselmann
        self._ConnectionLost()
1458 42242313 Michael Hanselmann
        return 0
1459 42242313 Michael Hanselmann
1460 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantWriteError:
1461 42242313 Michael Hanselmann
        continue
1462 42242313 Michael Hanselmann
1463 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantReadError:
1464 42242313 Michael Hanselmann
      # TODO
1465 42242313 Michael Hanselmann
1466 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, err:
1467 42242313 Michael Hanselmann
        if err.args[0] == -1 and data == "":
1468 42242313 Michael Hanselmann
          # errors when writing empty strings are expected
1469 42242313 Michael Hanselmann
          # and can be ignored
1470 42242313 Michael Hanselmann
          return 0
1471 42242313 Michael Hanselmann
1472 42242313 Michael Hanselmann
        self._ConnectionLost()
1473 42242313 Michael Hanselmann
        raise socket.error(err.args)
1474 42242313 Michael Hanselmann
1475 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
1476 42242313 Michael Hanselmann
        self._ConnectionLost()
1477 42242313 Michael Hanselmann
        raise socket.error(err.args)