Statistics
| Branch: | Tag: | Revision:

root / lib / http.py @ f34901f8

History | View | Annotate | Download (41.1 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 f20cbea2 Michael Hanselmann
class HttpSslParams(object):
219 f20cbea2 Michael Hanselmann
  """Data class for SSL key and certificate.
220 f20cbea2 Michael Hanselmann

221 f20cbea2 Michael Hanselmann
  """
222 f20cbea2 Michael Hanselmann
  def __init__(self, ssl_key_path, ssl_cert_path):
223 f20cbea2 Michael Hanselmann
    """Initializes this class.
224 f20cbea2 Michael Hanselmann

225 f20cbea2 Michael Hanselmann
    @type ssl_key_path: string
226 f20cbea2 Michael Hanselmann
    @param ssl_key_path: Path to file containing SSL key in PEM format
227 f20cbea2 Michael Hanselmann
    @type ssl_cert_path: string
228 f20cbea2 Michael Hanselmann
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
229 f20cbea2 Michael Hanselmann

230 f20cbea2 Michael Hanselmann
    """
231 65c6b8e0 Michael Hanselmann
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
232 65c6b8e0 Michael Hanselmann
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
233 f20cbea2 Michael Hanselmann
234 65c6b8e0 Michael Hanselmann
  def GetKey(self):
235 65c6b8e0 Michael Hanselmann
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
236 65c6b8e0 Michael Hanselmann
                                          self.ssl_key_pem)
237 65c6b8e0 Michael Hanselmann
238 65c6b8e0 Michael Hanselmann
  def GetCertificate(self):
239 65c6b8e0 Michael Hanselmann
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
240 65c6b8e0 Michael Hanselmann
                                           self.ssl_cert_pem)
241 f20cbea2 Michael Hanselmann
242 f20cbea2 Michael Hanselmann
243 b14f759e Michael Hanselmann
class _HttpSocketBase(object):
244 b14f759e Michael Hanselmann
  """Base class for HTTP server and client.
245 b14f759e Michael Hanselmann

246 b14f759e Michael Hanselmann
  """
247 b14f759e Michael Hanselmann
  def __init__(self):
248 b14f759e Michael Hanselmann
    self._using_ssl = None
249 f20cbea2 Michael Hanselmann
    self._ssl_params = None
250 65c6b8e0 Michael Hanselmann
    self._ssl_key = None
251 65c6b8e0 Michael Hanselmann
    self._ssl_cert = None
252 b14f759e Michael Hanselmann
253 f20cbea2 Michael Hanselmann
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
254 b14f759e Michael Hanselmann
    """Creates a TCP socket and initializes SSL if needed.
255 b14f759e Michael Hanselmann

256 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
257 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
258 b14f759e Michael Hanselmann
    @type ssl_verify_peer: bool
259 b14f759e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
260 b14f759e Michael Hanselmann
                            it with our certificate
261 b14f759e Michael Hanselmann

262 b14f759e Michael Hanselmann
    """
263 f20cbea2 Michael Hanselmann
    self._ssl_params = ssl_params
264 f20cbea2 Michael Hanselmann
265 b14f759e Michael Hanselmann
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
266 b14f759e Michael Hanselmann
267 b14f759e Michael Hanselmann
    # Should we enable SSL?
268 f20cbea2 Michael Hanselmann
    self._using_ssl = ssl_params is not None
269 b14f759e Michael Hanselmann
270 b14f759e Michael Hanselmann
    if not self._using_ssl:
271 b14f759e Michael Hanselmann
      return sock
272 b14f759e Michael Hanselmann
273 65c6b8e0 Michael Hanselmann
    self._ssl_key = ssl_params.GetKey()
274 65c6b8e0 Michael Hanselmann
    self._ssl_cert = ssl_params.GetCertificate()
275 65c6b8e0 Michael Hanselmann
276 b14f759e Michael Hanselmann
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
277 b14f759e Michael Hanselmann
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
278 b14f759e Michael Hanselmann
279 65c6b8e0 Michael Hanselmann
    ctx.use_privatekey(self._ssl_key)
280 65c6b8e0 Michael Hanselmann
    ctx.use_certificate(self._ssl_cert)
281 b14f759e Michael Hanselmann
    ctx.check_privatekey()
282 b14f759e Michael Hanselmann
283 b14f759e Michael Hanselmann
    if ssl_verify_peer:
284 b14f759e Michael Hanselmann
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
285 b14f759e Michael Hanselmann
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
286 b14f759e Michael Hanselmann
                     self._SSLVerifyCallback)
287 b14f759e Michael Hanselmann
288 b14f759e Michael Hanselmann
    return OpenSSL.SSL.Connection(ctx, sock)
289 b14f759e Michael Hanselmann
290 b14f759e Michael Hanselmann
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
291 b14f759e Michael Hanselmann
    """Verify the certificate provided by the peer
292 b14f759e Michael Hanselmann

293 b14f759e Michael Hanselmann
    We only compare fingerprints. The client must use the same certificate as
294 b14f759e Michael Hanselmann
    we do on our side.
295 b14f759e Michael Hanselmann

296 b14f759e Michael Hanselmann
    """
297 f20cbea2 Michael Hanselmann
    assert self._ssl_params, "SSL not initialized"
298 b14f759e Michael Hanselmann
299 65c6b8e0 Michael Hanselmann
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
300 65c6b8e0 Michael Hanselmann
            self._ssl_cert.digest("md5") == cert.digest("md5"))
301 b14f759e Michael Hanselmann
302 b14f759e Michael Hanselmann
303 42242313 Michael Hanselmann
class _HttpConnectionHandler(object):
304 42242313 Michael Hanselmann
  """Implements server side of HTTP
305 42242313 Michael Hanselmann

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

310 42242313 Michael Hanselmann
  """
311 42242313 Michael Hanselmann
  # The default request version.  This only affects responses up until
312 42242313 Michael Hanselmann
  # the point where the request line is parsed, so it mainly decides what
313 42242313 Michael Hanselmann
  # the client gets back when sending a malformed request line.
314 42242313 Michael Hanselmann
  # Most web servers default to HTTP 0.9, i.e. don't send a status line.
315 42242313 Michael Hanselmann
  default_request_version = HTTP_0_9
316 42242313 Michael Hanselmann
317 42242313 Michael Hanselmann
  # Error message settings
318 42242313 Michael Hanselmann
  error_message_format = DEFAULT_ERROR_MESSAGE
319 42242313 Michael Hanselmann
  error_content_type = DEFAULT_ERROR_CONTENT_TYPE
320 42242313 Michael Hanselmann
321 42242313 Michael Hanselmann
  responses = BaseHTTPServer.BaseHTTPRequestHandler.responses
322 42242313 Michael Hanselmann
323 42242313 Michael Hanselmann
  def __init__(self, server, conn, client_addr, fileio_class):
324 42242313 Michael Hanselmann
    """Initializes this class.
325 42242313 Michael Hanselmann

326 42242313 Michael Hanselmann
    Part of the initialization is reading the request and eventual POST/PUT
327 42242313 Michael Hanselmann
    data sent by the client.
328 42242313 Michael Hanselmann

329 42242313 Michael Hanselmann
    """
330 42242313 Michael Hanselmann
    self._server = server
331 42242313 Michael Hanselmann
332 42242313 Michael Hanselmann
    # We default rfile to buffered because otherwise it could be
333 42242313 Michael Hanselmann
    # really slow for large data (a getc() call per byte); we make
334 42242313 Michael Hanselmann
    # wfile unbuffered because (a) often after a write() we want to
335 42242313 Michael Hanselmann
    # read and we need to flush the line; (b) big writes to unbuffered
336 42242313 Michael Hanselmann
    # files are typically optimized by stdio even when big reads
337 42242313 Michael Hanselmann
    # aren't.
338 42242313 Michael Hanselmann
    self.rfile = fileio_class(conn, mode="rb", bufsize=-1)
339 42242313 Michael Hanselmann
    self.wfile = fileio_class(conn, mode="wb", bufsize=0)
340 42242313 Michael Hanselmann
341 42242313 Michael Hanselmann
    self.client_addr = client_addr
342 42242313 Michael Hanselmann
343 42242313 Michael Hanselmann
    self.request_headers = None
344 42242313 Michael Hanselmann
    self.request_method = None
345 42242313 Michael Hanselmann
    self.request_path = None
346 42242313 Michael Hanselmann
    self.request_requestline = None
347 42242313 Michael Hanselmann
    self.request_version = self.default_request_version
348 42242313 Michael Hanselmann
349 42242313 Michael Hanselmann
    self.response_body = None
350 42242313 Michael Hanselmann
    self.response_code = HTTP_OK
351 42242313 Michael Hanselmann
    self.response_content_type = None
352 713faea6 Oleksiy Mishchenko
    self.response_headers = {}
353 42242313 Michael Hanselmann
354 42242313 Michael Hanselmann
    self.should_fork = False
355 42242313 Michael Hanselmann
356 42242313 Michael Hanselmann
    try:
357 42242313 Michael Hanselmann
      self._ReadRequest()
358 42242313 Michael Hanselmann
      self._ReadPostData()
359 42242313 Michael Hanselmann
    except HTTPException, err:
360 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
361 42242313 Michael Hanselmann
362 42242313 Michael Hanselmann
  def Close(self):
363 42242313 Michael Hanselmann
    if not self.wfile.closed:
364 42242313 Michael Hanselmann
      self.wfile.flush()
365 42242313 Michael Hanselmann
    self.wfile.close()
366 42242313 Michael Hanselmann
    self.rfile.close()
367 42242313 Michael Hanselmann
368 42242313 Michael Hanselmann
  def _DateTimeHeader(self):
369 42242313 Michael Hanselmann
    """Return the current date and time formatted for a message header.
370 42242313 Michael Hanselmann

371 42242313 Michael Hanselmann
    """
372 42242313 Michael Hanselmann
    (year, month, day, hh, mm, ss, wd, _, _) = time.gmtime()
373 42242313 Michael Hanselmann
    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
374 42242313 Michael Hanselmann
            (WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss))
375 42242313 Michael Hanselmann
376 42242313 Michael Hanselmann
  def _SetErrorStatus(self, err):
