Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ 0c223ea9

History | View | Annotate | Download (40.7 kB)

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

20 a43f68dc Michael Hanselmann
"""
21 a43f68dc Michael Hanselmann
22 a43f68dc Michael Hanselmann
import BaseHTTPServer
23 42242313 Michael Hanselmann
import cgi
24 42242313 Michael Hanselmann
import logging
25 42242313 Michael Hanselmann
import mimetools
26 a43f68dc Michael Hanselmann
import OpenSSL
27 42242313 Michael Hanselmann
import os
28 42242313 Michael Hanselmann
import select
29 42242313 Michael Hanselmann
import socket
30 42242313 Michael Hanselmann
import sys
31 a43f68dc Michael Hanselmann
import time
32 42242313 Michael Hanselmann
import signal
33 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 42242313 Michael Hanselmann
94 42242313 Michael Hanselmann
class SocketClosed(socket.error):
95 42242313 Michael Hanselmann
  pass
96 42242313 Michael Hanselmann
97 42242313 Michael Hanselmann
98 438a366a Michael Hanselmann
class _HttpClientError(Exception):
99 438a366a Michael Hanselmann
  """Internal exception for HTTP client errors.
100 438a366a Michael Hanselmann

101 438a366a Michael Hanselmann
  This should only be used for internal error reporting.
102 438a366a Michael Hanselmann

103 438a366a Michael Hanselmann
  """
104 8a0b06d2 Michael Hanselmann
  pass
105 8a0b06d2 Michael Hanselmann
106 8a0b06d2 Michael Hanselmann
107 a43f68dc Michael Hanselmann
class HTTPException(Exception):
108 a43f68dc Michael Hanselmann
  code = None
109 a43f68dc Michael Hanselmann
  message = None
110 a43f68dc Michael Hanselmann
111 a43f68dc Michael Hanselmann
  def __init__(self, message=None):
112 42242313 Michael Hanselmann
    Exception.__init__(self)
113 a43f68dc Michael Hanselmann
    if message is not None:
114 a43f68dc Michael Hanselmann
      self.message = message
115 a43f68dc Michael Hanselmann
116 a43f68dc Michael Hanselmann
117 a43f68dc Michael Hanselmann
class HTTPBadRequest(HTTPException):
118 a43f68dc Michael Hanselmann
  code = 400
119 a43f68dc Michael Hanselmann
120 a43f68dc Michael Hanselmann
121 a43f68dc Michael Hanselmann
class HTTPForbidden(HTTPException):
122 a43f68dc Michael Hanselmann
  code = 403
123 a43f68dc Michael Hanselmann
124 a43f68dc Michael Hanselmann
125 a43f68dc Michael Hanselmann
class HTTPNotFound(HTTPException):
126 a43f68dc Michael Hanselmann
  code = 404
127 a43f68dc Michael Hanselmann
128 a43f68dc Michael Hanselmann
129 a43f68dc Michael Hanselmann
class HTTPGone(HTTPException):
130 a43f68dc Michael Hanselmann
  code = 410
131 a43f68dc Michael Hanselmann
132 a43f68dc Michael Hanselmann
133 a43f68dc Michael Hanselmann
class HTTPLengthRequired(HTTPException):
134 a43f68dc Michael Hanselmann
  code = 411
135 a43f68dc Michael Hanselmann
136 a43f68dc Michael Hanselmann
137 a43f68dc Michael Hanselmann
class HTTPInternalError(HTTPException):
138 a43f68dc Michael Hanselmann
  code = 500
139 a43f68dc Michael Hanselmann
140 a43f68dc Michael Hanselmann
141 a43f68dc Michael Hanselmann
class HTTPNotImplemented(HTTPException):
142 a43f68dc Michael Hanselmann
  code = 501
143 a43f68dc Michael Hanselmann
144 a43f68dc Michael Hanselmann
145 a43f68dc Michael Hanselmann
class HTTPServiceUnavailable(HTTPException):
146 a43f68dc Michael Hanselmann
  code = 503
147 a43f68dc Michael Hanselmann
148 a43f68dc Michael Hanselmann
149 42242313 Michael Hanselmann
class HTTPVersionNotSupported(HTTPException):
150 42242313 Michael Hanselmann
  code = 505
151 42242313 Michael Hanselmann
152 42242313 Michael Hanselmann
153 a43f68dc Michael Hanselmann
class ApacheLogfile:
154 a43f68dc Michael Hanselmann
  """Utility class to write HTTP server log files.
155 a43f68dc Michael Hanselmann

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

159 a43f68dc Michael Hanselmann
  """
160 a43f68dc Michael Hanselmann
  def __init__(self, fd):
161 a43f68dc Michael Hanselmann
    """Constructor for ApacheLogfile class.
162 a43f68dc Michael Hanselmann

163 a43f68dc Michael Hanselmann
    Args:
164 a43f68dc Michael Hanselmann
    - fd: Open file object
165 a43f68dc Michael Hanselmann

166 a43f68dc Michael Hanselmann
    """
167 a43f68dc Michael Hanselmann
    self._fd = fd
168 a43f68dc Michael Hanselmann
169 a43f68dc Michael Hanselmann
  def LogRequest(self, request, format, *args):
170 a43f68dc Michael Hanselmann
    self._fd.write("%s %s %s [%s] %s\n" % (
171 a43f68dc Michael Hanselmann
      # Remote host address
172 a43f68dc Michael Hanselmann
      request.address_string(),
173 a43f68dc Michael Hanselmann
174 a43f68dc Michael Hanselmann
      # RFC1413 identity (identd)
175 a43f68dc Michael Hanselmann
      "-",
176 a43f68dc Michael Hanselmann
177 a43f68dc Michael Hanselmann
      # Remote user
178 a43f68dc Michael Hanselmann
      "-",
179 a43f68dc Michael Hanselmann
180 a43f68dc Michael Hanselmann
      # Request time
181 a43f68dc Michael Hanselmann
      self._FormatCurrentTime(),
182 a43f68dc Michael Hanselmann
183 a43f68dc Michael Hanselmann
      # Message
184 a43f68dc Michael Hanselmann
      format % args,
185 a43f68dc Michael Hanselmann
      ))
186 a0638838 Oleksiy Mishchenko
    self._fd.flush()
187 a43f68dc Michael Hanselmann
188 a43f68dc Michael Hanselmann
  def _FormatCurrentTime(self):
189 a43f68dc Michael Hanselmann
    """Formats current time in Common Log Format.
190 a43f68dc Michael Hanselmann

191 a43f68dc Michael Hanselmann
    """
192 a43f68dc Michael Hanselmann
    return self._FormatLogTime(time.time())
193 a43f68dc Michael Hanselmann
194 a43f68dc Michael Hanselmann
  def _FormatLogTime(self, seconds):
195 a43f68dc Michael Hanselmann
    """Formats time for Common Log Format.
196 a43f68dc Michael Hanselmann

197 a43f68dc Michael Hanselmann
    All timestamps are logged in the UTC timezone.
198 a43f68dc Michael Hanselmann

199 a43f68dc Michael Hanselmann
    Args:
200 a43f68dc Michael Hanselmann
    - seconds: Time in seconds since the epoch
201 a43f68dc Michael Hanselmann

202 a43f68dc Michael Hanselmann
    """
203 a43f68dc Michael Hanselmann
    (_, month, _, _, _, _, _, _, _) = tm = time.gmtime(seconds)
204 42242313 Michael Hanselmann
    format = "%d/" + MONTHNAME[month] + "/%Y:%H:%M:%S +0000"
205 a43f68dc Michael Hanselmann
    return time.strftime(format, tm)
206 a43f68dc Michael Hanselmann
207 a43f68dc Michael Hanselmann
208 a43f68dc Michael Hanselmann
class HTTPJsonConverter:
209 a43f68dc Michael Hanselmann
  CONTENT_TYPE = "application/json"
210 a43f68dc Michael Hanselmann
211 a43f68dc Michael Hanselmann
  def Encode(self, data):
212 a43f68dc Michael Hanselmann
    return serializer.DumpJson(data)
213 a43f68dc Michael Hanselmann
214 a43f68dc Michael Hanselmann
  def Decode(self, data):
215 a43f68dc Michael Hanselmann
    return serializer.LoadJson(data)
216 a43f68dc Michael Hanselmann
217 a43f68dc Michael Hanselmann
218 b14f759e Michael Hanselmann
class _HttpSocketBase(object):
219 b14f759e Michael Hanselmann
  """Base class for HTTP server and client.
220 b14f759e Michael Hanselmann

221 b14f759e Michael Hanselmann
  """
222 b14f759e Michael Hanselmann
  def __init__(self):
223 b14f759e Michael Hanselmann
    self._using_ssl = None
224 b14f759e Michael Hanselmann
    self._ssl_cert = None
225 b14f759e Michael Hanselmann
    self._ssl_key = None
226 b14f759e Michael Hanselmann
227 b14f759e Michael Hanselmann
  def _CreateSocket(self, ssl_key_path, ssl_cert_path, ssl_verify_peer):
228 b14f759e Michael Hanselmann
    """Creates a TCP socket and initializes SSL if needed.
229 b14f759e Michael Hanselmann

230 b14f759e Michael Hanselmann
    @type ssl_key_path: string
231 b14f759e Michael Hanselmann
    @param ssl_key_path: Path to file containing SSL key in PEM format
232 b14f759e Michael Hanselmann
    @type ssl_cert_path: string
233 b14f759e Michael Hanselmann
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
234 b14f759e Michael Hanselmann
    @type ssl_verify_peer: bool
235 b14f759e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
236 b14f759e Michael Hanselmann
                            it with our certificate
237 b14f759e Michael Hanselmann

