"""
-import BaseHTTPServer
-import cgi
-import logging
-import OpenSSL
+# pylint: disable-msg=E1103
+
+# # E1103: %s %r has no %r member (but some types could not be
+# inferred), since _socketobject could be ssl or not and pylint
+# doesn't parse that
+
+
import os
import select
import socket
-import sys
-import time
-import signal
import errno
import threading
-from ganeti import constants
-from ganeti import serializer
from ganeti import workerpool
-from ganeti import utils
from ganeti import http
+from ganeti import utils
HTTP_CLIENT_THREADS = 10
class HttpClientRequest(object):
def __init__(self, host, port, method, path, headers=None, post_data=None,
- ssl_params=None, ssl_verify_peer=False):
+ ssl_params=None, ssl_verify_peer=False, read_timeout=None):
"""Describes an HTTP request.
@type host: string
@type ssl_params: HttpSslParams
@param ssl_params: SSL key and certificate
@type ssl_verify_peer: bool
- @param ssl_verify_peer: Whether to compare our certificate with server's
- certificate
+ @param ssl_verify_peer: Whether to compare our certificate with
+ server's certificate
+ @type read_timeout: int
+ @param read_timeout: if passed, it will be used as the read
+ timeout while reading the response from the server
"""
if post_data is not None:
self.path = path
self.headers = headers
self.post_data = post_data
+ self.read_timeout = read_timeout
self.success = None
self.error = None
self.resp_headers = None
self.resp_body = None
+ def __repr__(self):
+ status = ["%s.%s" % (self.__class__.__module__, self.__class__.__name__),
+ "%s:%s" % (self.host, self.port),
+ self.method,
+ self.path]
+
+ return "<%s at %#x>" % (" ".join(status), id(self))
+
class _HttpClientToServerMessageWriter(http.HttpMessageWriter):
pass
status = int(status)
if status < 100 or status > 999:
status = -1
- except ValueError:
+ except (TypeError, ValueError):
status = -1
if status == -1:
http.HttpBase.__init__(self)
self.request = req
- self.poller = select.poll()
-
try:
# TODO: Implement connection caching/keep-alive
self.sock = self._CreateSocket(req.ssl_params,
finally:
# TODO: Keep-alive is not supported, always close connection
force_close = True
- http.ShutdownConnection(self.poller, self.sock,
- self.CLOSE_TIMEOUT, self.WRITE_TIMEOUT,
- response_msg_reader, force_close)
+ http.ShutdownConnection(self.sock, self.CLOSE_TIMEOUT,
+ self.WRITE_TIMEOUT, response_msg_reader,
+ force_close)
self.sock.close()
self.sock = None
if not connected:
# Wait for connection
- event = http.WaitForSocketCondition(self.poller, self.sock,
- select.POLLOUT, self.CONNECT_TIMEOUT)
+ event = utils.WaitForFdCondition(self.sock, select.POLLOUT,
+ self.CONNECT_TIMEOUT)
if event is None:
raise http.HttpError("Timeout while connecting to server")
# keep-alive settings, see "man 7 tcp" for TCP_KEEPCNT, TCP_KEEPIDLE and
# TCP_KEEPINTVL.
+ # Do the secret SSL handshake
+ if self.using_ssl:
+ self.sock.set_connect_state() # pylint: disable-msg=E1103
+ try:
+ http.Handshake(self.sock, self.WRITE_TIMEOUT)
+ except http.HttpSessionHandshakeUnexpectedEOF:
+ raise http.HttpError("Server closed connection during SSL handshake")
+
def _SendRequest(self):
"""Sends request to server.
"""
response_msg = http.HttpMessage()
+ if self.request.read_timeout is None:
+ timeout = self.READ_TIMEOUT
+ else:
+ timeout = self.request.read_timeout
+
try:
response_msg_reader = \
- _HttpServerToClientMessageReader(self.sock, response_msg,
- self.READ_TIMEOUT)
+ _HttpServerToClientMessageReader(self.sock, response_msg, timeout)
except http.HttpSocketTimeout:
raise http.HttpError("Timeout while reading response")
except socket.error, err:
# Thread synchronization
self.done = threading.Event()
+ def __repr__(self):
+ status = ["%s.%s" % (self.__class__.__module__, self.__class__.__name__),
+ "req=%r" % self.request]
+
+ return "<%s at %#x>" % (" ".join(status), id(self))
+
class HttpClientWorker(workerpool.BaseWorker):
"""HTTP client worker class.
"""
- def RunTask(self, pend_req):
+ def RunTask(self, pend_req): # pylint: disable-msg=W0221
try:
HttpClientRequestExecutor(pend_req.request)
finally:
class HttpClientWorkerPool(workerpool.WorkerPool):
def __init__(self, manager):
- workerpool.WorkerPool.__init__(self, HTTP_CLIENT_THREADS,
+ workerpool.WorkerPool.__init__(self, "HttpClient",
+ HTTP_CLIENT_THREADS,
HttpClientWorker)
self.manager = manager
@type requests: List of HttpClientRequest instances
@param requests: The requests to execute
@rtype: List of HttpClientRequest instances
- @returns: The list of requests passed in
+ @return: The list of requests passed in
"""
# _HttpClientPendingRequest is used for internal thread synchronization