377 42242313 Michael Hanselmann
    """Sets the response code and body from a HTTPException.
378 42242313 Michael Hanselmann

379 42242313 Michael Hanselmann
    @type err: HTTPException
380 42242313 Michael Hanselmann
    @param err: Exception instance
381 42242313 Michael Hanselmann

382 42242313 Michael Hanselmann
    """
383 42242313 Michael Hanselmann
    try:
384 42242313 Michael Hanselmann
      (shortmsg, longmsg) = self.responses[err.code]
385 42242313 Michael Hanselmann
    except KeyError:
386 42242313 Michael Hanselmann
      shortmsg = longmsg = "Unknown"
387 42242313 Michael Hanselmann
388 42242313 Michael Hanselmann
    if err.message:
389 42242313 Michael Hanselmann
      message = err.message
390 42242313 Michael Hanselmann
    else:
391 42242313 Michael Hanselmann
      message = shortmsg
392 42242313 Michael Hanselmann
393 42242313 Michael Hanselmann
    values = {
394 42242313 Michael Hanselmann
      "code": err.code,
395 42242313 Michael Hanselmann
      "message": cgi.escape(message),
396 42242313 Michael Hanselmann
      "explain": longmsg,
397 42242313 Michael Hanselmann
      }
398 42242313 Michael Hanselmann
399 42242313 Michael Hanselmann
    self.response_code = err.code
400 42242313 Michael Hanselmann
    self.response_content_type = self.error_content_type
401 42242313 Michael Hanselmann
    self.response_body = self.error_message_format % values
402 42242313 Michael Hanselmann
403 42242313 Michael Hanselmann
  def HandleRequest(self):
404 42242313 Michael Hanselmann
    """Handle the actual request.
405 42242313 Michael Hanselmann

406 42242313 Michael Hanselmann
    Calls the actual handler function and converts exceptions into HTTP errors.
407 42242313 Michael Hanselmann

408 42242313 Michael Hanselmann
    """
409 42242313 Michael Hanselmann
    # Don't do anything if there's already been a problem
410 42242313 Michael Hanselmann
    if self.response_code != HTTP_OK:
411 42242313 Michael Hanselmann
      return
412 42242313 Michael Hanselmann
413 42242313 Michael Hanselmann
    assert self.request_method, "Status code %s requires a method" % HTTP_OK
414 42242313 Michael Hanselmann
415 42242313 Michael Hanselmann
    # Check whether client is still there
416 42242313 Michael Hanselmann
    self.rfile.read(0)
417 42242313 Michael Hanselmann
418 42242313 Michael Hanselmann
    try:
419 42242313 Michael Hanselmann
      try:
420 42242313 Michael Hanselmann
        result = self._server.HandleRequest(self)
421 42242313 Michael Hanselmann
422 42242313 Michael Hanselmann
        # TODO: Content-type
423 42242313 Michael Hanselmann
        encoder = HTTPJsonConverter()
424 42242313 Michael Hanselmann
        body = encoder.Encode(result)
425 42242313 Michael Hanselmann
426 42242313 Michael Hanselmann
        self.response_content_type = encoder.CONTENT_TYPE
427 42242313 Michael Hanselmann
        self.response_body = body
428 42242313 Michael Hanselmann
      except (HTTPException, KeyboardInterrupt, SystemExit):
429 42242313 Michael Hanselmann
        raise
430 42242313 Michael Hanselmann
      except Exception, err:
431 42242313 Michael Hanselmann
        logging.exception("Caught exception")
432 42242313 Michael Hanselmann
        raise HTTPInternalError(message=str(err))
433 42242313 Michael Hanselmann
      except:
434 42242313 Michael Hanselmann
        logging.exception("Unknown exception")
435 42242313 Michael Hanselmann
        raise HTTPInternalError(message="Unknown error")
436 42242313 Michael Hanselmann
437 42242313 Michael Hanselmann
    except HTTPException, err:
438 42242313 Michael Hanselmann
      self._SetErrorStatus(err)
439 42242313 Michael Hanselmann
440 42242313 Michael Hanselmann
  def SendResponse(self):
441 42242313 Michael Hanselmann
    """Sends response to the client.
442 42242313 Michael Hanselmann

443 42242313 Michael Hanselmann
    """
444 42242313 Michael Hanselmann
    # Check whether client is still there
445 42242313 Michael Hanselmann
    self.rfile.read(0)
446 42242313 Michael Hanselmann
447 42242313 Michael Hanselmann
    logging.info("%s:%s %s %s", self.client_addr[0], self.client_addr[1],
448 42242313 Michael Hanselmann
                 self.request_requestline, self.response_code)
449 42242313 Michael Hanselmann
450 42242313 Michael Hanselmann
    if self.response_code in self.responses:
451 42242313 Michael Hanselmann
      response_message = self.responses[self.response_code][0]
452 42242313 Michael Hanselmann
    else:
453 42242313 Michael Hanselmann
      response_message = ""
454 42242313 Michael Hanselmann
455 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
456 42242313 Michael Hanselmann
      self.wfile.write("%s %d %s\r\n" %
457 42242313 Michael Hanselmann
                       (self.request_version, self.response_code,
458 42242313 Michael Hanselmann
                        response_message))
459 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_SERVER, HTTP_GANETI_VERSION)
460 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_DATE, self._DateTimeHeader())
461 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_TYPE, self.response_content_type)
462 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONTENT_LENGTH, str(len(self.response_body)))
463 713faea6 Oleksiy Mishchenko
      for key, val in self.response_headers.iteritems():
464 713faea6 Oleksiy Mishchenko
        self._SendHeader(key, val)
465 713faea6 Oleksiy Mishchenko
466 42242313 Michael Hanselmann
      # We don't support keep-alive at this time
467 8a9f9060 Michael Hanselmann
      self._SendHeader(HTTP_CONNECTION, "close")
468 42242313 Michael Hanselmann
      self.wfile.write("\r\n")
469 42242313 Michael Hanselmann
470 42242313 Michael Hanselmann
    if (self.request_method != HTTP_HEAD and
471 42242313 Michael Hanselmann
        self.response_code >= HTTP_OK and
472 42242313 Michael Hanselmann
        self.response_code not in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED)):
473 42242313 Michael Hanselmann
      self.wfile.write(self.response_body)
474 42242313 Michael Hanselmann
475 42242313 Michael Hanselmann
  def _SendHeader(self, name, value):
476 42242313 Michael Hanselmann
    if self.request_version != HTTP_0_9:
477 42242313 Michael Hanselmann
      self.wfile.write("%s: %s\r\n" % (name, value))
478 42242313 Michael Hanselmann
479 42242313 Michael Hanselmann
  def _ReadRequest(self):
480 42242313 Michael Hanselmann
    """Reads and parses request line
481 42242313 Michael Hanselmann

482 42242313 Michael Hanselmann
    """
483 42242313 Michael Hanselmann
    raw_requestline = self.rfile.readline()
484 42242313 Michael Hanselmann
485 42242313 Michael Hanselmann
    requestline = raw_requestline
486 42242313 Michael Hanselmann
    if requestline[-2:] == '\r\n':
487 42242313 Michael Hanselmann
      requestline = requestline[:-2]
488 42242313 Michael Hanselmann
    elif requestline[-1:] == '\n':
489 42242313 Michael Hanselmann
      requestline = requestline[:-1]
490 42242313 Michael Hanselmann
491 42242313 Michael Hanselmann
    if not requestline:
492 42242313 Michael Hanselmann
      raise HTTPBadRequest("Empty request line")
493 42242313 Michael Hanselmann
494 42242313 Michael Hanselmann
    self.request_requestline = requestline
495 42242313 Michael Hanselmann
496 42242313 Michael Hanselmann
    logging.debug("HTTP request: %s", raw_requestline.rstrip("\r\n"))
497 42242313 Michael Hanselmann
498 42242313 Michael Hanselmann
    words = requestline.split()
499 42242313 Michael Hanselmann
500 42242313 Michael Hanselmann
    if len(words) == 3:
501 42242313 Michael Hanselmann
      [method, path, version] = words
502 42242313 Michael Hanselmann
      if version[:5] != 'HTTP/':
503 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
504 42242313 Michael Hanselmann
505 42242313 Michael Hanselmann
      try:
506 42242313 Michael Hanselmann
        base_version_number = version.split('/', 1)[1]
507 42242313 Michael Hanselmann
        version_number = base_version_number.split(".")
508 42242313 Michael Hanselmann
509 42242313 Michael Hanselmann
        # RFC 2145 section 3.1 says there can be only one "." and
510 42242313 Michael Hanselmann
        #   - major and minor numbers MUST be treated as
511 42242313 Michael Hanselmann
        #      separate integers;
512 42242313 Michael Hanselmann
        #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
513 42242313 Michael Hanselmann
        #      turn is lower than HTTP/12.3;
514 42242313 Michael Hanselmann
        #   - Leading zeros MUST be ignored by recipients.
515 42242313 Michael Hanselmann
        if len(version_number) != 2:
516 42242313 Michael Hanselmann
          raise HTTPBadRequest("Bad request version (%r)" % version)
517 42242313 Michael Hanselmann
518 42242313 Michael Hanselmann
        version_number = int(version_number[0]), int(version_number[1])
519 42242313 Michael Hanselmann
      except (ValueError, IndexError):
520 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad request version (%r)" % version)
521 42242313 Michael Hanselmann
522 42242313 Michael Hanselmann
      if version_number >= (2, 0):
523 42242313 Michael Hanselmann
        raise HTTPVersionNotSupported("Invalid HTTP Version (%s)" %
524 42242313 Michael Hanselmann
                                      base_version_number)
525 42242313 Michael Hanselmann
526 42242313 Michael Hanselmann
    elif len(words) == 2:
527 42242313 Michael Hanselmann
      version = HTTP_0_9
528 42242313 Michael Hanselmann
      [method, path] = words
529 42242313 Michael Hanselmann
      if method != HTTP_GET:
530 42242313 Michael Hanselmann
        raise HTTPBadRequest("Bad HTTP/0.9 request type (%r)" % method)