238 b14f759e Michael Hanselmann
    """
239 b14f759e Michael Hanselmann
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
240 b14f759e Michael Hanselmann
241 b14f759e Michael Hanselmann
    # Should we enable SSL?
242 b14f759e Michael Hanselmann
    self._using_ssl = (ssl_cert_path and ssl_key_path)
243 b14f759e Michael Hanselmann
244 b14f759e Michael Hanselmann
    if not self._using_ssl:
245 b14f759e Michael Hanselmann
      return sock
246 b14f759e Michael Hanselmann
247 b14f759e Michael Hanselmann
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
248 b14f759e Michael Hanselmann
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
249 b14f759e Michael Hanselmann
250 b14f759e Michael Hanselmann
    ssl_key_pem = utils.ReadFile(ssl_key_path)
251 b14f759e Michael Hanselmann
    ssl_cert_pem = utils.ReadFile(ssl_cert_path)
252 b14f759e Michael Hanselmann
253 b14f759e Michael Hanselmann
    cr = OpenSSL.crypto
254 b14f759e Michael Hanselmann
    self._ssl_cert = cr.load_certificate(cr.FILETYPE_PEM, ssl_cert_pem)
255 b14f759e Michael Hanselmann
    self._ssl_key = cr.load_privatekey(cr.FILETYPE_PEM, ssl_key_pem)
256 b14f759e Michael Hanselmann
    del cr
257 b14f759e Michael Hanselmann
258 b14f759e Michael Hanselmann
    ctx.use_privatekey(self._ssl_key)
259 b14f759e Michael Hanselmann
    ctx.use_certificate(self._ssl_cert)
260 b14f759e Michael Hanselmann
    ctx.check_privatekey()
261 b14f759e Michael Hanselmann
262 b14f759e Michael Hanselmann
    if ssl_verify_peer:
263 b14f759e Michael Hanselmann
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
264 b14f759e Michael Hanselmann
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
265 b14f759e Michael Hanselmann
                     self._SSLVerifyCallback)
266 b14f759e Michael Hanselmann
267 b14f759e Michael Hanselmann
    return OpenSSL.SSL.Connection(ctx, sock)
268 b14f759e Michael Hanselmann
269 b14f759e Michael Hanselmann
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
270 b14f759e Michael Hanselmann
    """Verify the certificate provided by the peer
271 b14f759e Michael Hanselmann

272 b14f759e Michael Hanselmann
    We only compare fingerprints. The client must use the same certificate as
273 b14f759e Michael Hanselmann
    we do on our side.
274 b14f759e Michael Hanselmann

275 b14f759e Michael Hanselmann
    """
276 b14f759e Michael Hanselmann
    assert self._ssl_cert and self._ssl_key, "SSL not initialized"
277 b14f759e Michael Hanselmann
278 b14f759e Michael Hanselmann
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
279 b14f759e Michael Hanselmann
            self._ssl_cert.digest("md5") == cert.digest("md5"))
280 b14f759e Michael Hanselmann
281 b14f759e Michael Hanselmann
282 42242313 Michael Hanselmann
class _HttpConnectionHandler(object):
283 42242313 Michael Hanselmann
  """Implements server side of HTTP
284 42242313 Michael Hanselmann

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

289 42242313 Michael Hanselmann
  """
290 42242313 Michael Hanselmann
  # The default request version.  This only affects responses up until
291 42242313 Michael Hanselmann
  # the point where the request line is parsed, so it mainly decides what
292 42242313 Michael Hanselmann
  # the client gets back when sending a malformed request line.
293 42242313 Michael Hanselmann
  # Most web servers default to HTTP 0.9, i.e. don't send a status line.
294 42242313 Michael Hanselmann
  default_request_version = HTTP_0_9
295 42242313 Michael Hanselmann
296 42242313 Michael Hanselmann
  # Error message settings
297 42242313 Michael Hanselmann
  error_message_format = DEFAULT_ERROR_MESSAGE
298 42242313 Michael Hanselmann
  error_content_type = DEFAULT_ERROR_CONTENT_TYPE
299 42242313 Michael Hanselmann
300 42242313 Michael Hanselmann
  responses = BaseHTTPServer.BaseHTTPRequestHandler.responses
301 42242313 Michael Hanselmann
302 42242313 Michael Hanselmann
  def __init__(self, server, conn, client_addr, fileio_class):
303 42242313 Michael Hanselmann
    """Initializes this class.
304 42242313 Michael Hanselmann

305 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
306 42242313 Michael Hanselmann
    data sent by the client.
307 42242313 Michael Hanselmann

308 42242313 Michael Hanselmann
    """
309 42242313 Michael Hanselmann
    self._server = server
310 42242313 Michael Hanselmann
311 42242313 Michael Hanselmann
    # We default rfile to buffered because otherwise it could be
312 42242313 Michael Hanselmann
    # really slow for large data (a getc() call per byte); we make
313 42242313 Michael Hanselmann
    # wfile unbuffered because (a) often after a write() we want to
314 42242313 Michael Hanselmann
    # read and we need to flush the line; (b) big writes to unbuffered
315 42242313 Michael Hanselmann
    # files are typically optimized by stdio even when big reads
316 42242313 Michael Hanselmann
    # aren't.
317 42242313 Michael Hanselmann
    self.rfile = fileio_class(conn, mode="rb", bufsize=-1)
318 42242313 Michael Hanselmann
    self.wfile = fileio_class(conn, mode="wb", bufsize=0)
319 42242313 Michael Hanselmann
320 42242313 Michael Hanselmann
    self.client_addr = client_addr
321 42242313 Michael Hanselmann
322 42242313 Michael Hanselmann
    self.request_headers = None
323 42242313 Michael Hanselmann
    self.request_method = None
324 42242313 Michael Hanselmann
    self.request_path = None
325 42242313 Michael Hanselmann
    self.request_requestline = None
326 42242313 Michael Hanselmann
    self.request_version = self.default_request_version
327 42242313 Michael Hanselmann
328 42242313 Michael Hanselmann
    self.response_body = None
329 42242313 Michael Hanselmann
    self.response_code = HTTP_OK
330 42242313 Michael Hanselmann
    self.response_content_type = None
331 713faea6 Oleksiy Mishchenko
    self.response_headers = {}
332 42242313 Michael Hanselmann
333 42242313 Michael Hanselmann
    self.should_fork = False
334 42242313 Michael Hanselmann
335 42242313 Michael Hanselmann
    try:
336 42242313 Michael Hanselmann
      self._ReadRequest()
337 42242313 Michael Hanselmann
      self._ReadPostData()
338 42242313 Michael Hanselmann
    except HTTPException, err:
339 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
340 42242313 Michael Hanselmann
341 42242313 Michael Hanselmann
  def Close(self):
342 42242313 Michael Hanselmann
    if not self.wfile.closed:
343 42242313 Michael Hanselmann
      self.wfile.flush()
344 42242313 Michael Hanselmann
    self.wfile.close()
345 42242313 Michael Hanselmann
    self.rfile.close()
346 42242313 Michael Hanselmann
347 42242313 Michael Hanselmann
  def _DateTimeHeader(self):
348 42242313 Michael Hanselmann
    """Return the current date and time formatted for a message header.
349 42242313 Michael Hanselmann

350 42242313 Michael Hanselmann
    """
351 42242313 Michael Hanselmann
    (year, month, day, hh, mm, ss, wd, _, _) = time.gmtime()
352 42242313 Michael Hanselmann
    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
353 42242313 Michael Hanselmann
            (WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
354 42242313 Michael Hanselmann
355 42242313 Michael Hanselmann
  def _SetErrorStatus(self, err):
356 42242313 Michael Hanselmann
    """Sets the response code and body from a HTTPException.
357 42242313 Michael Hanselmann

358 42242313 Michael Hanselmann
    @type err: HTTPException
359 42242313 Michael Hanselmann
    @param err: Exception instance
360 42242313 Michael Hanselmann

361 42242313 Michael Hanselmann
    """
362 42242313 Michael Hanselmann
    try:
363 42242313 Michael Hanselmann
      (shortmsg, longmsg) = self.responses[err.code]
364 42242313 Michael Hanselmann
    except KeyError:
365 42242313 Michael Hanselmann
      shortmsg = longmsg = "Unknown"
366 42242313 Michael Hanselmann
367 42242313 Michael Hanselmann
    if err.message:
368 42242313 Michael Hanselmann
      message = err.message
369 42242313 Michael Hanselmann
    else:
370 42242313 Michael Hanselmann
      message = shortmsg
371 42242313 Michael Hanselmann
372 42242313 Michael Hanselmann
    values = {
373 42242313 Michael Hanselmann
      "code": err.code,
374 42242313 Michael Hanselmann
      "message": cgi.escape(message),
375 42242313 Michael Hanselmann
      "explain": longmsg,
376 42242313 Michael Hanselmann
      }
377 42242313 Michael Hanselmann
378 42242313 Michael Hanselmann
    self.response_code = err.code
379 42242313 Michael Hanselmann
    self.response_content_type = self.error_content_type
380 42242313 Michael Hanselmann
    self.response_body = self.error_message_format % values
381 42242313 Michael Hanselmann
382 42242313 Michael Hanselmann
  def HandleRequest(self):
383 42242313 Michael Hanselmann
    """Handle the actual request.
384 42242313 Michael Hanselmann

385 42242313 Michael Hanselmann
    Calls the actual handler function and converts exceptions into HTTP errors.
386 42242313 Michael Hanselmann

387 42242313 Michael Hanselmann
    """
388 42242313 Michael Hanselmann
    # Don't do anything if there's already been a problem
389 42242313 Michael Hanselmann
    if self.response_code != HTTP_OK:
390 42242313 Michael Hanselmann
      return
391 42242313 Michael Hanselmann
392 42242313 Michael Hanselmann
    assert self.request_method, "Status code %s requires a method" % HTTP_OK
393 42242313 Michael Hanselmann
394 42242313 Michael Hanselmann
    # Check whether client is still there
395 42242313 Michael Hanselmann
    self.rfile.read(0)
396 42242313 Michael Hanselmann
397 42242313 Michael Hanselmann
    try:
398 42242313 Michael Hanselmann
      try:
399 42242313 Michael Hanselmann
        result = self._server.HandleRequest(self)
400 42242313 Michael Hanselmann
401 42242313 Michael Hanselmann
        # TODO: Content-type
402 42242313 Michael Hanselmann
        encoder = HTTPJsonConverter()
403 42242313 Michael Hanselmann
        body = encoder.Encode(result)
404 42242313 Michael Hanselmann
405 42242313 Michael Hanselmann
        self.response_content_type = encoder.CONTENT_TYPE
406 42242313 Michael Hanselmann
        self.response_body = body
407 42242313 Michael Hanselmann
      except (HTTPException, KeyboardInterrupt, SystemExit):
408 42242313 Michael Hanselmann
        raise
409 42242313 Michael Hanselmann
      except Exception, err:
410 42242313 Michael Hanselmann
        logging.exception("Caught exception")
411 42242313 Michael Hanselmann
        raise HTTPInternalError(message=str(err))
412 42242313 Michael Hanselmann
      except:
413 42242313 Michael Hanselmann
        logging.exception("Unknown exception")
414 42242313 Michael Hanselmann
        raise HTTPInternalError(message="Unknown error")
415 42242313 Michael Hanselmann
416 42242313 Michael Hanselmann
    except HTTPException, err:
417 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
418 42242313 Michael Hanselmann
419 42242313 Michael Hanselmann
  def SendResponse(self):
420 42242313 Michael Hanselmann
    """Sends response to the client.
