Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ b1d979cf

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

106 438a366a Michael Hanselmann
  This should only be used for internal error reporting.
107 438a366a Michael Hanselmann

108 438a366a Michael Hanselmann
  """
109 73a59d9e Michael Hanselmann
110 73a59d9e Michael Hanselmann
111 73a59d9e Michael Hanselmann
class _HttpSocketTimeout(Exception):
112 73a59d9e Michael Hanselmann
  """Internal exception for socket timeouts.
113 73a59d9e Michael Hanselmann

114 73a59d9e Michael Hanselmann
  This should only be used for internal error reporting.
115 73a59d9e Michael Hanselmann

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

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

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

217 73a59d9e Michael Hanselmann
  This function abstracts error handling for socket operations, especially
218 73a59d9e Michael Hanselmann
  for the complicated interaction with OpenSSL.
219 73a59d9e Michael Hanselmann

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

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

333 f20cbea2 Michael Hanselmann
  """
334 f20cbea2 Michael Hanselmann
  def __init__(self, ssl_key_path, ssl_cert_path):
335 f20cbea2 Michael Hanselmann
    """Initializes this class.
336 f20cbea2 Michael Hanselmann

337 f20cbea2 Michael Hanselmann
    @type ssl_key_path: string
338 f20cbea2 Michael Hanselmann
    @param ssl_key_path: Path to file containing SSL key in PEM format
339 f20cbea2 Michael Hanselmann
    @type ssl_cert_path: string
340 f20cbea2 Michael Hanselmann
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
341 f20cbea2 Michael Hanselmann

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

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

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

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

405 b14f759e Michael Hanselmann
    We only compare fingerprints. The client must use the same certificate as
406 b14f759e Michael Hanselmann
    we do on our side.
407 b14f759e Michael Hanselmann

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

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

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

438 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
439 42242313 Michael Hanselmann
    data sent by the client.
440 42242313 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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