531 42242313 Michael Hanselmann
532 42242313 Michael Hanselmann
    else:
533 42242313 Michael Hanselmann
      raise HTTPBadRequest("Bad request syntax (%r)" % requestline)
534 42242313 Michael Hanselmann
535 42242313 Michael Hanselmann
    # Examine the headers and look for a Connection directive
536 42242313 Michael Hanselmann
    headers = mimetools.Message(self.rfile, 0)
537 42242313 Michael Hanselmann
538 42242313 Michael Hanselmann
    self.request_method = method
539 42242313 Michael Hanselmann
    self.request_path = path
540 42242313 Michael Hanselmann
    self.request_version = version
541 42242313 Michael Hanselmann
    self.request_headers = headers
542 42242313 Michael Hanselmann
543 42242313 Michael Hanselmann
  def _ReadPostData(self):
544 42242313 Michael Hanselmann
    """Reads POST/PUT data
545 42242313 Michael Hanselmann

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

551 42242313 Michael Hanselmann
    """
552 64357ed8 Michael Hanselmann
    # While not according to specification, we only support an entity body for
553 64357ed8 Michael Hanselmann
    # POST and PUT.
554 8a9f9060 Michael Hanselmann
    if (not self.request_method or
555 8a9f9060 Michael Hanselmann
        self.request_method.upper() not in (HTTP_POST, HTTP_PUT)):
556 42242313 Michael Hanselmann
      self.request_post_data = None
557 42242313 Michael Hanselmann
      return
558 42242313 Michael Hanselmann
559 64357ed8 Michael Hanselmann
    content_length = None
560 42242313 Michael Hanselmann
    try:
561 64357ed8 Michael Hanselmann
      if HTTP_CONTENT_LENGTH in self.request_headers:
562 64357ed8 Michael Hanselmann
        content_length = int(self.request_headers[HTTP_CONTENT_LENGTH])
563 64357ed8 Michael Hanselmann
    except TypeError:
564 64357ed8 Michael Hanselmann
      pass
565 42242313 Michael Hanselmann
    except ValueError:
566 64357ed8 Michael Hanselmann
      pass
567 64357ed8 Michael Hanselmann
568 64357ed8 Michael Hanselmann
    # 411 Length Required is specified in RFC2616, section 10.4.12 (HTTP/1.1)
569 64357ed8 Michael Hanselmann
    if content_length is None:
570 64357ed8 Michael Hanselmann
      raise HTTPLengthRequired("Missing Content-Length header or"
571 64357ed8 Michael Hanselmann
                               " invalid format")
572 42242313 Michael Hanselmann
573 42242313 Michael Hanselmann
    data = self.rfile.read(content_length)
574 42242313 Michael Hanselmann
575 42242313 Michael Hanselmann
    # TODO: Content-type, error handling
576 7c46aafd Oleksiy Mishchenko
    if data:
577 7c46aafd Oleksiy Mishchenko
      self.request_post_data = HTTPJsonConverter().Decode(data)
578 7c46aafd Oleksiy Mishchenko
    else:
579 7c46aafd Oleksiy Mishchenko
      self.request_post_data = None
580 42242313 Michael Hanselmann
581 42242313 Michael Hanselmann
    logging.debug("HTTP POST data: %s", self.request_post_data)
582 42242313 Michael Hanselmann
583 42242313 Michael Hanselmann
584 b14f759e Michael Hanselmann
class HttpServer(_HttpSocketBase):
585 42242313 Michael Hanselmann
  """Generic HTTP server class
586 42242313 Michael Hanselmann

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

589 42242313 Michael Hanselmann
  """
590 42242313 Michael Hanselmann
  MAX_CHILDREN = 20
591 42242313 Michael Hanselmann
592 f2a6fc9e Michael Hanselmann
  def __init__(self, mainloop, local_address, port,
593 f20cbea2 Michael Hanselmann
               ssl_params=None, ssl_verify_peer=False):
594 23e46494 Michael Hanselmann
    """Initializes the HTTP server
595 23e46494 Michael Hanselmann

596 23e46494 Michael Hanselmann
    @type mainloop: ganeti.daemon.Mainloop
597 23e46494 Michael Hanselmann
    @param mainloop: Mainloop used to poll for I/O events
598 23e46494 Michael Hanselmann
    @type local_addess: string
599 23e46494 Michael Hanselmann
    @param local_address: Local IP address to bind to
600 23e46494 Michael Hanselmann
    @type port: int
601 23e46494 Michael Hanselmann
    @param port: TCP port to listen on
602 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
603 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
604 f2a6fc9e Michael Hanselmann
    @type ssl_verify_peer: bool
605 f2a6fc9e Michael Hanselmann
    @param ssl_verify_peer: Whether to require client certificate and compare
606 f2a6fc9e Michael Hanselmann
                            it with our certificate
607 23e46494 Michael Hanselmann

608 23e46494 Michael Hanselmann
    """
609 b14f759e Michael Hanselmann
    _HttpSocketBase.__init__(self)
610 b14f759e Michael Hanselmann
611 42242313 Michael Hanselmann
    self.mainloop = mainloop
612 23e46494 Michael Hanselmann
    self.local_address = local_address
613 23e46494 Michael Hanselmann
    self.port = port
614 42242313 Michael Hanselmann
615 f20cbea2 Michael Hanselmann
    self.socket = self._CreateSocket(ssl_params, ssl_verify_peer)
616 f2a6fc9e Michael Hanselmann
617 b14f759e Michael Hanselmann
    # Allow port to be reused
618 b14f759e Michael Hanselmann
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
619 42242313 Michael Hanselmann
620 b14f759e Michael Hanselmann
    if self._using_ssl:
621 42242313 Michael Hanselmann
      self._fileio_class = _SSLFileObject
622 42242313 Michael Hanselmann
    else:
623 42242313 Michael Hanselmann
      self._fileio_class = socket._fileobject
624 42242313 Michael Hanselmann
625 42242313 Michael Hanselmann
    self._children = []
626 42242313 Michael Hanselmann
627 42242313 Michael Hanselmann
    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
628 42242313 Michael Hanselmann
    mainloop.RegisterSignal(self)
629 42242313 Michael Hanselmann
630 42242313 Michael Hanselmann
  def Start(self):
631 23e46494 Michael Hanselmann
    self.socket.bind((self.local_address, self.port))
632 42242313 Michael Hanselmann
    self.socket.listen(5)
633 42242313 Michael Hanselmann
634 42242313 Michael Hanselmann
  def Stop(self):
635 42242313 Michael Hanselmann
    self.socket.close()
636 42242313 Michael Hanselmann
637 42242313 Michael Hanselmann
  def OnIO(self, fd, condition):
638 42242313 Michael Hanselmann
    if condition & select.POLLIN:
639 42242313 Michael Hanselmann
      self._IncomingConnection()
640 42242313 Michael Hanselmann
641 42242313 Michael Hanselmann
  def OnSignal(self, signum):
642 42242313 Michael Hanselmann
    if signum == signal.SIGCHLD:
643 42242313 Michael Hanselmann
      self._CollectChildren(True)
644 42242313 Michael Hanselmann
645 42242313 Michael Hanselmann
  def _CollectChildren(self, quick):
646 42242313 Michael Hanselmann
    """Checks whether any child processes are done
647 42242313 Michael Hanselmann

648 42242313 Michael Hanselmann
    @type quick: bool
649 42242313 Michael Hanselmann
    @param quick: Whether to only use non-blocking functions
650 42242313 Michael Hanselmann

651 42242313 Michael Hanselmann
    """
652 42242313 Michael Hanselmann
    if not quick:
653 42242313 Michael Hanselmann
      # Don't wait for other processes if it should be a quick check
654 42242313 Michael Hanselmann
      while len(self._children) > self.MAX_CHILDREN:
655 42242313 Michael Hanselmann
        try:
656 6526ddcd Michael Hanselmann
          # Waiting without a timeout brings us into a potential DoS situation.
657 6526ddcd Michael Hanselmann
          # As soon as too many children run, we'll not respond to new
658 6526ddcd Michael Hanselmann
          # requests. The real solution would be to add a timeout for children
659 6526ddcd Michael Hanselmann
          # and killing them after some time.
660 42242313 Michael Hanselmann
          pid, status = os.waitpid(0, 0)
661 42242313 Michael Hanselmann
        except os.error:
662 42242313 Michael Hanselmann
          pid = None
663 42242313 Michael Hanselmann
        if pid and pid in self._children:
664 42242313 Michael Hanselmann
          self._children.remove(pid)
665 42242313 Michael Hanselmann
666 42242313 Michael Hanselmann
    for child in self._children:
667 42242313 Michael Hanselmann
      try:
668 42242313 Michael Hanselmann
        pid, status = os.waitpid(child, os.WNOHANG)
669 42242313 Michael Hanselmann
      except os.error:
670 42242313 Michael Hanselmann
        pid = None
671 42242313 Michael Hanselmann
      if pid and pid in self._children:
672 42242313 Michael Hanselmann
        self._children.remove(pid)
673 42242313 Michael Hanselmann
674 42242313 Michael Hanselmann
  def _IncomingConnection(self):
675 6526ddcd Michael Hanselmann
    """Called for each incoming connection
676 42242313 Michael Hanselmann

677 6526ddcd Michael Hanselmann
    """
678 6526ddcd Michael Hanselmann
    (connection, client_addr) = self.socket.accept()
679 42242313 Michael Hanselmann
680 42242313 Michael Hanselmann
    self._CollectChildren(False)
681 42242313 Michael Hanselmann
682 42242313 Michael Hanselmann
    pid = os.fork()
683 42242313 Michael Hanselmann
    if pid == 0:
684 42242313 Michael Hanselmann
      # Child process
685 6526ddcd Michael Hanselmann
      logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
686 6526ddcd Michael Hanselmann
687 42242313 Michael Hanselmann
      try:
688 6526ddcd Michael Hanselmann
        try:
689 6526ddcd Michael Hanselmann
          try:
690 6526ddcd Michael Hanselmann
            handler = None
691 6526ddcd Michael Hanselmann
            try:
692 6526ddcd Michael Hanselmann
              # Read, parse and handle request