421 42242313 Michael Hanselmann

422 42242313 Michael Hanselmann
    """
423 42242313 Michael Hanselmann
    # Check whether client is still there
424 42242313 Michael Hanselmann
    self.rfile.read(0)
425 42242313 Michael Hanselmann
426 42242313 Michael Hanselmann
    logging.info("%s:%s %s %s", self.client_addr[0], self.client_addr[1],
427 42242313 Michael Hanselmann
                 self.request_requestline, self.response_code)
428 42242313 Michael Hanselmann
429 42242313 Michael Hanselmann
    if self.response_code in self.responses:
430 42242313 Michael Hanselmann
      response_message = self.responses[self.response_code][0]
431 42242313 Michael Hanselmann
    else:
432 42242313 Michael Hanselmann
      response_message = ""
433 42242313 Michael Hanselmann
434 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
435 42242313 Michael Hanselmann
      self.wfile.write("%s %d %s\r\n" %
436 42242313 Michael Hanselmann
                       (self.request_version, self.response_code,
437 42242313 Michael Hanselmann
                        response_message))
438 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_SERVER, HTTP_GANETI_VERSION)
439 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_DATE, self._DateTimeHeader())
440 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_TYPE, self.response_content_type)
441 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_LENGTH, str(len(self.response_body)))
442 713faea6 Oleksiy Mishchenko
      for key, val in self.response_headers.iteritems():
443 713faea6 Oleksiy Mishchenko
        self._SendHeader(key, val)
444 713faea6 Oleksiy Mishchenko
445 42242313 Michael Hanselmann
      # We don't support keep-alive at this time
446 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONNECTION, "close")
447 42242313 Michael Hanselmann
      self.wfile.write("\r\n")
448 42242313 Michael Hanselmann
449 42242313 Michael Hanselmann
    if (self.request_method != HTTP_HEAD and
450 42242313 Michael Hanselmann
        self.response_code >= HTTP_OK and
451 42242313 Michael Hanselmann
        self.response_code not in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED)):
452 42242313 Michael Hanselmann
      self.wfile.write(self.response_body)
453 42242313 Michael Hanselmann
454 42242313 Michael Hanselmann
  def _SendHeader(self, name, value):
455 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
456 42242313 Michael Hanselmann
      self.wfile.write("%s: %s\r\n" % (name, value))
457 42242313 Michael Hanselmann
458 42242313 Michael Hanselmann
  def _ReadRequest(self):
459 42242313 Michael Hanselmann
    """Reads and parses request line
460 42242313 Michael Hanselmann

461 42242313 Michael Hanselmann
    """
462 42242313 Michael Hanselmann
    raw_requestline = self.rfile.readline()
463 42242313 Michael Hanselmann
464 42242313 Michael Hanselmann
    requestline = raw_requestline
465 42242313 Michael Hanselmann
    if requestline[-2:] == '\r\n':
466 42242313 Michael Hanselmann
      requestline = requestline[:-2]
467 42242313 Michael Hanselmann
    elif requestline[-1:] == '\n':
468 42242313 Michael Hanselmann
      requestline = requestline[:-1]
469 42242313 Michael Hanselmann
470 42242313 Michael Hanselmann
    if not requestline:
471 42242313 Michael Hanselmann
      raise HTTPBadRequest("Empty request line")
472 42242313 Michael Hanselmann
473 42242313 Michael Hanselmann
    self.request_requestline = requestline
474 42242313 Michael Hanselmann
475 42242313 Michael Hanselmann
    logging.debug("HTTP request: %s", raw_requestline.rstrip("\r\n"))
476 42242313 Michael Hanselmann
477 42242313 Michael Hanselmann
    words = requestline.split()
478 42242313 Michael Hanselmann
479 42242313 Michael Hanselmann
    if len(words) == 3:
480 42242313 Michael Hanselmann
      [method, path, version] = words
481 42242313 Michael Hanselmann
      if version[:5] != 'HTTP/':
482 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
483 42242313 Michael Hanselmann
484 42242313 Michael Hanselmann
      try:
485 42242313 Michael Hanselmann
        base_version_number = version.split('/', 1)[1]
486 42242313 Michael Hanselmann
        version_number = base_version_number.split(".")
487 42242313 Michael Hanselmann
488 42242313 Michael Hanselmann
        # RFC 2145 section 3.1 says there can be only one "." and
489 42242313 Michael Hanselmann
        #   - major and minor numbers MUST be treated as
490 42242313 Michael Hanselmann
        #      separate integers;
491 42242313 Michael Hanselmann
        #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
492 42242313 Michael Hanselmann
        #      turn is lower than HTTP/12.3;
493 42242313 Michael Hanselmann
        #   - Leading zeros MUST be ignored by recipients.
494 42242313 Michael Hanselmann
        if len(version_number) != 2:
495 42242313 Michael Hanselmann
          raise HTTPBadRequest("Bad request version (%r)" % version)
496 42242313 Michael Hanselmann
497 42242313 Michael Hanselmann
        version_number = int(version_number[0]), int(version_number[1])
498 42242313 Michael Hanselmann
      except (ValueError, IndexError):
499 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
500 42242313 Michael Hanselmann
501 42242313 Michael Hanselmann
      if version_number >= (2, 0):
502 42242313 Michael Hanselmann
        raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
503 42242313 Michael Hanselmann
                                      base_version_number)
504 42242313 Michael Hanselmann
505 42242313 Michael Hanselmann
    elif len(words) == 2:
506 42242313 Michael Hanselmann
      version = HTTP_0_9
507 42242313 Michael Hanselmann
      [method, path] = words
508 42242313 Michael Hanselmann
      if method != HTTP_GET:
509 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
510 42242313 Michael Hanselmann
511 42242313 Michael Hanselmann
    else:
512 42242313 Michael Hanselmann
      raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
513 42242313 Michael Hanselmann
514 42242313 Michael Hanselmann
    # Examine the headers and look for a Connection directive
515 42242313 Michael Hanselmann
    headers = mimetools.Message(self.rfile, 0)
516 42242313 Michael Hanselmann
517 42242313 Michael Hanselmann
    self.request_method = method
518 42242313 Michael Hanselmann
    self.request_path = path
519 42242313 Michael Hanselmann
    self.request_version = version
520 42242313 Michael Hanselmann
    self.request_headers = headers
521 42242313 Michael Hanselmann
522 42242313 Michael Hanselmann
  def _ReadPostData(self):
523 42242313 Michael Hanselmann
    """Reads POST/PUT data
524 42242313 Michael Hanselmann

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

530 42242313 Michael Hanselmann
    """
531 64357ed8 Michael Hanselmann
    # While not according to specification, we only support an entity body for
532 64357ed8 Michael Hanselmann
    # POST and PUT.
533 8a9f9060 Michael Hanselmann
    if (not self.request_method or
534 8a9f9060 Michael Hanselmann
        self.request_method.upper() not in (HTTP_POST, HTTP_PUT)):
535 42242313 Michael Hanselmann
      self.request_post_data = None
536 42242313 Michael Hanselmann
      return
537 42242313 Michael Hanselmann
538 64357ed8 Michael Hanselmann
    content_length = None
539 42242313 Michael Hanselmann
    try:
540 64357ed8 Michael Hanselmann
      if HTTP_CONTENT_LENGTH in self.request_headers:
541 64357ed8 Michael Hanselmann
        content_length = int(self.request_headers[HTTP_CONTENT_LENGTH])
542 64357ed8 Michael Hanselmann
    except TypeError:
543 64357ed8 Michael Hanselmann
      pass
544 42242313 Michael Hanselmann
    except ValueError:
545 64357ed8 Michael Hanselmann
      pass
546 64357ed8 Michael Hanselmann
547 64357ed8 Michael Hanselmann
    # 411 Length Required is specified in RFC2616, section 10.4.12 (HTTP/1.1)
548 64357ed8 Michael Hanselmann
    if content_length is None:
549 64357ed8 Michael Hanselmann
      raise HTTPLengthRequired("Missing Content-Length header or"
550 64357ed8 Michael Hanselmann
                               " invalid format")
551 42242313 Michael Hanselmann
552 42242313 Michael Hanselmann
    data = self.rfile.read(content_length)
553 42242313 Michael Hanselmann
554 42242313 Michael Hanselmann
    # TODO: Content-type, error handling
555 7c46aafd Oleksiy Mishchenko
    if data:
556 7c46aafd Oleksiy Mishchenko
      self.request_post_data = HTTPJsonConverter().Decode(data)
557 7c46aafd Oleksiy Mishchenko
    else:
558 7c46aafd Oleksiy Mishchenko
      self.request_post_data = None
559 42242313 Michael Hanselmann
560 42242313 Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.request_post_data)
561 42242313 Michael Hanselmann
562 42242313 Michael Hanselmann
563 b14f759e Michael Hanselmann
class HttpServer(_HttpSocketBase):
564 42242313 Michael Hanselmann
  """Generic HTTP server class
565 42242313 Michael Hanselmann

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

568 42242313 Michael Hanselmann
  """
569 42242313 Michael Hanselmann
  MAX_CHILDREN = 20
570 42242313 Michael Hanselmann
571 f2a6fc9e Michael Hanselmann
  def __init__(self, mainloop, local_address, port,
572 f2a6fc9e Michael Hanselmann
               ssl_key_path=None, ssl_cert_path=None, ssl_verify_peer=False):
573 23e46494 Michael Hanselmann
    """Initializes the HTTP server
574 23e46494 Michael Hanselmann

575 23e46494 Michael Hanselmann
    @type mainloop: ganeti.daemon.Mainloop
576 23e46494 Michael Hanselmann
    @param mainloop: Mainloop used to poll for I/O events
577 23e46494 Michael Hanselmann
    @type local_addess: string
578 23e46494 Michael Hanselmann
    @param local_address: Local IP address to bind to
579 23e46494 Michael Hanselmann
    @type port: int
580 23e46494 Michael Hanselmann
    @param port: TCP port to listen on
581 f2a6fc9e Michael Hanselmann
    @type ssl_key_path: string
582 f2a6fc9e Michael Hanselmann
    @param ssl_key_path: Path to file containing SSL key in PEM format
583 f2a6fc9e Michael Hanselmann
    @type ssl_cert_path: string
584 f2a6fc9e Michael Hanselmann
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
585 f2a6fc9e Michael Hanselmann
    @type ssl_verify_peer: bool