693 6526ddcd Michael Hanselmann
              handler = _HttpConnectionHandler(self, connection, client_addr,
694 6526ddcd Michael Hanselmann
                                               self._fileio_class)
695 6526ddcd Michael Hanselmann
              handler.HandleRequest()
696 6526ddcd Michael Hanselmann
            finally:
697 6526ddcd Michael Hanselmann
              # Try to send a response
698 6526ddcd Michael Hanselmann
              if handler:
699 6526ddcd Michael Hanselmann
                handler.SendResponse()
700 6526ddcd Michael Hanselmann
                handler.Close()
701 6526ddcd Michael Hanselmann
          except SocketClosed:
702 6526ddcd Michael Hanselmann
            pass
703 6526ddcd Michael Hanselmann
        finally:
704 6526ddcd Michael Hanselmann
          logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
705 42242313 Michael Hanselmann
      except:
706 42242313 Michael Hanselmann
        logging.exception("Error while handling request from %s:%s",
707 42242313 Michael Hanselmann
                          client_addr[0], client_addr[1])
708 42242313 Michael Hanselmann
        os._exit(1)
709 42242313 Michael Hanselmann
      os._exit(0)
710 42242313 Michael Hanselmann
    else:
711 42242313 Michael Hanselmann
      self._children.append(pid)
712 42242313 Michael Hanselmann
713 42242313 Michael Hanselmann
  def HandleRequest(self, req):
714 42242313 Michael Hanselmann
    raise NotImplementedError()
715 42242313 Michael Hanselmann
716 42242313 Michael Hanselmann
717 8a0b06d2 Michael Hanselmann
class HttpClientRequest(object):
718 438a366a Michael Hanselmann
  def __init__(self, host, port, method, path, headers=None, post_data=None,
719 f20cbea2 Michael Hanselmann
               ssl_params=None, ssl_verify_peer=False):
720 8a0b06d2 Michael Hanselmann
    """Describes an HTTP request.
721 8a0b06d2 Michael Hanselmann

722 8a0b06d2 Michael Hanselmann
    @type host: string
723 8a0b06d2 Michael Hanselmann
    @param host: Hostname
724 8a0b06d2 Michael Hanselmann
    @type port: int
725 8a0b06d2 Michael Hanselmann
    @param port: Port
726 8a0b06d2 Michael Hanselmann
    @type method: string
727 8a0b06d2 Michael Hanselmann
    @param method: Method name
728 8a0b06d2 Michael Hanselmann
    @type path: string
729 8a0b06d2 Michael Hanselmann
    @param path: Request path
730 8a0b06d2 Michael Hanselmann
    @type headers: dict or None
731 8a0b06d2 Michael Hanselmann
    @param headers: Additional headers to send
732 8a0b06d2 Michael Hanselmann
    @type post_data: string or None
733 8a0b06d2 Michael Hanselmann
    @param post_data: Additional data to send
734 f20cbea2 Michael Hanselmann
    @type ssl_params: HttpSslParams
735 f20cbea2 Michael Hanselmann
    @param ssl_params: SSL key and certificate
736 f20cbea2 Michael Hanselmann
    @type ssl_verify_peer: bool
737 f20cbea2 Michael Hanselmann
    @param ssl_verify_peer: Whether to compare our certificate with server's
738 f20cbea2 Michael Hanselmann
                            certificate
739 8a0b06d2 Michael Hanselmann

740 8a0b06d2 Michael Hanselmann
    """
741 8a0b06d2 Michael Hanselmann
    if post_data is not None:
742 8a0b06d2 Michael Hanselmann
      assert method.upper() in (HTTP_POST, HTTP_PUT), \
743 8a0b06d2 Michael Hanselmann
        "Only POST and GET requests support sending data"
744 8a0b06d2 Michael Hanselmann
745 8a0b06d2 Michael Hanselmann
    assert path.startswith("/"), "Path must start with slash (/)"
746 8a0b06d2 Michael Hanselmann
747 8a0b06d2 Michael Hanselmann
    self.host = host
748 8a0b06d2 Michael Hanselmann
    self.port = port
749 f20cbea2 Michael Hanselmann
    self.ssl_params = ssl_params
750 438a366a Michael Hanselmann
    self.ssl_verify_peer = ssl_verify_peer
751 8a0b06d2 Michael Hanselmann
    self.method = method
752 8a0b06d2 Michael Hanselmann
    self.path = path
753 8a0b06d2 Michael Hanselmann
    self.headers = headers
754 8a0b06d2 Michael Hanselmann
    self.post_data = post_data
755 8a0b06d2 Michael Hanselmann
756 8a0b06d2 Michael Hanselmann
    self.success = None
757 8a0b06d2 Michael Hanselmann
    self.error = None
758 8a0b06d2 Michael Hanselmann
759 8a0b06d2 Michael Hanselmann
    self.resp_status_line = None
760 8a0b06d2 Michael Hanselmann
    self.resp_version = None
761 8a0b06d2 Michael Hanselmann
    self.resp_status = None
762 8a0b06d2 Michael Hanselmann
    self.resp_reason = None
763 8a0b06d2 Michael Hanselmann
    self.resp_headers = None
764 8a0b06d2 Michael Hanselmann
    self.resp_body = None
765 8a0b06d2 Michael Hanselmann
766 8a0b06d2 Michael Hanselmann
767 438a366a Michael Hanselmann
class HttpClientRequestExecutor(_HttpSocketBase):
768 8a0b06d2 Michael Hanselmann
  # Default headers
769 8a0b06d2 Michael Hanselmann
  DEFAULT_HEADERS = {
770 8a0b06d2 Michael Hanselmann
    HTTP_USER_AGENT: HTTP_GANETI_VERSION,
771 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, don't send "Connection: close"
772 8a0b06d2 Michael Hanselmann
    HTTP_CONNECTION: "close",
773 8a0b06d2 Michael Hanselmann
    }
774 8a0b06d2 Michael Hanselmann
775 8a0b06d2 Michael Hanselmann
  # Length limits
776 8a0b06d2 Michael Hanselmann
  STATUS_LINE_LENGTH_MAX = 512
777 8a0b06d2 Michael Hanselmann
  HEADER_LENGTH_MAX = 4 * 1024
778 8a0b06d2 Michael Hanselmann
779 438a366a Michael Hanselmann
  # Timeouts in seconds for socket layer
780 8a0b06d2 Michael Hanselmann
  # TODO: Make read timeout configurable per OpCode
781 8a0b06d2 Michael Hanselmann
  CONNECT_TIMEOUT = 5.0
782 8a0b06d2 Michael Hanselmann
  WRITE_TIMEOUT = 10
783 8a0b06d2 Michael Hanselmann
  READ_TIMEOUT = None
784 8a0b06d2 Michael Hanselmann
  CLOSE_TIMEOUT = 1
785 8a0b06d2 Michael Hanselmann
786 8a0b06d2 Michael Hanselmann
  # Parser state machine
787 8a0b06d2 Michael Hanselmann
  PS_STATUS_LINE = "status-line"
788 8a0b06d2 Michael Hanselmann
  PS_HEADERS = "headers"
789 8a0b06d2 Michael Hanselmann
  PS_BODY = "body"
790 8a0b06d2 Michael Hanselmann
  PS_COMPLETE = "complete"
791 8a0b06d2 Michael Hanselmann
792 438a366a Michael Hanselmann
  # Socket operations
793 438a366a Michael Hanselmann
  (OP_SEND,
794 438a366a Michael Hanselmann
   OP_RECV,
795 438a366a Michael Hanselmann
   OP_CLOSE_CHECK,
796 438a366a Michael Hanselmann
   OP_SHUTDOWN) = range(4)
797 438a366a Michael Hanselmann
798 8a0b06d2 Michael Hanselmann
  def __init__(self, req):
799 8a0b06d2 Michael Hanselmann
    """Initializes the HttpClientRequestExecutor class.
800 8a0b06d2 Michael Hanselmann

801 8a0b06d2 Michael Hanselmann
    @type req: HttpClientRequest
802 8a0b06d2 Michael Hanselmann
    @param req: Request object
803 8a0b06d2 Michael Hanselmann

804 8a0b06d2 Michael Hanselmann
    """
805 438a366a Michael Hanselmann
    _HttpSocketBase.__init__(self)
806 438a366a Michael Hanselmann
807 8a0b06d2 Michael Hanselmann
    self.request = req
808 8a0b06d2 Michael Hanselmann
809 8a0b06d2 Michael Hanselmann
    self.parser_status = self.PS_STATUS_LINE
810 8a0b06d2 Michael Hanselmann
    self.header_buffer = StringIO()
811 8a0b06d2 Michael Hanselmann
    self.body_buffer = StringIO()
812 8a0b06d2 Michael Hanselmann
    self.content_length = None
813 8a0b06d2 Michael Hanselmann
    self.server_will_close = None
814 8a0b06d2 Michael Hanselmann
815 8a0b06d2 Michael Hanselmann
    self.poller = select.poll()
816 8a0b06d2 Michael Hanselmann
817 8a0b06d2 Michael Hanselmann
    try:
818 8a0b06d2 Michael Hanselmann
      # TODO: Implement connection caching/keep-alive
819 f20cbea2 Michael Hanselmann
      self.sock = self._CreateSocket(req.ssl_params,
820 438a366a Michael Hanselmann
                                     req.ssl_verify_peer)
821 8a0b06d2 Michael Hanselmann
822 8a0b06d2 Michael Hanselmann
      # Disable Python's timeout
823 8a0b06d2 Michael Hanselmann
      self.sock.settimeout(None)
824 8a0b06d2 Michael Hanselmann
825 8a0b06d2 Michael Hanselmann
      # Operate in non-blocking mode
826 8a0b06d2 Michael Hanselmann
      self.sock.setblocking(0)
827 8a0b06d2 Michael Hanselmann
828 8a0b06d2 Michael Hanselmann
      force_close = True
829 8a0b06d2 Michael Hanselmann
      self._Connect()
830 8a0b06d2 Michael Hanselmann
      try:
831 8a0b06d2 Michael Hanselmann
        self._SendRequest()