586 f2a6fc9e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
587 f2a6fc9e Michael Hanselmann
                            it with our certificate
588 23e46494 Michael Hanselmann

589 23e46494 Michael Hanselmann
    """
590 b14f759e Michael Hanselmann
    _HttpSocketBase.__init__(self)
591 b14f759e Michael Hanselmann
592 42242313 Michael Hanselmann
    self.mainloop = mainloop
593 23e46494 Michael Hanselmann
    self.local_address = local_address
594 23e46494 Michael Hanselmann
    self.port = port
595 42242313 Michael Hanselmann
596 b14f759e Michael Hanselmann
    self.socket = self._CreateSocket(ssl_key_path, ssl_cert_path, ssl_verify_peer)
597 f2a6fc9e Michael Hanselmann
598 b14f759e Michael Hanselmann
    # Allow port to be reused
599 b14f759e Michael Hanselmann
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
600 42242313 Michael Hanselmann
601 b14f759e Michael Hanselmann
    if self._using_ssl:
602 42242313 Michael Hanselmann
      self._fileio_class = _SSLFileObject
603 42242313 Michael Hanselmann
    else:
604 42242313 Michael Hanselmann
      self._fileio_class = socket._fileobject
605 42242313 Michael Hanselmann
606 42242313 Michael Hanselmann
    self._children = []
607 42242313 Michael Hanselmann
608 42242313 Michael Hanselmann
    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
609 42242313 Michael Hanselmann
    mainloop.RegisterSignal(self)
610 42242313 Michael Hanselmann
611 42242313 Michael Hanselmann
  def Start(self):
612 23e46494 Michael Hanselmann
    self.socket.bind((self.local_address, self.port))
613 42242313 Michael Hanselmann
    self.socket.listen(5)
614 42242313 Michael Hanselmann
615 42242313 Michael Hanselmann
  def Stop(self):
616 42242313 Michael Hanselmann
    self.socket.close()
617 42242313 Michael Hanselmann
618 42242313 Michael Hanselmann
  def OnIO(self, fd, condition):
619 42242313 Michael Hanselmann
    if condition & select.POLLIN:
620 42242313 Michael Hanselmann
      self._IncomingConnection()
621 42242313 Michael Hanselmann
622 42242313 Michael Hanselmann
  def OnSignal(self, signum):
623 42242313 Michael Hanselmann
    if signum == signal.SIGCHLD:
624 42242313 Michael Hanselmann
      self._CollectChildren(True)
625 42242313 Michael Hanselmann
626 42242313 Michael Hanselmann
  def _CollectChildren(self, quick):
627 42242313 Michael Hanselmann
    """Checks whether any child processes are done
628 42242313 Michael Hanselmann

629 42242313 Michael Hanselmann
    @type quick: bool
630 42242313 Michael Hanselmann
    @param quick: Whether to only use non-blocking functions
631 42242313 Michael Hanselmann

632 42242313 Michael Hanselmann
    """
633 42242313 Michael Hanselmann
    if not quick:
634 42242313 Michael Hanselmann
      # Don't wait for other processes if it should be a quick check
635 42242313 Michael Hanselmann
      while len(self._children) > self.MAX_CHILDREN:
636 42242313 Michael Hanselmann
        try:
637 6526ddcd Michael Hanselmann
          # Waiting without a timeout brings us into a potential DoS situation.
638 6526ddcd Michael Hanselmann
          # As soon as too many children run, we'll not respond to new
639 6526ddcd Michael Hanselmann
          # requests. The real solution would be to add a timeout for children
640 6526ddcd Michael Hanselmann
          # and killing them after some time.
641 42242313 Michael Hanselmann
          pid, status = os.waitpid(0, 0)
642 42242313 Michael Hanselmann
        except os.error:
643 42242313 Michael Hanselmann
          pid = None
644 42242313 Michael Hanselmann
        if pid and pid in self._children:
645 42242313 Michael Hanselmann
          self._children.remove(pid)
646 42242313 Michael Hanselmann
647 42242313 Michael Hanselmann
    for child in self._children:
648 42242313 Michael Hanselmann
      try:
649 42242313 Michael Hanselmann
        pid, status = os.waitpid(child, os.WNOHANG)
650 42242313 Michael Hanselmann
      except os.error:
651 42242313 Michael Hanselmann
        pid = None
652 42242313 Michael Hanselmann
      if pid and pid in self._children:
653 42242313 Michael Hanselmann
        self._children.remove(pid)
654 42242313 Michael Hanselmann
655 42242313 Michael Hanselmann
  def _IncomingConnection(self):
656 6526ddcd Michael Hanselmann
    """Called for each incoming connection
657 42242313 Michael Hanselmann

658 6526ddcd Michael Hanselmann
    """
659 6526ddcd Michael Hanselmann
    (connection, client_addr) = self.socket.accept()
660 42242313 Michael Hanselmann
661 42242313 Michael Hanselmann
    self._CollectChildren(False)
662 42242313 Michael Hanselmann
663 42242313 Michael Hanselmann
    pid = os.fork()
664 42242313 Michael Hanselmann
    if pid == 0:
665 42242313 Michael Hanselmann
      # Child process
666 6526ddcd Michael Hanselmann
      logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
667 6526ddcd Michael Hanselmann
668 42242313 Michael Hanselmann
      try:
669 6526ddcd Michael Hanselmann
        try:
670 6526ddcd Michael Hanselmann
          try:
671 6526ddcd Michael Hanselmann
            handler = None
672 6526ddcd Michael Hanselmann
            try:
673 6526ddcd Michael Hanselmann
              # Read, parse and handle request
674 6526ddcd Michael Hanselmann
              handler = _HttpConnectionHandler(self, connection, client_addr,
675 6526ddcd Michael Hanselmann
                                               self._fileio_class)
676 6526ddcd Michael Hanselmann
              handler.HandleRequest()
677 6526ddcd Michael Hanselmann
            finally:
678 6526ddcd Michael Hanselmann
              # Try to send a response
679 6526ddcd Michael Hanselmann
              if handler:
680 6526ddcd Michael Hanselmann
                handler.SendResponse()
681 6526ddcd Michael Hanselmann
                handler.Close()
682 6526ddcd Michael Hanselmann
          except SocketClosed:
683 6526ddcd Michael Hanselmann
            pass
684 6526ddcd Michael Hanselmann
        finally:
685 6526ddcd Michael Hanselmann
          logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
686 42242313 Michael Hanselmann
      except:
687 42242313 Michael Hanselmann
        logging.exception("Error while handling request from %s:%s",
688 42242313 Michael Hanselmann
                          client_addr[0], client_addr[1])
689 42242313 Michael Hanselmann
        os._exit(1)
690 42242313 Michael Hanselmann
      os._exit(0)
691 42242313 Michael Hanselmann
    else:
692 42242313 Michael Hanselmann
      self._children.append(pid)
693 42242313 Michael Hanselmann
694 42242313 Michael Hanselmann
  def HandleRequest(self, req):
695 42242313 Michael Hanselmann
    raise NotImplementedError()
696 42242313 Michael Hanselmann
697 42242313 Michael Hanselmann
698 8a0b06d2 Michael Hanselmann
class HttpClientRequest(object):
699 438a366a Michael Hanselmann
  def __init__(self, host, port, method, path, headers=None, post_data=None,
700 438a366a Michael Hanselmann
               ssl_key_path=None, ssl_cert_path=None, ssl_verify_peer=False):
701 8a0b06d2 Michael Hanselmann
    """Describes an HTTP request.
702 8a0b06d2 Michael Hanselmann

703 8a0b06d2 Michael Hanselmann
    @type host: string
704 8a0b06d2 Michael Hanselmann
    @param host: Hostname
705 8a0b06d2 Michael Hanselmann
    @type port: int
706 8a0b06d2 Michael Hanselmann
    @param port: Port
707 8a0b06d2 Michael Hanselmann
    @type method: string
708 8a0b06d2 Michael Hanselmann
    @param method: Method name
709 8a0b06d2 Michael Hanselmann
    @type path: string
710 8a0b06d2 Michael Hanselmann
    @param path: Request path
711 8a0b06d2 Michael Hanselmann
    @type headers: dict or None
712 8a0b06d2 Michael Hanselmann
    @param headers: Additional headers to send
713 8a0b06d2 Michael Hanselmann
    @type post_data: string or None
714 8a0b06d2 Michael Hanselmann
    @param post_data: Additional data to send
715 8a0b06d2 Michael Hanselmann

716 8a0b06d2 Michael Hanselmann
    """
717 8a0b06d2 Michael Hanselmann
    if post_data is not None:
718 8a0b06d2 Michael Hanselmann
      assert method.upper() in (HTTP_POST, HTTP_PUT), \
719 8a0b06d2 Michael Hanselmann
        "Only POST and GET requests support sending data"
720 8a0b06d2 Michael Hanselmann
721 8a0b06d2 Michael Hanselmann
    assert path.startswith("/"), "Path must start with slash (/)"
722 8a0b06d2 Michael Hanselmann
723 8a0b06d2 Michael Hanselmann
    self.host = host
724 8a0b06d2 Michael Hanselmann
    self.port = port
725 438a366a Michael Hanselmann
    self.ssl_key_path = ssl_key_path
726 438a366a Michael Hanselmann
    self.ssl_cert_path = ssl_cert_path
727 438a366a Michael Hanselmann
    self.ssl_verify_peer = ssl_verify_peer
728 8a0b06d2 Michael Hanselmann
    self.method = method
729 8a0b06d2 Michael Hanselmann
    self.path = path
730 8a0b06d2 Michael Hanselmann
    self.headers = headers
731 8a0b06d2 Michael Hanselmann
    self.post_data = post_data
732 8a0b06d2 Michael Hanselmann
733 8a0b06d2 Michael Hanselmann
    self.success = None
734 8a0b06d2 Michael Hanselmann
    self.error = None
735 8a0b06d2 Michael Hanselmann
736 8a0b06d2 Michael Hanselmann
    self.resp_status_line = None
737 8a0b06d2 Michael Hanselmann
    self.resp_version = None
738 8a0b06d2 Michael Hanselmann
    self.resp_status = None
739 8a0b06d2 Michael Hanselmann
    self.resp_reason = None
740 8a0b06d2 Michael Hanselmann
    self.resp_headers = None
741 8a0b06d2 Michael Hanselmann
    self.resp_body = None
742 8a0b06d2 Michael Hanselmann
743 8a0b06d2 Michael Hanselmann
744 438a366a Michael Hanselmann
class HttpClientRequestExecutor(_HttpSocketBase):
745 8a0b06d2 Michael Hanselmann
  # Default headers
746 8a0b06d2 Michael Hanselmann
  DEFAULT_HEADERS = {
747 8a0b06d2 Michael Hanselmann
    HTTP_USER_AGENT: HTTP_GANETI_VERSION,
748 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, don't send "Connection: close"
749 8a0b06d2 Michael Hanselmann
    HTTP_CONNECTION: "close",
750 8a0b06d2 Michael Hanselmann
    }
751 8a0b06d2 Michael Hanselmann
752 8a0b06d2 Michael Hanselmann
  # Length limits
753 8a0b06d2 Michael Hanselmann
  STATUS_LINE_LENGTH_MAX = 512
754 8a0b06d2 Michael Hanselmann
  HEADER_LENGTH_MAX = 4 * 1024
755 8a0b06d2 Michael Hanselmann
756 438a366a Michael Hanselmann
  # Timeouts in seconds for socket layer
757 8a0b06d2 Michael Hanselmann
  # TODO: Make read timeout configurable per OpCode
758 8a0b06d2 Michael Hanselmann
  CONNECT_TIMEOUT = 5.0
759 8a0b06d2 Michael Hanselmann
  WRITE_TIMEOUT = 10
760 8a0b06d2 Michael Hanselmann
  READ_TIMEOUT = None
761 8a0b06d2 Michael Hanselmann
  CLOSE_TIMEOUT = 1
762 8a0b06d2 Michael Hanselmann
763 8a0b06d2 Michael Hanselmann
  # Parser state machine
764 8a0b06d2 Michael Hanselmann
  PS_STATUS_LINE = "status-line"
765 8a0b06d2 Michael Hanselmann
  PS_HEADERS = "headers"
766 8a0b06d2 Michael Hanselmann
  PS_BODY = "body"
767 8a0b06d2 Michael Hanselmann
  PS_COMPLETE = "complete"
768 8a0b06d2 Michael Hanselmann
769 438a366a Michael Hanselmann
  # Socket operations
770 438a366a Michael Hanselmann
  (OP_SEND,
771 438a366a Michael Hanselmann
   OP_RECV,
772 438a366a Michael Hanselmann
   OP_CLOSE_CHECK,
773 438a366a Michael Hanselmann
   OP_SHUTDOWN) = range(4)
774 438a366a Michael Hanselmann
775 8a0b06d2 Michael Hanselmann
  def __init__(self, req):
776 8a0b06d2 Michael Hanselmann
    """Initializes the HttpClientRequestExecutor class.
777 8a0b06d2 Michael Hanselmann

778 8a0b06d2 Michael Hanselmann
    @type req: HttpClientRequest
779 8a0b06d2 Michael Hanselmann
    @param req: Request object
780 8a0b06d2 Michael Hanselmann

781 8a0b06d2 Michael Hanselmann
    """
782 438a366a Michael Hanselmann
    _HttpSocketBase.__init__(self)
783 438a366a Michael Hanselmann
784 8a0b06d2 Michael Hanselmann
    self.request = req
785 8a0b06d2 Michael Hanselmann
786 8a0b06d2 Michael Hanselmann
    self.parser_status = self.PS_STATUS_LINE
787 8a0b06d2 Michael Hanselmann
    self.header_buffer = StringIO()
788 8a0b06d2 Michael Hanselmann
    self.body_buffer = StringIO()
789 8a0b06d2 Michael Hanselmann
    self.content_length = None
790 8a0b06d2 Michael Hanselmann
    self.server_will_close = None
791 8a0b06d2 Michael Hanselmann
792 8a0b06d2 Michael Hanselmann
    self.poller = select.poll()
793 8a0b06d2 Michael Hanselmann
794 8a0b06d2 Michael Hanselmann
    try:
795 8a0b06d2 Michael Hanselmann
      # TODO: Implement connection caching/keep-alive
796 438a366a Michael Hanselmann
      self.sock = self._CreateSocket(req.ssl_key_path,
797 438a366a Michael Hanselmann
                                     req.ssl_cert_path,
798 438a366a Michael Hanselmann
                                     req.ssl_verify_peer)
799 8a0b06d2 Michael Hanselmann
800 8a0b06d2 Michael Hanselmann
      # Disable Python's timeout
801 8a0b06d2 Michael Hanselmann
      self.sock.settimeout(None)
802 8a0b06d2 Michael Hanselmann
803 8a0b06d2 Michael Hanselmann
      # Operate in non-blocking mode
804 8a0b06d2 Michael Hanselmann
      self.sock.setblocking(0)
805 8a0b06d2 Michael Hanselmann
806 8a0b06d2 Michael Hanselmann
      force_close = True
807 8a0b06d2 Michael Hanselmann
      self._Connect()
808 8a0b06d2 Michael Hanselmann
      try:
809 8a0b06d2 Michael Hanselmann
        self._SendRequest()
810 8a0b06d2 Michael Hanselmann
        self._ReadResponse()
811 8a0b06d2 Michael Hanselmann
812 8a0b06d2 Michael Hanselmann
        # Only wait for server to close if we didn't have any exception.
813 8a0b06d2 Michael Hanselmann
        force_close = False
814 8a0b06d2 Michael Hanselmann
      finally:
815 8a0b06d2 Michael Hanselmann
        self._CloseConnection(force_close)
816 8a0b06d2 Michael Hanselmann
817 8a0b06d2 Michael Hanselmann
      self.sock.close()
818 8a0b06d2 Michael Hanselmann
      self.sock = None
819 8a0b06d2 Michael Hanselmann
820 8a0b06d2 Michael Hanselmann
      req.resp_body = self.body_buffer.getvalue()
821 8a0b06d2 Michael Hanselmann
822 8a0b06d2 Michael Hanselmann
      req.success = True
823 8a0b06d2 Michael Hanselmann
      req.error = None
824 8a0b06d2 Michael Hanselmann
825 438a366a Michael Hanselmann
    except _HttpClientError, err:
826 8a0b06d2 Michael Hanselmann
      req.success = False
827 8a0b06d2 Michael Hanselmann
      req.error = str(err)
828 8a0b06d2 Michael Hanselmann
829 8a0b06d2 Michael Hanselmann
  def _BuildRequest(self):
830 8a0b06d2 Michael Hanselmann
    """Build HTTP request.
831 8a0b06d2 Michael Hanselmann

832 8a0b06d2 Michael Hanselmann
    @rtype: string
833 8a0b06d2 Michael Hanselmann
    @return: Complete request
834 8a0b06d2 Michael Hanselmann

835 8a0b06d2 Michael Hanselmann
    """
836 8a0b06d2 Michael Hanselmann
    # Headers
837 8a0b06d2 Michael Hanselmann
    send_headers = self.DEFAULT_HEADERS.copy()
838 8a0b06d2 Michael Hanselmann
839 8a0b06d2 Michael Hanselmann
    if self.request.headers:
840 33bbdbec Michael Hanselmann
      send_headers.update(self.request.headers)
841 8a0b06d2 Michael Hanselmann
842 8a0b06d2 Michael Hanselmann
    send_headers[HTTP_HOST] = "%s:%s" % (self.request.host, self.request.port)
843 8a0b06d2 Michael Hanselmann
844 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
845 8a0b06d2 Michael Hanselmann
      send_headers[HTTP_CONTENT_LENGTH] = len(self.request.post_data)
846 8a0b06d2 Michael Hanselmann
847 8a0b06d2 Michael Hanselmann
    buf = StringIO()
848 8a0b06d2 Michael Hanselmann
849 8a0b06d2 Michael Hanselmann
    # Add request line. We only support HTTP/1.0 (no chunked transfers and no
850 8a0b06d2 Michael Hanselmann
    # keep-alive).
851 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, change to HTTP/1.1
852 8a0b06d2 Michael Hanselmann
    buf.write("%s %s %s\r\n" % (self.request.method.upper(),
853 8a0b06d2 Michael Hanselmann
                                self.request.path, HTTP_1_0))
854 8a0b06d2 Michael Hanselmann
855 8a0b06d2 Michael Hanselmann
    # Add headers
856 8a0b06d2 Michael Hanselmann
    for name, value in send_headers.iteritems():
857 8a0b06d2 Michael Hanselmann
      buf.write("%s: %s\r\n" % (name, value))
858 8a0b06d2 Michael Hanselmann
859 8a0b06d2 Michael Hanselmann
    buf.write("\r\n")
860 8a0b06d2 Michael Hanselmann
861 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
862 8a0b06d2 Michael Hanselmann
      buf.write(self.request.post_data)
863 8a0b06d2 Michael Hanselmann
864 8a0b06d2 Michael Hanselmann
    return buf.getvalue()
865 8a0b06d2 Michael Hanselmann
866 8a0b06d2 Michael Hanselmann
  def _ParseStatusLine(self):
867 8a0b06d2 Michael Hanselmann
    """Parses the status line sent by the server.
868 8a0b06d2 Michael Hanselmann

869 8a0b06d2 Michael Hanselmann
    """
870 8a0b06d2 Michael Hanselmann
    line = self.request.resp_status_line
871 8a0b06d2 Michael Hanselmann
872 8a0b06d2 Michael Hanselmann
    if not line:
873 438a366a Michael Hanselmann
      raise _HttpClientError("Empty status line")
874 8a0b06d2 Michael Hanselmann
875 8a0b06d2 Michael Hanselmann
    try:
876 8a0b06d2 Michael Hanselmann
      [version, status, reason] = line.split(None, 2)
877 8a0b06d2 Michael Hanselmann
    except ValueError:
878 8a0b06d2 Michael Hanselmann
      try:
879 8a0b06d2 Michael Hanselmann
        [version, status] = line.split(None, 1)
880 8a0b06d2 Michael Hanselmann
        reason = ""
881 8a0b06d2 Michael Hanselmann
      except ValueError:
882 8a0b06d2 Michael Hanselmann
        version = HTTP_9_0
883 8a0b06d2 Michael Hanselmann
884 8a0b06d2 Michael Hanselmann
    if version:
885 8a0b06d2 Michael Hanselmann
      version = version.upper()
886 8a0b06d2 Michael Hanselmann
887 8a0b06d2 Michael Hanselmann
    if version not in (HTTP_1_0, HTTP_1_1):
888 8a0b06d2 Michael Hanselmann
      # We do not support HTTP/0.9, despite the specification requiring it
889 8a0b06d2 Michael Hanselmann
      # (RFC2616, section 19.6)
890 438a366a Michael Hanselmann
      raise _HttpClientError("Only HTTP/1.0 and HTTP/1.1 are supported (%r)" %
891 438a366a Michael Hanselmann
                             line)
892 8a0b06d2 Michael Hanselmann
893 8a0b06d2 Michael Hanselmann
    # The status code is a three-digit number
894 8a0b06d2 Michael Hanselmann
    try:
895 8a0b06d2 Michael Hanselmann
      status = int(status)
896 8a0b06d2 Michael Hanselmann
      if status < 100 or status > 999:
897 8a0b06d2 Michael Hanselmann
        status = -1
898 8a0b06d2 Michael Hanselmann
    except ValueError:
899 8a0b06d2 Michael Hanselmann
      status = -1
900 8a0b06d2 Michael Hanselmann
901 8a0b06d2 Michael Hanselmann
    if status == -1:
902 438a366a Michael Hanselmann
      raise _HttpClientError("Invalid status code (%r)" % line)
903 8a0b06d2 Michael Hanselmann
904 8a0b06d2 Michael Hanselmann
    self.request.resp_version = version
905 8a0b06d2 Michael Hanselmann
    self.request.resp_status = status
906 8a0b06d2 Michael Hanselmann
    self.request.resp_reason = reason
907 8a0b06d2 Michael Hanselmann
908 8a0b06d2 Michael Hanselmann
  def _WillServerCloseConnection(self):
909 8a0b06d2 Michael Hanselmann
    """Evaluate whether server will close the connection.