832 8a0b06d2 Michael Hanselmann
        self._ReadResponse()
833 8a0b06d2 Michael Hanselmann
834 8a0b06d2 Michael Hanselmann
        # Only wait for server to close if we didn't have any exception.
835 8a0b06d2 Michael Hanselmann
        force_close = False
836 8a0b06d2 Michael Hanselmann
      finally:
837 8a0b06d2 Michael Hanselmann
        self._CloseConnection(force_close)
838 8a0b06d2 Michael Hanselmann
839 8a0b06d2 Michael Hanselmann
      self.sock.close()
840 8a0b06d2 Michael Hanselmann
      self.sock = None
841 8a0b06d2 Michael Hanselmann
842 8a0b06d2 Michael Hanselmann
      req.resp_body = self.body_buffer.getvalue()
843 8a0b06d2 Michael Hanselmann
844 8a0b06d2 Michael Hanselmann
      req.success = True
845 8a0b06d2 Michael Hanselmann
      req.error = None
846 8a0b06d2 Michael Hanselmann
847 438a366a Michael Hanselmann
    except _HttpClientError, err:
848 8a0b06d2 Michael Hanselmann
      req.success = False
849 8a0b06d2 Michael Hanselmann
      req.error = str(err)
850 8a0b06d2 Michael Hanselmann
851 8a0b06d2 Michael Hanselmann
  def _BuildRequest(self):
852 8a0b06d2 Michael Hanselmann
    """Build HTTP request.
853 8a0b06d2 Michael Hanselmann

854 8a0b06d2 Michael Hanselmann
    @rtype: string
855 8a0b06d2 Michael Hanselmann
    @return: Complete request
856 8a0b06d2 Michael Hanselmann

857 8a0b06d2 Michael Hanselmann
    """
858 8a0b06d2 Michael Hanselmann
    # Headers
859 8a0b06d2 Michael Hanselmann
    send_headers = self.DEFAULT_HEADERS.copy()
860 8a0b06d2 Michael Hanselmann
861 8a0b06d2 Michael Hanselmann
    if self.request.headers:
862 33bbdbec Michael Hanselmann
      send_headers.update(self.request.headers)
863 8a0b06d2 Michael Hanselmann
864 8a0b06d2 Michael Hanselmann
    send_headers[HTTP_HOST] = "%s:%s" % (self.request.host, self.request.port)
865 8a0b06d2 Michael Hanselmann
866 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
867 8a0b06d2 Michael Hanselmann
      send_headers[HTTP_CONTENT_LENGTH] = len(self.request.post_data)
868 8a0b06d2 Michael Hanselmann
869 8a0b06d2 Michael Hanselmann
    buf = StringIO()
870 8a0b06d2 Michael Hanselmann
871 8a0b06d2 Michael Hanselmann
    # Add request line. We only support HTTP/1.0 (no chunked transfers and no
872 8a0b06d2 Michael Hanselmann
    # keep-alive).
873 8a0b06d2 Michael Hanselmann
    # TODO: For keep-alive, change to HTTP/1.1
874 8a0b06d2 Michael Hanselmann
    buf.write("%s %s %s\r\n" % (self.request.method.upper(),
875 8a0b06d2 Michael Hanselmann
                                self.request.path, HTTP_1_0))
876 8a0b06d2 Michael Hanselmann
877 8a0b06d2 Michael Hanselmann
    # Add headers
878 8a0b06d2 Michael Hanselmann
    for name, value in send_headers.iteritems():
879 8a0b06d2 Michael Hanselmann
      buf.write("%s: %s\r\n" % (name, value))
880 8a0b06d2 Michael Hanselmann
881 8a0b06d2 Michael Hanselmann
    buf.write("\r\n")
882 8a0b06d2 Michael Hanselmann
883 8a0b06d2 Michael Hanselmann
    if self.request.post_data:
884 8a0b06d2 Michael Hanselmann
      buf.write(self.request.post_data)
885 8a0b06d2 Michael Hanselmann
886 8a0b06d2 Michael Hanselmann
    return buf.getvalue()
887 8a0b06d2 Michael Hanselmann
888 8a0b06d2 Michael Hanselmann
  def _ParseStatusLine(self):
889 8a0b06d2 Michael Hanselmann
    """Parses the status line sent by the server.
890 8a0b06d2 Michael Hanselmann

891 8a0b06d2 Michael Hanselmann
    """
892 8a0b06d2 Michael Hanselmann
    line = self.request.resp_status_line
893 8a0b06d2 Michael Hanselmann
894 8a0b06d2 Michael Hanselmann
    if not line:
895 438a366a Michael Hanselmann
      raise _HttpClientError("Empty status line")
896 8a0b06d2 Michael Hanselmann
897 8a0b06d2 Michael Hanselmann
    try:
898 8a0b06d2 Michael Hanselmann
      [version, status, reason] = line.split(None, 2)
899 8a0b06d2 Michael Hanselmann
    except ValueError:
900 8a0b06d2 Michael Hanselmann
      try:
901 8a0b06d2 Michael Hanselmann
        [version, status] = line.split(None, 1)
902 8a0b06d2 Michael Hanselmann
        reason = ""
903 8a0b06d2 Michael Hanselmann
      except ValueError:
904 8a0b06d2 Michael Hanselmann
        version = HTTP_9_0
905 8a0b06d2 Michael Hanselmann
906 8a0b06d2 Michael Hanselmann
    if version:
907 8a0b06d2 Michael Hanselmann
      version = version.upper()
908 8a0b06d2 Michael Hanselmann
909 8a0b06d2 Michael Hanselmann
    if version not in (HTTP_1_0, HTTP_1_1):
910 8a0b06d2 Michael Hanselmann
      # We do not support HTTP/0.9, despite the specification requiring it
911 8a0b06d2 Michael Hanselmann
      # (RFC2616, section 19.6)
912 438a366a Michael Hanselmann
      raise _HttpClientError("Only HTTP/1.0 and HTTP/1.1 are supported (%r)" %
913 438a366a Michael Hanselmann
                             line)
914 8a0b06d2 Michael Hanselmann
915 8a0b06d2 Michael Hanselmann
    # The status code is a three-digit number
916 8a0b06d2 Michael Hanselmann
    try:
917 8a0b06d2 Michael Hanselmann
      status = int(status)
918 8a0b06d2 Michael Hanselmann
      if status < 100 or status > 999:
919 8a0b06d2 Michael Hanselmann
        status = -1
920 8a0b06d2 Michael Hanselmann
    except ValueError:
921 8a0b06d2 Michael Hanselmann
      status = -1
922 8a0b06d2 Michael Hanselmann
923 8a0b06d2 Michael Hanselmann
    if status == -1:
924 438a366a Michael Hanselmann
      raise _HttpClientError("Invalid status code (%r)" % line)
925 8a0b06d2 Michael Hanselmann
926 8a0b06d2 Michael Hanselmann
    self.request.resp_version = version
927 8a0b06d2 Michael Hanselmann
    self.request.resp_status = status
928 8a0b06d2 Michael Hanselmann
    self.request.resp_reason = reason
929 8a0b06d2 Michael Hanselmann
930 8a0b06d2 Michael Hanselmann
  def _WillServerCloseConnection(self):
931 8a0b06d2 Michael Hanselmann
    """Evaluate whether server will close the connection.
932 8a0b06d2 Michael Hanselmann

933 8a0b06d2 Michael Hanselmann
    @rtype: bool
934 8a0b06d2 Michael Hanselmann
    @return: Whether server will close the connection
935 8a0b06d2 Michael Hanselmann

936 8a0b06d2 Michael Hanselmann
    """
937 8a0b06d2 Michael Hanselmann
    hdr_connection = self.request.resp_headers.get(HTTP_CONNECTION, None)
938 8a0b06d2 Michael Hanselmann
    if hdr_connection:
939 8a0b06d2 Michael Hanselmann
      hdr_connection = hdr_connection.lower()
940 8a0b06d2 Michael Hanselmann
941 8a0b06d2 Michael Hanselmann
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
942 8a0b06d2 Michael Hanselmann
    if self.request.resp_version == HTTP_1_1:
943 8a0b06d2 Michael Hanselmann
      return (hdr_connection and "close" in hdr_connection)
944 8a0b06d2 Michael Hanselmann
945 8a0b06d2 Michael Hanselmann
    # Some HTTP/1.0 implementations have support for persistent connections,
946 8a0b06d2 Michael Hanselmann
    # using rules different than HTTP/1.1.
947 8a0b06d2 Michael Hanselmann
948 8a0b06d2 Michael Hanselmann
    # For older HTTP, Keep-Alive indicates persistent connection.
949 8a0b06d2 Michael Hanselmann
    if self.request.resp_headers.get(HTTP_KEEP_ALIVE):
950 8a0b06d2 Michael Hanselmann
      return False
951 8a0b06d2 Michael Hanselmann
952 8a0b06d2 Michael Hanselmann
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
953 8a0b06d2 Michael Hanselmann
    # supposed to be sent by the client.
954 8a0b06d2 Michael Hanselmann
    if hdr_connection and "keep-alive" in hdr_connection:
955 8a0b06d2 Michael Hanselmann
      return False
956 8a0b06d2 Michael Hanselmann
957 8a0b06d2 Michael Hanselmann
    return True
958 8a0b06d2 Michael Hanselmann
959 8a0b06d2 Michael Hanselmann
  def _ParseHeaders(self):
960 8a0b06d2 Michael Hanselmann
    """Parses the headers sent by the server.
961 8a0b06d2 Michael Hanselmann

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

964 8a0b06d2 Michael Hanselmann
    """
965 8a0b06d2 Michael Hanselmann
    req = self.request
966 8a0b06d2 Michael Hanselmann
967 8a0b06d2 Michael Hanselmann
    # Parse headers
968 8a0b06d2 Michael Hanselmann
    self.header_buffer.seek(0, 0)
969 8a0b06d2 Michael Hanselmann
    req.resp_headers = mimetools.Message(self.header_buffer, 0)
970 8a0b06d2 Michael Hanselmann
971 8a0b06d2 Michael Hanselmann
    self.server_will_close = self._WillServerCloseConnection()