910 8a0b06d2 Michael Hanselmann

911 8a0b06d2 Michael Hanselmann
    @rtype: bool
912 8a0b06d2 Michael Hanselmann
    @return: Whether server will close the connection
913 8a0b06d2 Michael Hanselmann

914 8a0b06d2 Michael Hanselmann
    """
915 8a0b06d2 Michael Hanselmann
    hdr_connection = self.request.resp_headers.get(HTTP_CONNECTION, None)
916 8a0b06d2 Michael Hanselmann
    if hdr_connection:
917 8a0b06d2 Michael Hanselmann
      hdr_connection = hdr_connection.lower()
918 8a0b06d2 Michael Hanselmann
919 8a0b06d2 Michael Hanselmann
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
920 8a0b06d2 Michael Hanselmann
    if self.request.resp_version == HTTP_1_1:
921 8a0b06d2 Michael Hanselmann
      return (hdr_connection and "close" in hdr_connection)
922 8a0b06d2 Michael Hanselmann
923 8a0b06d2 Michael Hanselmann
    # Some HTTP/1.0 implementations have support for persistent connections,
924 8a0b06d2 Michael Hanselmann
    # using rules different than HTTP/1.1.
925 8a0b06d2 Michael Hanselmann
926 8a0b06d2 Michael Hanselmann
    # For older HTTP, Keep-Alive indicates persistent connection.
927 8a0b06d2 Michael Hanselmann
    if self.request.resp_headers.get(HTTP_KEEP_ALIVE):
928 8a0b06d2 Michael Hanselmann
      return False
929 8a0b06d2 Michael Hanselmann
930 8a0b06d2 Michael Hanselmann
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
931 8a0b06d2 Michael Hanselmann
    # supposed to be sent by the client.
932 8a0b06d2 Michael Hanselmann
    if hdr_connection and "keep-alive" in hdr_connection:
933 8a0b06d2 Michael Hanselmann
      return False
934 8a0b06d2 Michael Hanselmann
935 8a0b06d2 Michael Hanselmann
    return True
936 8a0b06d2 Michael Hanselmann
937 8a0b06d2 Michael Hanselmann
  def _ParseHeaders(self):
938 8a0b06d2 Michael Hanselmann
    """Parses the headers sent by the server.
939 8a0b06d2 Michael Hanselmann

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

942 8a0b06d2 Michael Hanselmann
    """
943 8a0b06d2 Michael Hanselmann
    req = self.request
944 8a0b06d2 Michael Hanselmann
945 8a0b06d2 Michael Hanselmann
    # Parse headers
946 8a0b06d2 Michael Hanselmann
    self.header_buffer.seek(0, 0)
947 8a0b06d2 Michael Hanselmann
    req.resp_headers = mimetools.Message(self.header_buffer, 0)
948 8a0b06d2 Michael Hanselmann
949 8a0b06d2 Michael Hanselmann
    self.server_will_close = self._WillServerCloseConnection()
950 8a0b06d2 Michael Hanselmann
951 8a0b06d2 Michael Hanselmann
    # Do we have a Content-Length header?
952 8a0b06d2 Michael Hanselmann
    hdr_content_length = req.resp_headers.get(HTTP_CONTENT_LENGTH, None)
953 8a0b06d2 Michael Hanselmann
    if hdr_content_length:
954 8a0b06d2 Michael Hanselmann
      try:
955 8a0b06d2 Michael Hanselmann
        self.content_length = int(hdr_content_length)
956 8a0b06d2 Michael Hanselmann
      except ValueError:
957 8a0b06d2 Michael Hanselmann
        pass
958 8a0b06d2 Michael Hanselmann
      if self.content_length is not None and self.content_length < 0:
959 8a0b06d2 Michael Hanselmann
        self.content_length = None
960 8a0b06d2 Michael Hanselmann
961 8a0b06d2 Michael Hanselmann
    # does the body have a fixed length? (of zero)
962 8a0b06d2 Michael Hanselmann
    if (req.resp_status in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED) or
963 8a0b06d2 Michael Hanselmann
        100 <= req.resp_status < 200 or req.method == HTTP_HEAD):
964 8a0b06d2 Michael Hanselmann
      self.content_length = 0
965 8a0b06d2 Michael Hanselmann
966 8a0b06d2 Michael Hanselmann
    # if the connection remains open and a content-length was not provided,
967 8a0b06d2 Michael Hanselmann
    # then assume that the connection WILL close.
968 8a0b06d2 Michael Hanselmann
    if self.content_length is None:
969 8a0b06d2 Michael Hanselmann
      self.server_will_close = True
970 8a0b06d2 Michael Hanselmann
971 8a0b06d2 Michael Hanselmann
  def _CheckStatusLineLength(self, length):
972 8a0b06d2 Michael Hanselmann
    if length > self.STATUS_LINE_LENGTH_MAX:
973 438a366a Michael Hanselmann
      raise _HttpClientError("Status line longer than %d chars" %
974 438a366a Michael Hanselmann
                             self.STATUS_LINE_LENGTH_MAX)
975 8a0b06d2 Michael Hanselmann
976 8a0b06d2 Michael Hanselmann
  def _CheckHeaderLength(self, length):
977 8a0b06d2 Michael Hanselmann
    if length > self.HEADER_LENGTH_MAX:
978 438a366a Michael Hanselmann
      raise _HttpClientError("Headers longer than %d chars" %
979 438a366a Michael Hanselmann
                             self.HEADER_LENGTH_MAX)
980 8a0b06d2 Michael Hanselmann
981 8a0b06d2 Michael Hanselmann
  def _ParseBuffer(self, buf, eof):
982 8a0b06d2 Michael Hanselmann
    """Main function for HTTP response state machine.
983 8a0b06d2 Michael Hanselmann

984 8a0b06d2 Michael Hanselmann
    @type buf: string
985 8a0b06d2 Michael Hanselmann
    @param buf: Receive buffer
986 8a0b06d2 Michael Hanselmann
    @type eof: bool
987 8a0b06d2 Michael Hanselmann
    @param eof: Whether we've reached EOF on the socket
988 8a0b06d2 Michael Hanselmann
    @rtype: string
989 8a0b06d2 Michael Hanselmann
    @return: Updated receive buffer
990 8a0b06d2 Michael Hanselmann

991 8a0b06d2 Michael Hanselmann
    """
992 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_STATUS_LINE:
993 8a0b06d2 Michael Hanselmann
      # Expect status line
994 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n")
995 8a0b06d2 Michael Hanselmann
      if idx >= 0:
996 8a0b06d2 Michael Hanselmann
        self.request.resp_status_line = buf[:idx]
997 8a0b06d2 Michael Hanselmann
998 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(self.request.resp_status_line))
999 8a0b06d2 Michael Hanselmann
1000 8a0b06d2 Michael Hanselmann
        # Remove status line, including CRLF
1001 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 2:]
1002 8a0b06d2 Michael Hanselmann
1003 8a0b06d2 Michael Hanselmann
        self._ParseStatusLine()
1004 8a0b06d2 Michael Hanselmann
1005 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_HEADERS
1006 8a0b06d2 Michael Hanselmann
      else:
1007 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1008 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1009 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(buf))
1010 8a0b06d2 Michael Hanselmann
1011 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_HEADERS:
1012 8a0b06d2 Michael Hanselmann
      # Wait for header end
1013 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n\r\n")
1014 8a0b06d2 Michael Hanselmann
      if idx >= 0:
1015 8a0b06d2 Michael Hanselmann
        self.header_buffer.write(buf[:idx + 2])
1016 8a0b06d2 Michael Hanselmann
1017 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(self.header_buffer.tell())
1018 8a0b06d2 Michael Hanselmann
1019 8a0b06d2 Michael Hanselmann
        # Remove headers, including CRLF
1020 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 4:]
1021 8a0b06d2 Michael Hanselmann
1022 8a0b06d2 Michael Hanselmann
        self._ParseHeaders()
1023 8a0b06d2 Michael Hanselmann
1024 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_BODY
1025 8a0b06d2 Michael Hanselmann
      else:
1026 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1027 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1028 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(len(buf))
1029 8a0b06d2 Michael Hanselmann
1030 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_BODY:
1031 8a0b06d2 Michael Hanselmann
      self.body_buffer.write(buf)
1032 8a0b06d2 Michael Hanselmann
      buf = ""
1033 8a0b06d2 Michael Hanselmann
1034 8a0b06d2 Michael Hanselmann
      # Check whether we've read everything
1035 8a0b06d2 Michael Hanselmann
      if (eof or
1036 8a0b06d2 Michael Hanselmann
          (self.content_length is not None and
1037 8a0b06d2 Michael Hanselmann
           self.body_buffer.tell() >= self.content_length)):
1038 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_COMPLETE
1039 8a0b06d2 Michael Hanselmann
1040 8a0b06d2 Michael Hanselmann
    return buf
1041 8a0b06d2 Michael Hanselmann
1042 8a0b06d2 Michael Hanselmann
  def _WaitForCondition(self, event, timeout):
1043 8a0b06d2 Michael Hanselmann
    """Waits for a condition to occur on the socket.
1044 8a0b06d2 Michael Hanselmann

1045 8a0b06d2 Michael Hanselmann
    @type event: int
1046 8a0b06d2 Michael Hanselmann
    @param event: ORed condition (see select module)
1047 8a0b06d2 Michael Hanselmann
    @type timeout: float or None
1048 8a0b06d2 Michael Hanselmann
    @param timeout: Timeout in seconds
1049 8a0b06d2 Michael Hanselmann
    @rtype: int or None
1050 8a0b06d2 Michael Hanselmann
    @return: None for timeout, otherwise occured conditions
1051 8a0b06d2 Michael Hanselmann

1052 8a0b06d2 Michael Hanselmann
    """
1053 8a0b06d2 Michael Hanselmann
    check = (event | select.POLLPRI |
1054 8a0b06d2 Michael Hanselmann
             select.POLLNVAL | select.POLLHUP | select.POLLERR)
1055 8a0b06d2 Michael Hanselmann
1056 8a0b06d2 Michael Hanselmann
    if timeout is not None:
1057 8a0b06d2 Michael Hanselmann
      # Poller object expects milliseconds
1058 8a0b06d2 Michael Hanselmann
      timeout *= 1000
1059 8a0b06d2 Michael Hanselmann
1060 8a0b06d2 Michael Hanselmann
    self.poller.register(self.sock, event)
1061 8a0b06d2 Michael Hanselmann
    try:
1062 8a0b06d2 Michael Hanselmann
      while True:
1063 8a0b06d2 Michael Hanselmann
        # TODO: If the main thread receives a signal and we have no timeout, we
1064 8a0b06d2 Michael Hanselmann
        # could wait forever. This should check a global "quit" flag or
1065 8a0b06d2 Michael Hanselmann
        # something every so often.
1066 8a0b06d2 Michael Hanselmann
        io_events = self.poller.poll(timeout)
1067 8a0b06d2 Michael Hanselmann
        if io_events:
1068 8a0b06d2 Michael Hanselmann
          for (evfd, evcond) in io_events:
1069 8a0b06d2 Michael Hanselmann
            if evcond & check:
1070 8a0b06d2 Michael Hanselmann
              return evcond
1071 8a0b06d2 Michael Hanselmann
        else:
1072 8a0b06d2 Michael Hanselmann
          # Timeout
1073 8a0b06d2 Michael Hanselmann
          return None
1074 8a0b06d2 Michael Hanselmann
    finally:
1075 8a0b06d2 Michael Hanselmann
      self.poller.unregister(self.sock)
1076 8a0b06d2 Michael Hanselmann
1077 438a366a Michael Hanselmann
  def _SocketOperation(self, op, arg1, error_msg, timeout_msg):
1078 438a366a Michael Hanselmann
    """Wrapper around socket functions.
1079 438a366a Michael Hanselmann

1080 438a366a Michael Hanselmann
    This function abstracts error handling for socket operations, especially
1081 438a366a Michael Hanselmann
    for the complicated interaction with OpenSSL.
1082 438a366a Michael Hanselmann

1083 438a366a Michael Hanselmann
    """
1084 438a366a Michael Hanselmann
    if op == self.OP_SEND:
1085 438a366a Michael Hanselmann
      event_poll = select.POLLOUT
1086 438a366a Michael Hanselmann
      event_check = select.POLLOUT
1087 438a366a Michael Hanselmann
      timeout = self.WRITE_TIMEOUT
1088 438a366a Michael Hanselmann
1089 438a366a Michael Hanselmann
    elif op in (self.OP_RECV, self.OP_CLOSE_CHECK):
1090 438a366a Michael Hanselmann
      event_poll = select.POLLIN
1091 438a366a Michael Hanselmann
      event_check = select.POLLIN | select.POLLPRI
1092 438a366a Michael Hanselmann
      if op == self.OP_CLOSE_CHECK:
1093 438a366a Michael Hanselmann
        timeout = self.CLOSE_TIMEOUT
1094 438a366a Michael Hanselmann
      else:
1095 438a366a Michael Hanselmann
        timeout = self.READ_TIMEOUT
1096 438a366a Michael Hanselmann
1097 438a366a Michael Hanselmann
    elif op == self.OP_SHUTDOWN:
1098 438a366a Michael Hanselmann
      event_poll = None
1099 438a366a Michael Hanselmann
      event_check = None
1100 438a366a Michael Hanselmann
1101 438a366a Michael Hanselmann
      # The timeout is only used when OpenSSL requests polling for a condition.
1102 438a366a Michael Hanselmann
      # It is not advisable to have no timeout for shutdown.
1103 438a366a Michael Hanselmann
      timeout = self.WRITE_TIMEOUT
1104 438a366a Michael Hanselmann
1105 438a366a Michael Hanselmann
    else:
1106 438a366a Michael Hanselmann
      raise AssertionError("Invalid socket operation")
1107 438a366a Michael Hanselmann
1108 438a366a Michael Hanselmann
    # No override by default
1109 438a366a Michael Hanselmann
    event_override = 0
1110 438a366a Michael Hanselmann
1111 438a366a Michael Hanselmann
    while True:
1112 438a366a Michael Hanselmann
      # Poll only for certain operations and when asked for by an override
1113 438a366a Michael Hanselmann
      if (event_override or
1114 438a366a Michael Hanselmann
          op in (self.OP_SEND, self.OP_RECV, self.OP_CLOSE_CHECK)):
1115 438a366a Michael Hanselmann
        if event_override:
1116 438a366a Michael Hanselmann
          wait_for_event = event_override
1117 438a366a Michael Hanselmann
        else:
1118 438a366a Michael Hanselmann
          wait_for_event = event_poll
1119 438a366a Michael Hanselmann
1120 438a366a Michael Hanselmann
        event = self._WaitForCondition(wait_for_event, timeout)
1121 438a366a Michael Hanselmann
        if event is None:
1122 438a366a Michael Hanselmann
          raise _HttpClientTimeout(timeout_msg)
1123 438a366a Michael Hanselmann
1124 438a366a Michael Hanselmann
        if (op == self.OP_RECV and
1125 438a366a Michael Hanselmann
            event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
1126 438a366a Michael Hanselmann
          return ""
1127 438a366a Michael Hanselmann
1128 438a366a Michael Hanselmann
        if not event & wait_for_event:
1129 438a366a Michael Hanselmann
          continue
1130 438a366a Michael Hanselmann
1131 438a366a Michael Hanselmann
      # Reset override
1132 438a366a Michael Hanselmann
      event_override = 0
1133 438a366a Michael Hanselmann
1134 438a366a Michael Hanselmann
      try:
1135 438a366a Michael Hanselmann
        try:
1136 438a366a Michael Hanselmann
          if op == self.OP_SEND:
1137 438a366a Michael Hanselmann
            return self.sock.send(arg1)
1138 438a366a Michael Hanselmann
1139 438a366a Michael Hanselmann
          elif op in (self.OP_RECV, self.OP_CLOSE_CHECK):
1140 438a366a Michael Hanselmann
            return self.sock.recv(arg1)
1141 438a366a Michael Hanselmann
1142 438a366a Michael Hanselmann
          elif op == self.OP_SHUTDOWN:
1143 438a366a Michael Hanselmann
            if self._using_ssl:
1144 438a366a Michael Hanselmann
              # PyOpenSSL's shutdown() doesn't take arguments
1145 438a366a Michael Hanselmann
              return self.sock.shutdown()
1146 438a366a Michael Hanselmann
            else:
1147 438a366a Michael Hanselmann
              return self.sock.shutdown(arg1)
1148 438a366a Michael Hanselmann
1149 438a366a Michael Hanselmann
        except OpenSSL.SSL.WantWriteError:
1150 438a366a Michael Hanselmann
          # OpenSSL wants to write, poll for POLLOUT
1151 438a366a Michael Hanselmann
          event_override = select.POLLOUT
1152 438a366a Michael Hanselmann
          continue
1153 438a366a Michael Hanselmann
1154 438a366a Michael Hanselmann
        except OpenSSL.SSL.WantReadError:
1155 438a366a Michael Hanselmann
          # OpenSSL wants to read, poll for POLLIN
1156 438a366a Michael Hanselmann
          event_override = select.POLLIN | select.POLLPRI
1157 438a366a Michael Hanselmann
          continue
1158 438a366a Michael Hanselmann
1159 438a366a Michael Hanselmann
        except OpenSSL.SSL.WantX509LookupError:
1160 438a366a Michael Hanselmann
          continue
1161 438a366a Michael Hanselmann
1162 438a366a Michael Hanselmann
        except OpenSSL.SSL.SysCallError, err:
1163 438a366a Michael Hanselmann
          if op == self.OP_SEND:
1164 438a366a Michael Hanselmann
            # arg1 is the data when writing
1165 438a366a Michael Hanselmann
            if err.args and err.args[0] == -1 and arg1 == "":
1166 438a366a Michael Hanselmann
              # errors when writing empty strings are expected
1167 438a366a Michael Hanselmann
              # and can be ignored
1168 438a366a Michael Hanselmann
              return 0
1169 438a366a Michael Hanselmann
1170 438a366a Michael Hanselmann
          elif op == self.OP_RECV:
1171 438a366a Michael Hanselmann
            if err.args == (-1, _SSL_UNEXPECTED_EOF):
1172 438a366a Michael Hanselmann
              return ""
1173 438a366a Michael Hanselmann
1174 438a366a Michael Hanselmann
          raise socket.error(err.args)
1175 438a366a Michael Hanselmann
1176 438a366a Michael Hanselmann
        except OpenSSL.SSL.Error, err:
1177 438a366a Michael Hanselmann
          raise socket.error(err.args)
1178 438a366a Michael Hanselmann
1179 438a366a Michael Hanselmann
      except socket.error, err:
1180 438a366a Michael Hanselmann
        if err.args and err.args[0] == errno.EAGAIN:
1181 438a366a Michael Hanselmann
          # Ignore EAGAIN
1182 438a366a Michael Hanselmann
          continue
1183 438a366a Michael Hanselmann
1184 438a366a Michael Hanselmann
        raise _HttpClientError("%s: %s" % (error_msg, str(err)))
1185 438a366a Michael Hanselmann
1186 8a0b06d2 Michael Hanselmann
  def _Connect(self):
1187 8a0b06d2 Michael Hanselmann
    """Non-blocking connect to host with timeout.
1188 8a0b06d2 Michael Hanselmann