972 8a0b06d2 Michael Hanselmann
973 8a0b06d2 Michael Hanselmann
    # Do we have a Content-Length header?
974 8a0b06d2 Michael Hanselmann
    hdr_content_length = req.resp_headers.get(HTTP_CONTENT_LENGTH, None)
975 8a0b06d2 Michael Hanselmann
    if hdr_content_length:
976 8a0b06d2 Michael Hanselmann
      try:
977 8a0b06d2 Michael Hanselmann
        self.content_length = int(hdr_content_length)
978 8a0b06d2 Michael Hanselmann
      except ValueError:
979 8a0b06d2 Michael Hanselmann
        pass
980 8a0b06d2 Michael Hanselmann
      if self.content_length is not None and self.content_length < 0:
981 8a0b06d2 Michael Hanselmann
        self.content_length = None
982 8a0b06d2 Michael Hanselmann
983 8a0b06d2 Michael Hanselmann
    # does the body have a fixed length? (of zero)
984 8a0b06d2 Michael Hanselmann
    if (req.resp_status in (HTTP_NO_CONTENT, HTTP_NOT_MODIFIED) or
985 8a0b06d2 Michael Hanselmann
        100 <= req.resp_status < 200 or req.method == HTTP_HEAD):
986 8a0b06d2 Michael Hanselmann
      self.content_length = 0
987 8a0b06d2 Michael Hanselmann
988 8a0b06d2 Michael Hanselmann
    # if the connection remains open and a content-length was not provided,
989 8a0b06d2 Michael Hanselmann
    # then assume that the connection WILL close.
990 8a0b06d2 Michael Hanselmann
    if self.content_length is None:
991 8a0b06d2 Michael Hanselmann
      self.server_will_close = True
992 8a0b06d2 Michael Hanselmann
993 8a0b06d2 Michael Hanselmann
  def _CheckStatusLineLength(self, length):
994 8a0b06d2 Michael Hanselmann
    if length > self.STATUS_LINE_LENGTH_MAX:
995 438a366a Michael Hanselmann
      raise _HttpClientError("Status line longer than %d chars" %
996 438a366a Michael Hanselmann
                             self.STATUS_LINE_LENGTH_MAX)
997 8a0b06d2 Michael Hanselmann
998 8a0b06d2 Michael Hanselmann
  def _CheckHeaderLength(self, length):
999 8a0b06d2 Michael Hanselmann
    if length > self.HEADER_LENGTH_MAX:
1000 438a366a Michael Hanselmann
      raise _HttpClientError("Headers longer than %d chars" %
1001 438a366a Michael Hanselmann
                             self.HEADER_LENGTH_MAX)
1002 8a0b06d2 Michael Hanselmann
1003 8a0b06d2 Michael Hanselmann
  def _ParseBuffer(self, buf, eof):
1004 8a0b06d2 Michael Hanselmann
    """Main function for HTTP response state machine.
1005 8a0b06d2 Michael Hanselmann

1006 8a0b06d2 Michael Hanselmann
    @type buf: string
1007 8a0b06d2 Michael Hanselmann
    @param buf: Receive buffer
1008 8a0b06d2 Michael Hanselmann
    @type eof: bool
1009 8a0b06d2 Michael Hanselmann
    @param eof: Whether we've reached EOF on the socket
1010 8a0b06d2 Michael Hanselmann
    @rtype: string
1011 8a0b06d2 Michael Hanselmann
    @return: Updated receive buffer
1012 8a0b06d2 Michael Hanselmann

1013 8a0b06d2 Michael Hanselmann
    """
1014 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_STATUS_LINE:
1015 8a0b06d2 Michael Hanselmann
      # Expect status line
1016 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n")
1017 8a0b06d2 Michael Hanselmann
      if idx >= 0:
1018 8a0b06d2 Michael Hanselmann
        self.request.resp_status_line = buf[:idx]
1019 8a0b06d2 Michael Hanselmann
1020 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(self.request.resp_status_line))
1021 8a0b06d2 Michael Hanselmann
1022 8a0b06d2 Michael Hanselmann
        # Remove status line, including CRLF
1023 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 2:]
1024 8a0b06d2 Michael Hanselmann
1025 8a0b06d2 Michael Hanselmann
        self._ParseStatusLine()
1026 8a0b06d2 Michael Hanselmann
1027 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_HEADERS
1028 8a0b06d2 Michael Hanselmann
      else:
1029 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1030 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1031 8a0b06d2 Michael Hanselmann
        self._CheckStatusLineLength(len(buf))
1032 8a0b06d2 Michael Hanselmann
1033 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_HEADERS:
1034 8a0b06d2 Michael Hanselmann
      # Wait for header end
1035 8a0b06d2 Michael Hanselmann
      idx = buf.find("\r\n\r\n")
1036 8a0b06d2 Michael Hanselmann
      if idx >= 0:
1037 8a0b06d2 Michael Hanselmann
        self.header_buffer.write(buf[:idx + 2])
1038 8a0b06d2 Michael Hanselmann
1039 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(self.header_buffer.tell())
1040 8a0b06d2 Michael Hanselmann
1041 8a0b06d2 Michael Hanselmann
        # Remove headers, including CRLF
1042 8a0b06d2 Michael Hanselmann
        buf = buf[idx + 4:]
1043 8a0b06d2 Michael Hanselmann
1044 8a0b06d2 Michael Hanselmann
        self._ParseHeaders()
1045 8a0b06d2 Michael Hanselmann
1046 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_BODY
1047 8a0b06d2 Michael Hanselmann
      else:
1048 8a0b06d2 Michael Hanselmann
        # Check whether incoming data is getting too large, otherwise we just
1049 8a0b06d2 Michael Hanselmann
        # fill our read buffer.
1050 8a0b06d2 Michael Hanselmann
        self._CheckHeaderLength(len(buf))
1051 8a0b06d2 Michael Hanselmann
1052 8a0b06d2 Michael Hanselmann
    if self.parser_status == self.PS_BODY:
1053 8a0b06d2 Michael Hanselmann
      self.body_buffer.write(buf)
1054 8a0b06d2 Michael Hanselmann
      buf = ""
1055 8a0b06d2 Michael Hanselmann
1056 8a0b06d2 Michael Hanselmann
      # Check whether we've read everything
1057 8a0b06d2 Michael Hanselmann
      if (eof or
1058 8a0b06d2 Michael Hanselmann
          (self.content_length is not None and
1059 8a0b06d2 Michael Hanselmann
           self.body_buffer.tell() >= self.content_length)):
1060 8a0b06d2 Michael Hanselmann
        self.parser_status = self.PS_COMPLETE
1061 8a0b06d2 Michael Hanselmann
1062 8a0b06d2 Michael Hanselmann
    return buf
1063 8a0b06d2 Michael Hanselmann
1064 8a0b06d2 Michael Hanselmann
  def _WaitForCondition(self, event, timeout):
1065 8a0b06d2 Michael Hanselmann
    """Waits for a condition to occur on the socket.
1066 8a0b06d2 Michael Hanselmann

1067 8a0b06d2 Michael Hanselmann
    @type event: int
1068 8a0b06d2 Michael Hanselmann
    @param event: ORed condition (see select module)
1069 8a0b06d2 Michael Hanselmann
    @type timeout: float or None
1070 8a0b06d2 Michael Hanselmann
    @param timeout: Timeout in seconds
1071 8a0b06d2 Michael Hanselmann
    @rtype: int or None
1072 8a0b06d2 Michael Hanselmann
    @return: None for timeout, otherwise occured conditions
1073 8a0b06d2 Michael Hanselmann

1074 8a0b06d2 Michael Hanselmann
    """
1075 8a0b06d2 Michael Hanselmann
    check = (event | select.POLLPRI |
1076 8a0b06d2 Michael Hanselmann
             select.POLLNVAL | select.POLLHUP | select.POLLERR)
1077 8a0b06d2 Michael Hanselmann
1078 8a0b06d2 Michael Hanselmann
    if timeout is not None:
1079 8a0b06d2 Michael Hanselmann
      # Poller object expects milliseconds
1080 8a0b06d2 Michael Hanselmann
      timeout *= 1000
1081 8a0b06d2 Michael Hanselmann
1082 8a0b06d2 Michael Hanselmann
    self.poller.register(self.sock, event)
1083 8a0b06d2 Michael Hanselmann
    try:
1084 8a0b06d2 Michael Hanselmann
      while True:
1085 8a0b06d2 Michael Hanselmann
        # TODO: If the main thread receives a signal and we have no timeout, we
1086 8a0b06d2 Michael Hanselmann
        # could wait forever. This should check a global "quit" flag or
1087 8a0b06d2 Michael Hanselmann
        # something every so often.
1088 8a0b06d2 Michael Hanselmann
        io_events = self.poller.poll(timeout)
1089 8a0b06d2 Michael Hanselmann
        if io_events:
1090 8a0b06d2 Michael Hanselmann
          for (evfd, evcond) in io_events:
1091 8a0b06d2 Michael Hanselmann
            if evcond & check:
1092 8a0b06d2 Michael Hanselmann
              return evcond
1093 8a0b06d2 Michael Hanselmann
        else:
1094 8a0b06d2 Michael Hanselmann
          # Timeout
1095 8a0b06d2 Michael Hanselmann
          return None
1096 8a0b06d2 Michael Hanselmann
    finally:
1097 8a0b06d2 Michael Hanselmann
      self.poller.unregister(self.sock)
1098 8a0b06d2 Michael Hanselmann
1099 438a366a Michael Hanselmann
  def _SocketOperation(self, op, arg1, error_msg, timeout_msg):
1100 438a366a Michael Hanselmann
    """Wrapper around socket functions.
1101 438a366a Michael Hanselmann

1102 438a366a Michael Hanselmann
    This function abstracts error handling for socket operations, especially
1103 438a366a Michael Hanselmann
    for the complicated interaction with OpenSSL.
1104 438a366a Michael Hanselmann

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

1211 8a0b06d2 Michael Hanselmann
    """
1212 8a0b06d2 Michael Hanselmann
    connected = False
1213 8a0b06d2 Michael Hanselmann
    while True:
1214 438a366a Michael Hanselmann
      try:
1215 438a366a Michael Hanselmann
        connect_error = self.sock.connect_ex((self.request.host,
1216 438a366a Michael Hanselmann
                                              self.request.port))
1217 438a366a Michael Hanselmann
      except socket.gaierror, err:
1218 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed: %s" % str(err))
1219 438a366a Michael Hanselmann
1220 8a0b06d2 Michael Hanselmann
      if connect_error == errno.EINTR:
1221 8a0b06d2 Michael Hanselmann
        # Mask signals
1222 8a0b06d2 Michael Hanselmann
        pass
1223 8a0b06d2 Michael Hanselmann
1224 8a0b06d2 Michael Hanselmann
      elif connect_error == 0:
1225 8a0b06d2 Michael Hanselmann
        # Connection established
1226 8a0b06d2 Michael Hanselmann
        connected = True
1227 8a0b06d2 Michael Hanselmann
        break
1228 8a0b06d2 Michael Hanselmann
1229 8a0b06d2 Michael Hanselmann
      elif connect_error == errno.EINPROGRESS:
1230 8a0b06d2 Michael Hanselmann
        # Connection started
1231 8a0b06d2 Michael Hanselmann
        break
1232 8a0b06d2 Michael Hanselmann
1233 438a366a Michael Hanselmann
      raise _HttpClientError("Connection failed (%s: %s)" %
1234 438a366a Michael Hanselmann
                             (connect_error, os.strerror(connect_error)))
1235 8a0b06d2 Michael Hanselmann
1236 8a0b06d2 Michael Hanselmann
    if not connected:
1237 8a0b06d2 Michael Hanselmann
      # Wait for connection
1238 8a0b06d2 Michael Hanselmann
      event = self._WaitForCondition(select.POLLOUT, self.CONNECT_TIMEOUT)
1239 8a0b06d2 Michael Hanselmann
      if event is None:
1240 438a366a Michael Hanselmann
        raise _HttpClientError("Timeout while connecting to server")
1241 8a0b06d2 Michael Hanselmann
1242 8a0b06d2 Michael Hanselmann
      # Get error code
1243 8a0b06d2 Michael Hanselmann
      connect_error = self.sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
1244 8a0b06d2 Michael Hanselmann
      if connect_error != 0:
1245 438a366a Michael Hanselmann
        raise _HttpClientError("Connection failed (%s: %s)" %
1246 438a366a Michael Hanselmann
                               (connect_error, os.strerror(connect_error)))
1247 8a0b06d2 Michael Hanselmann
1248 8a0b06d2 Michael Hanselmann
    # Enable TCP keep-alive
1249 8a0b06d2 Michael Hanselmann
    self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
1250 8a0b06d2 Michael Hanselmann
1251 8a0b06d2 Michael Hanselmann
    # If needed, Linux specific options are available to change the TCP
1252 8a0b06d2 Michael Hanselmann
    # keep-alive settings, see "man 7 tcp" for TCP_KEEPCNT, TCP_KEEPIDLE and
1253 8a0b06d2 Michael Hanselmann
    # TCP_KEEPINTVL.
1254 8a0b06d2 Michael Hanselmann
1255 8a0b06d2 Michael Hanselmann
  def _SendRequest(self):
1256 8a0b06d2 Michael Hanselmann
    """Sends request to server.
1257 8a0b06d2 Michael Hanselmann

1258 8a0b06d2 Michael Hanselmann
    """
1259 8a0b06d2 Michael Hanselmann
    buf = self._BuildRequest()
1260 8a0b06d2 Michael Hanselmann
1261 8a0b06d2 Michael Hanselmann
    while buf:
1262 438a366a Michael Hanselmann
      # Send only 4 KB at a time
1263 438a366a Michael Hanselmann
      data = buf[:4096]
1264 8a0b06d2 Michael Hanselmann
1265 438a366a Michael Hanselmann
      sent = self._SocketOperation(self.OP_SEND, data,
1266 438a366a Michael Hanselmann
                                   "Error while sending request",
1267 438a366a Michael Hanselmann
                                   "Timeout while sending request")
1268 8a0b06d2 Michael Hanselmann
1269 8a0b06d2 Michael Hanselmann
      # Remove sent bytes
1270 8a0b06d2 Michael Hanselmann
      buf = buf[sent:]
1271 8a0b06d2 Michael Hanselmann
1272 8a0b06d2 Michael Hanselmann
    assert not buf, "Request wasn't sent completely"
1273 8a0b06d2 Michael Hanselmann
1274 8a0b06d2 Michael Hanselmann
  def _ReadResponse(self):
1275 8a0b06d2 Michael Hanselmann
    """Read response from server.
1276 8a0b06d2 Michael Hanselmann

1277 8a0b06d2 Michael Hanselmann
    Calls the parser function after reading a chunk of data.
1278 8a0b06d2 Michael Hanselmann

1279 8a0b06d2 Michael Hanselmann
    """
1280 8a0b06d2 Michael Hanselmann
    buf = ""
1281 8a0b06d2 Michael Hanselmann
    eof = False
1282 8a0b06d2 Michael Hanselmann
    while self.parser_status != self.PS_COMPLETE:
1283 438a366a Michael Hanselmann
      data = self._SocketOperation(self.OP_RECV, 4096,
1284 438a366a Michael Hanselmann
                                   "Error while reading response",
1285 438a366a Michael Hanselmann
                                   "Timeout while reading response")
1286 8a0b06d2 Michael Hanselmann
1287 438a366a Michael Hanselmann
      if data:
1288 438a366a Michael Hanselmann
        buf += data
1289 438a366a Michael Hanselmann
      else:
1290 8a0b06d2 Michael Hanselmann
        eof = True
1291 8a0b06d2 Michael Hanselmann
1292 8a0b06d2 Michael Hanselmann
      # Do some parsing and error checking while more data arrives
1293 8a0b06d2 Michael Hanselmann
      buf = self._ParseBuffer(buf, eof)
1294 8a0b06d2 Michael Hanselmann
1295 8a0b06d2 Michael Hanselmann
      # Must be done only after the buffer has been evaluated
1296 8a0b06d2 Michael Hanselmann
      if (eof and
1297 8a0b06d2 Michael Hanselmann
          self.parser_status in (self.PS_STATUS_LINE,
1298 8a0b06d2 Michael Hanselmann
                                 self.PS_HEADERS)):
1299 438a366a Michael Hanselmann
        raise _HttpClientError("Connection closed prematurely")
1300 8a0b06d2 Michael Hanselmann
1301 8a0b06d2 Michael Hanselmann
    # Parse rest
1302 8a0b06d2 Michael Hanselmann
    buf = self._ParseBuffer(buf, True)
1303 8a0b06d2 Michael Hanselmann
1304 8a0b06d2 Michael Hanselmann
    assert self.parser_status == self.PS_COMPLETE
1305 8a0b06d2 Michael Hanselmann
    assert not buf, "Parser didn't read full response"
1306 8a0b06d2 Michael Hanselmann
1307 8a0b06d2 Michael Hanselmann
  def _CloseConnection(self, force):
1308 8a0b06d2 Michael Hanselmann
    """Closes the connection.
1309 8a0b06d2 Michael Hanselmann

1310 8a0b06d2 Michael Hanselmann
    """
1311 8a0b06d2 Michael Hanselmann
    if self.server_will_close and not force:
1312 8a0b06d2 Michael Hanselmann
      # Wait for server to close
1313 438a366a Michael Hanselmann
      try:
1314 438a366a Michael Hanselmann
        # Check whether it's actually closed
1315 438a366a Michael Hanselmann
        if not self._SocketOperation(self.OP_CLOSE_CHECK, 1,
1316 438a366a Michael Hanselmann
                                     "Error", "Timeout"):
1317 438a366a Michael Hanselmann
          return
1318 438a366a Michael Hanselmann
      except (socket.error, _HttpClientError):
1319 438a366a Michael Hanselmann
        # Ignore errors at this stage
1320 8a0b06d2 Michael Hanselmann
        pass
1321 8a0b06d2 Michael Hanselmann
1322 8a0b06d2 Michael Hanselmann
    # Close the connection from our side
1323 438a366a Michael Hanselmann
    self._SocketOperation(self.OP_SHUTDOWN, socket.SHUT_RDWR,
1324 438a366a Michael Hanselmann
                          "Error while shutting down connection",
1325 438a366a Michael Hanselmann
                          "Timeout while shutting down connection")
1326 8a0b06d2 Michael Hanselmann
1327 8a0b06d2 Michael Hanselmann
1328 33bbdbec Michael Hanselmann
class _HttpClientPendingRequest(object):
1329 33bbdbec Michael Hanselmann
  """Data class for pending requests.
1330 33bbdbec Michael Hanselmann

1331 33bbdbec Michael Hanselmann
  """
1332 33bbdbec Michael Hanselmann
  def __init__(self, request):
1333 33bbdbec Michael Hanselmann
    self.request = request
1334 33bbdbec Michael Hanselmann
1335 33bbdbec Michael Hanselmann
    # Thread synchronization
1336 33bbdbec Michael Hanselmann
    self.done = threading.Event()
1337 33bbdbec Michael Hanselmann
1338 33bbdbec Michael Hanselmann
1339 8a0b06d2 Michael Hanselmann
class HttpClientWorker(workerpool.BaseWorker):
1340 8a0b06d2 Michael Hanselmann
  """HTTP client worker class.
1341 8a0b06d2 Michael Hanselmann

1342 8a0b06d2 Michael Hanselmann
  """
1343 33bbdbec Michael Hanselmann
  def RunTask(self, pend_req):
1344 33bbdbec Michael Hanselmann
    try:
1345 33bbdbec Michael Hanselmann
      HttpClientRequestExecutor(pend_req.request)
1346 33bbdbec Michael Hanselmann
    finally:
1347 33bbdbec Michael Hanselmann
      pend_req.done.set()
1348 8a0b06d2 Michael Hanselmann
1349 8a0b06d2 Michael Hanselmann
1350 8a0b06d2 Michael Hanselmann
class HttpClientWorkerPool(workerpool.WorkerPool):
1351 8a0b06d2 Michael Hanselmann
  def __init__(self, manager):