1189 8a0b06d2 Michael Hanselmann
    """
1190 8a0b06d2 Michael Hanselmann
    connected = False
1191 8a0b06d2 Michael Hanselmann
    while True:
1192 438a366a Michael Hanselmann
      try:
1193 438a366a Michael Hanselmann
        connect_error = self.sock.connect_ex((self.request.host,
1194 438a366a Michael Hanselmann
                                              self.request.port))
1195 438a366a Michael Hanselmann
      except socket.gaierror, err:
1196 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed: %s" % str(err))
1197 438a366a Michael Hanselmann
1198 8a0b06d2 Michael Hanselmann
      if connect_error == errno.EINTR:
1199 8a0b06d2 Michael Hanselmann
        # Mask signals
1200 8a0b06d2 Michael Hanselmann
        pass
1201 8a0b06d2 Michael Hanselmann
1202 8a0b06d2 Michael Hanselmann
      elif connect_error == 0:
1203 8a0b06d2 Michael Hanselmann
        # Connection established
1204 8a0b06d2 Michael Hanselmann
        connected = True
1205 8a0b06d2 Michael Hanselmann
        break
1206 8a0b06d2 Michael Hanselmann
1207 8a0b06d2 Michael Hanselmann
      elif connect_error == errno.EINPROGRESS:
1208 8a0b06d2 Michael Hanselmann
        # Connection started
1209 8a0b06d2 Michael Hanselmann
        break
1210 8a0b06d2 Michael Hanselmann
1211 438a366a Michael Hanselmann
      raise _HttpClientError("Connection failed (%s: %s)" %
1212 438a366a Michael Hanselmann
                             (connect_error, os.strerror(connect_error)))
1213 8a0b06d2 Michael Hanselmann
1214 8a0b06d2 Michael Hanselmann
    if not connected:
1215 8a0b06d2 Michael Hanselmann
      # Wait for connection
1216 8a0b06d2 Michael Hanselmann
      event = self._WaitForCondition(select.POLLOUT, self.CONNECT_TIMEOUT)
1217 8a0b06d2 Michael Hanselmann
      if event is None:
1218 438a366a Michael Hanselmann
        raise _HttpClientError("Timeout while connecting to server")
1219 8a0b06d2 Michael Hanselmann
1220 8a0b06d2 Michael Hanselmann
      # Get error code
1221 8a0b06d2 Michael Hanselmann
      connect_error = self.sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
1222 8a0b06d2 Michael Hanselmann
      if connect_error != 0:
1223 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed (%s: %s)" %
1224 438a366a Michael Hanselmann
                               (connect_error, os.strerror(connect_error)))
1225 8a0b06d2 Michael Hanselmann
1226 8a0b06d2 Michael Hanselmann
    # Enable TCP keep-alive
1227 8a0b06d2 Michael Hanselmann
    self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
1228 8a0b06d2 Michael Hanselmann
1229 8a0b06d2 Michael Hanselmann
    # If needed, Linux specific options are available to change the TCP
1230 8a0b06d2 Michael Hanselmann
    # keep-alive settings, see "man 7 tcp" for TCP_KEEPCNT, TCP_KEEPIDLE and
1231 8a0b06d2 Michael Hanselmann
    # TCP_KEEPINTVL.
1232 8a0b06d2 Michael Hanselmann
1233 8a0b06d2 Michael Hanselmann
  def _SendRequest(self):
1234 8a0b06d2 Michael Hanselmann
    """Sends request to server.
1235 8a0b06d2 Michael Hanselmann

1236 8a0b06d2 Michael Hanselmann
    """
1237 8a0b06d2 Michael Hanselmann
    buf = self._BuildRequest()
1238 8a0b06d2 Michael Hanselmann
1239 8a0b06d2 Michael Hanselmann
    while buf:
1240 438a366a Michael Hanselmann
      # Send only 4 KB at a time
1241 438a366a Michael Hanselmann
      data = buf[:4096]
1242 8a0b06d2 Michael Hanselmann
1243 438a366a Michael Hanselmann
      sent = self._SocketOperation(self.OP_SEND, data,
1244 438a366a Michael Hanselmann
                                   "Error while sending request",
1245 438a366a Michael Hanselmann
                                   "Timeout while sending request")
1246 8a0b06d2 Michael Hanselmann
1247 8a0b06d2 Michael Hanselmann
      # Remove sent bytes
1248 8a0b06d2 Michael Hanselmann
      buf = buf[sent:]
1249 8a0b06d2 Michael Hanselmann
1250 8a0b06d2 Michael Hanselmann
    assert not buf, "Request wasn't sent completely"
1251 8a0b06d2 Michael Hanselmann
1252 8a0b06d2 Michael Hanselmann
  def _ReadResponse(self):
1253 8a0b06d2 Michael Hanselmann
    """Read response from server.
1254 8a0b06d2 Michael Hanselmann

1255 8a0b06d2 Michael Hanselmann
    Calls the parser function after reading a chunk of data.
1256 8a0b06d2 Michael Hanselmann

1257 8a0b06d2 Michael Hanselmann
    """
1258 8a0b06d2 Michael Hanselmann
    buf = ""
1259 8a0b06d2 Michael Hanselmann
    eof = False
1260 8a0b06d2 Michael Hanselmann
    while self.parser_status != self.PS_COMPLETE:
1261 438a366a Michael Hanselmann
      data = self._SocketOperation(self.OP_RECV, 4096,
1262 438a366a Michael Hanselmann
                                   "Error while reading response",
1263 438a366a Michael Hanselmann
                                   "Timeout while reading response")
1264 8a0b06d2 Michael Hanselmann
1265 438a366a Michael Hanselmann
      if data:
1266 438a366a Michael Hanselmann
        buf += data
1267 438a366a Michael Hanselmann
      else:
1268 8a0b06d2 Michael Hanselmann
        eof = True
1269 8a0b06d2 Michael Hanselmann
1270 8a0b06d2 Michael Hanselmann
      # Do some parsing and error checking while more data arrives
1271 8a0b06d2 Michael Hanselmann
      buf = self._ParseBuffer(buf, eof)
1272 8a0b06d2 Michael Hanselmann
1273 8a0b06d2 Michael Hanselmann
      # Must be done only after the buffer has been evaluated
1274 8a0b06d2 Michael Hanselmann
      if (eof and
1275 8a0b06d2 Michael Hanselmann
          self.parser_status in (self.PS_STATUS_LINE,
1276 8a0b06d2 Michael Hanselmann
                                 self.PS_HEADERS)):
1277 438a366a Michael Hanselmann
        raise _HttpClientError("Connection closed prematurely")
1278 8a0b06d2 Michael Hanselmann
1279 8a0b06d2 Michael Hanselmann
    # Parse rest
1280 8a0b06d2 Michael Hanselmann
    buf = self._ParseBuffer(buf, True)
1281 8a0b06d2 Michael Hanselmann
1282 8a0b06d2 Michael Hanselmann
    assert self.parser_status == self.PS_COMPLETE
1283 8a0b06d2 Michael Hanselmann
    assert not buf, "Parser didn't read full response"
1284 8a0b06d2 Michael Hanselmann
1285 8a0b06d2 Michael Hanselmann
  def _CloseConnection(self, force):
1286 8a0b06d2 Michael Hanselmann
    """Closes the connection.
1287 8a0b06d2 Michael Hanselmann

1288 8a0b06d2 Michael Hanselmann
    """
1289 8a0b06d2 Michael Hanselmann
    if self.server_will_close and not force:
1290 8a0b06d2 Michael Hanselmann
      # Wait for server to close
1291 438a366a Michael Hanselmann
      try:
1292 438a366a Michael Hanselmann
        # Check whether it's actually closed
1293 438a366a Michael Hanselmann
        if not self._SocketOperation(self.OP_CLOSE_CHECK, 1,
1294 438a366a Michael Hanselmann
                                     "Error", "Timeout"):
1295 438a366a Michael Hanselmann
          return
1296 438a366a Michael Hanselmann
      except (socket.error, _HttpClientError):
1297 438a366a Michael Hanselmann
        # Ignore errors at this stage
1298 8a0b06d2 Michael Hanselmann
        pass
1299 8a0b06d2 Michael Hanselmann
1300 8a0b06d2 Michael Hanselmann
    # Close the connection from our side
1301 438a366a Michael Hanselmann
    self._SocketOperation(self.OP_SHUTDOWN, socket.SHUT_RDWR,
1302 438a366a Michael Hanselmann
                          "Error while shutting down connection",
1303 438a366a Michael Hanselmann
                          "Timeout while shutting down connection")
1304 8a0b06d2 Michael Hanselmann
1305 8a0b06d2 Michael Hanselmann
1306 33bbdbec Michael Hanselmann
class _HttpClientPendingRequest(object):
1307 33bbdbec Michael Hanselmann
  """Data class for pending requests.
1308 33bbdbec Michael Hanselmann

1309 33bbdbec Michael Hanselmann
  """
1310 33bbdbec Michael Hanselmann
  def __init__(self, request):
1311 33bbdbec Michael Hanselmann
    self.request = request
1312 33bbdbec Michael Hanselmann
1313 33bbdbec Michael Hanselmann
    # Thread synchronization
1314 33bbdbec Michael Hanselmann
    self.done = threading.Event()
1315 33bbdbec Michael Hanselmann
1316 33bbdbec Michael Hanselmann
1317 8a0b06d2 Michael Hanselmann
class HttpClientWorker(workerpool.BaseWorker):
1318 8a0b06d2 Michael Hanselmann
  """HTTP client worker class.
1319 8a0b06d2 Michael Hanselmann

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

1338 33bbdbec Michael Hanselmann
  """
1339 8a0b06d2 Michael Hanselmann
  def __init__(self):
1340 8a0b06d2 Michael Hanselmann
    self._wpool = HttpClientWorkerPool(self)
1341 8a0b06d2 Michael Hanselmann
1342 8a0b06d2 Michael Hanselmann
  def __del__(self):
1343 8a0b06d2 Michael Hanselmann
    self.Shutdown()
1344 8a0b06d2 Michael Hanselmann
1345 8a0b06d2 Michael Hanselmann
  def ExecRequests(self, requests):
1346 33bbdbec Michael Hanselmann
    """Execute HTTP requests.
1347 8a0b06d2 Michael Hanselmann

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

1350 33bbdbec Michael Hanselmann
    @type requests: List of HttpClientRequest instances
1351 33bbdbec Michael Hanselmann
    @param requests: The requests to execute
1352 33bbdbec Michael Hanselmann
    @rtype: List of HttpClientRequest instances
1353 33bbdbec Michael Hanselmann
    @returns: The list of requests passed in
1354 33bbdbec Michael Hanselmann

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

1384 42242313 Michael Hanselmann
  This wrapper is required to handle OpenSSL exceptions.
1385 42242313 Michael Hanselmann

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