1352 8a0b06d2 Michael Hanselmann
    workerpool.WorkerPool.__init__(self, HTTP_CLIENT_THREADS,
1353 8a0b06d2 Michael Hanselmann
                                   HttpClientWorker)
1354 8a0b06d2 Michael Hanselmann
    self.manager = manager
1355 8a0b06d2 Michael Hanselmann
1356 8a0b06d2 Michael Hanselmann
1357 8a0b06d2 Michael Hanselmann
class HttpClientManager(object):
1358 33bbdbec Michael Hanselmann
  """Manages HTTP requests.
1359 33bbdbec Michael Hanselmann

1360 33bbdbec Michael Hanselmann
  """
1361 8a0b06d2 Michael Hanselmann
  def __init__(self):
1362 8a0b06d2 Michael Hanselmann
    self._wpool = HttpClientWorkerPool(self)
1363 8a0b06d2 Michael Hanselmann
1364 8a0b06d2 Michael Hanselmann
  def __del__(self):
1365 8a0b06d2 Michael Hanselmann
    self.Shutdown()
1366 8a0b06d2 Michael Hanselmann
1367 8a0b06d2 Michael Hanselmann
  def ExecRequests(self, requests):
1368 33bbdbec Michael Hanselmann
    """Execute HTTP requests.
1369 8a0b06d2 Michael Hanselmann

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

1372 33bbdbec Michael Hanselmann
    @type requests: List of HttpClientRequest instances
1373 33bbdbec Michael Hanselmann
    @param requests: The requests to execute
1374 33bbdbec Michael Hanselmann
    @rtype: List of HttpClientRequest instances
1375 33bbdbec Michael Hanselmann
    @returns: The list of requests passed in
1376 33bbdbec Michael Hanselmann

1377 33bbdbec Michael Hanselmann
    """
1378 33bbdbec Michael Hanselmann
    # _HttpClientPendingRequest is used for internal thread synchronization
1379 33bbdbec Michael Hanselmann
    pending = [_HttpClientPendingRequest(req) for req in requests]
1380 33bbdbec Michael Hanselmann
1381 33bbdbec Michael Hanselmann
    try:
1382 33bbdbec Michael Hanselmann
      # Add requests to queue
1383 33bbdbec Michael Hanselmann
      for pend_req in pending:
1384 33bbdbec Michael Hanselmann
        self._wpool.AddTask(pend_req)
1385 33bbdbec Michael Hanselmann
1386 33bbdbec Michael Hanselmann
    finally:
1387 33bbdbec Michael Hanselmann
      # In case of an exception we should still wait for the rest, otherwise
1388 33bbdbec Michael Hanselmann
      # another thread from the worker pool could modify the request object
1389 33bbdbec Michael Hanselmann
      # after we returned.
1390 33bbdbec Michael Hanselmann
1391 33bbdbec Michael Hanselmann
      # And wait for them to finish
1392 33bbdbec Michael Hanselmann
      for pend_req in pending:
1393 33bbdbec Michael Hanselmann
        pend_req.done.wait()
1394 33bbdbec Michael Hanselmann
1395 33bbdbec Michael Hanselmann
    # Return original list
1396 8a0b06d2 Michael Hanselmann
    return requests
1397 8a0b06d2 Michael Hanselmann
1398 8a0b06d2 Michael Hanselmann
  def Shutdown(self):
1399 33bbdbec Michael Hanselmann
    self._wpool.Quiesce()
1400 8a0b06d2 Michael Hanselmann
    self._wpool.TerminateWorkers()
1401 8a0b06d2 Michael Hanselmann
1402 8a0b06d2 Michael Hanselmann
1403 42242313 Michael Hanselmann
class _SSLFileObject(object):
1404 42242313 Michael Hanselmann
  """Wrapper around socket._fileobject
1405 42242313 Michael Hanselmann

1406 42242313 Michael Hanselmann
  This wrapper is required to handle OpenSSL exceptions.
1407 42242313 Michael Hanselmann

1408 42242313 Michael Hanselmann
  """
1409 42242313 Michael Hanselmann
  def _RequireOpenSocket(fn):
1410 42242313 Michael Hanselmann
    def wrapper(self, *args, **kwargs):
1411 42242313 Michael Hanselmann
      if self.closed:
1412 42242313 Michael Hanselmann
        raise SocketClosed("Socket is closed")
1413 42242313 Michael Hanselmann
      return fn(self, *args, **kwargs)
1414 42242313 Michael Hanselmann
    return wrapper
1415 42242313 Michael Hanselmann
1416 42242313 Michael Hanselmann
  def __init__(self, sock, mode='rb', bufsize=-1):
1417 42242313 Michael Hanselmann
    self._base = socket._fileobject(sock, mode=mode, bufsize=bufsize)
1418 42242313 Michael Hanselmann
1419 42242313 Michael Hanselmann
  def _ConnectionLost(self):
1420 42242313 Michael Hanselmann
    self._base = None
1421 42242313 Michael Hanselmann
1422 42242313 Michael Hanselmann
  def _getclosed(self):
1423 42242313 Michael Hanselmann
    return self._base is None or self._base.closed
1424 42242313 Michael Hanselmann
  closed = property(_getclosed, doc="True if the file is closed")
1425 42242313 Michael Hanselmann
1426 42242313 Michael Hanselmann
  @_RequireOpenSocket
1427 42242313 Michael Hanselmann
  def close(self):
1428 42242313 Michael Hanselmann
    return self._base.close()
1429 42242313 Michael Hanselmann
1430 42242313 Michael Hanselmann
  @_RequireOpenSocket
1431 42242313 Michael Hanselmann
  def flush(self):
1432 42242313 Michael Hanselmann
    return self._base.flush()
1433 42242313 Michael Hanselmann
1434 42242313 Michael Hanselmann
  @_RequireOpenSocket
1435 42242313 Michael Hanselmann
  def fileno(self):
1436 42242313 Michael Hanselmann
    return self._base.fileno()
1437 42242313 Michael Hanselmann
1438 42242313 Michael Hanselmann
  @_RequireOpenSocket
1439 42242313 Michael Hanselmann
  def read(self, size=-1):
1440 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.read, size=size)
1441 42242313 Michael Hanselmann
1442 42242313 Michael Hanselmann
  @_RequireOpenSocket
1443 42242313 Michael Hanselmann
  def readline(self, size=-1):
1444 42242313 Michael Hanselmann
    return self._ReadWrapper(self._base.readline, size=size)
1445 42242313 Michael Hanselmann
1446 42242313 Michael Hanselmann
  def _ReadWrapper(self, fn, *args, **kwargs):
1447 42242313 Michael Hanselmann
    while True:
1448 42242313 Michael Hanselmann
      try:
1449 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
1450 42242313 Michael Hanselmann
1451 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
1452 42242313 Michael Hanselmann
        self._ConnectionLost()
1453 42242313 Michael Hanselmann
        return ""
1454 42242313 Michael Hanselmann
1455 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantReadError:
1456 42242313 Michael Hanselmann
        continue
1457 42242313 Michael Hanselmann
1458 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantWriteError:
1459 42242313 Michael Hanselmann
      # TODO
1460 42242313 Michael Hanselmann
1461 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, (retval, desc):
1462 d7bace1b Michael Hanselmann
        if ((retval == -1 and desc == _SSL_UNEXPECTED_EOF)
1463 42242313 Michael Hanselmann
            or retval > 0):
1464 42242313 Michael Hanselmann
          self._ConnectionLost()
1465 42242313 Michael Hanselmann
          return ""
1466 42242313 Michael Hanselmann
1467 42242313 Michael Hanselmann
        logging.exception("Error in OpenSSL")
1468 42242313 Michael Hanselmann
        self._ConnectionLost()
1469 42242313 Michael Hanselmann
        raise socket.error(err.args)
1470 42242313 Michael Hanselmann
1471 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
1472 42242313 Michael Hanselmann
        self._ConnectionLost()
1473 42242313 Michael Hanselmann
        raise socket.error(err.args)
1474 42242313 Michael Hanselmann
1475 42242313 Michael Hanselmann
  @_RequireOpenSocket
1476 42242313 Michael Hanselmann
  def write(self, data):
1477 42242313 Michael Hanselmann
    return self._WriteWrapper(self._base.write, data)
1478 42242313 Michael Hanselmann
1479 42242313 Michael Hanselmann
  def _WriteWrapper(self, fn, *args, **kwargs):
1480 42242313 Michael Hanselmann
    while True:
1481 42242313 Michael Hanselmann
      try:
1482 42242313 Michael Hanselmann
        return fn(*args, **kwargs)
1483 42242313 Michael Hanselmann
      except OpenSSL.SSL.ZeroReturnError, err:
1484 42242313 Michael Hanselmann
        self._ConnectionLost()
1485 42242313 Michael Hanselmann
        return 0
1486 42242313 Michael Hanselmann
1487 42242313 Michael Hanselmann
      except OpenSSL.SSL.WantWriteError:
1488 42242313 Michael Hanselmann
        continue
1489 42242313 Michael Hanselmann
1490 42242313 Michael Hanselmann
      #except OpenSSL.SSL.WantReadError:
1491 42242313 Michael Hanselmann
      # TODO
1492 42242313 Michael Hanselmann
1493 42242313 Michael Hanselmann
      except OpenSSL.SSL.SysCallError, err:
1494 42242313 Michael Hanselmann
        if err.args[0] == -1 and data == "":
1495 42242313 Michael Hanselmann
          # errors when writing empty strings are expected
1496 42242313 Michael Hanselmann
          # and can be ignored
1497 42242313 Michael Hanselmann
          return 0
1498 42242313 Michael Hanselmann
1499 42242313 Michael Hanselmann
        self._ConnectionLost()
1500 42242313 Michael Hanselmann
        raise socket.error(err.args)
1501 42242313 Michael Hanselmann
1502 42242313 Michael Hanselmann
      except OpenSSL.SSL.Error, err:
1503 42242313 Michael Hanselmann
        self._ConnectionLost()
1504 42242313 Michael Hanselmann
        raise socket.error(err.args)