diff --git a/lib/http.py b/lib/http.py
index 699cb274ed635d56ad46f1b1a12321131f4504a6..d0e930e3e7f54a0caa107128be268000388af280 100644
--- a/lib/http.py
+++ b/lib/http.py
@@ -90,6 +90,11 @@ HTTP_KEEP_ALIVE = "Keep-Alive"
 
 _SSL_UNEXPECTED_EOF = "Unexpected EOF"
 
+# Socket operations
+(SOCKOP_SEND,
+ SOCKOP_RECV,
+ SOCKOP_SHUTDOWN) = range(3)
+
 
 class SocketClosed(socket.error):
   pass
@@ -101,7 +106,14 @@ class _HttpClientError(Exception):
   This should only be used for internal error reporting.
 
   """
-  pass
+
+
+class _HttpSocketTimeout(Exception):
+  """Internal exception for socket timeouts.
+
+  This should only be used for internal error reporting.
+
+  """
 
 
 class HTTPException(Exception):
@@ -160,13 +172,13 @@ class HTTPJsonConverter:
     return serializer.LoadJson(data)
 
 
-def WaitForSocketCondition(sock, poller, event, timeout):
+def WaitForSocketCondition(poller, sock, event, timeout):
   """Waits for a condition to occur on the socket.
 
-  @type sock: socket
-  @param socket: Wait for events on this socket
   @type poller: select.Poller
   @param poller: Poller object as created by select.poll()
+  @type sock: socket
+  @param socket: Wait for events on this socket
   @type event: int
   @param event: ORed condition (see select module)
   @type timeout: float or None
@@ -199,6 +211,122 @@ def WaitForSocketCondition(sock, poller, event, timeout):
     poller.unregister(sock)
 
 
+def SocketOperation(poller, sock, op, arg1, timeout):
+  """Wrapper around socket functions.
+
+  This function abstracts error handling for socket operations, especially
+  for the complicated interaction with OpenSSL.
+
+  @type poller: select.Poller
+  @param poller: Poller object as created by select.poll()
+  @type sock: socket
+  @param socket: Socket for the operation
+  @type op: int
+  @param op: Operation to execute (SOCKOP_* constants)
+  @type arg1: any
+  @param arg1: Parameter for function (if needed)
+  @type timeout: None or float
+  @param timeout: Timeout in seconds or None
+
+  """
+  # TODO: event_poll/event_check/override
+  if op == SOCKOP_SEND:
+    event_poll = select.POLLOUT
+    event_check = select.POLLOUT
+
+  elif op == SOCKOP_RECV:
+    event_poll = select.POLLIN
+    event_check = select.POLLIN | select.POLLPRI
+
+  elif op == SOCKOP_SHUTDOWN:
+    event_poll = None
+    event_check = None
+
+    # The timeout is only used when OpenSSL requests polling for a condition.
+    # It is not advisable to have no timeout for shutdown.
+    assert timeout
+
+  else:
+    raise AssertionError("Invalid socket operation")
+
+  # No override by default
+  event_override = 0
+
+  while True:
+    # Poll only for certain operations and when asked for by an override
+    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV):
+      if event_override:
+        wait_for_event = event_override
+      else:
+        wait_for_event = event_poll
+
+      event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
+      if event is None:
+        raise _HttpSocketTimeout()
+
+      if (op == SOCKOP_RECV and
+          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
+        return ""
+
+      if not event & wait_for_event:
+        continue
+
+    # Reset override
+    event_override = 0
+
+    try:
+      try:
+        if op == SOCKOP_SEND:
+          return sock.send(arg1)
+
+        elif op == SOCKOP_RECV:
+          return sock.recv(arg1)
+
+        elif op == SOCKOP_SHUTDOWN:
+          if isinstance(sock, OpenSSL.SSL.ConnectionType):
+            # PyOpenSSL's shutdown() doesn't take arguments
+            return sock.shutdown()
+          else:
+            return sock.shutdown(arg1)
+
+      except OpenSSL.SSL.WantWriteError:
+        # OpenSSL wants to write, poll for POLLOUT
+        event_override = select.POLLOUT
+        continue
+
+      except OpenSSL.SSL.WantReadError:
+        # OpenSSL wants to read, poll for POLLIN
+        event_override = select.POLLIN | select.POLLPRI
+        continue
+
+      except OpenSSL.SSL.WantX509LookupError:
+        continue
+
+      except OpenSSL.SSL.SysCallError, err:
+        if op == SOCKOP_SEND:
+          # arg1 is the data when writing
+          if err.args and err.args[0] == -1 and arg1 == "":
+            # errors when writing empty strings are expected
+            # and can be ignored
+            return 0
+
+        elif op == SOCKOP_RECV:
+          if err.args == (-1, _SSL_UNEXPECTED_EOF):
+            return ""
+
+        raise socket.error(err.args)
+
+      except OpenSSL.SSL.Error, err:
+        raise socket.error(err.args)
+
+    except socket.error, err:
+      if err.args and err.args[0] == errno.EAGAIN:
+        # Ignore EAGAIN
+        continue
+
+      raise
+
+
 class HttpSslParams(object):
   """Data class for SSL key and certificate.
 
@@ -773,12 +901,6 @@ class HttpClientRequestExecutor(_HttpSocketBase):
   PS_BODY = "body"
   PS_COMPLETE = "complete"
 
-  # Socket operations
-  (OP_SEND,
-   OP_RECV,
-   OP_CLOSE_CHECK,
-   OP_SHUTDOWN) = range(4)
-
   def __init__(self, req):
     """Initializes the HttpClientRequestExecutor class.
 
@@ -1045,116 +1167,6 @@ class HttpClientRequestExecutor(_HttpSocketBase):
 
     return buf
 
-  def _SocketOperation(self, op, arg1, error_msg, timeout_msg):
-    """Wrapper around socket functions.
-
-    This function abstracts error handling for socket operations, especially
-    for the complicated interaction with OpenSSL.
-
-    """
-    if op == self.OP_SEND:
-      event_poll = select.POLLOUT
-      event_check = select.POLLOUT
-      timeout = self.WRITE_TIMEOUT
-
-    elif op in (self.OP_RECV, self.OP_CLOSE_CHECK):
-      event_poll = select.POLLIN
-      event_check = select.POLLIN | select.POLLPRI
-      if op == self.OP_CLOSE_CHECK:
-        timeout = self.CLOSE_TIMEOUT
-      else:
-        timeout = self.READ_TIMEOUT
-
-    elif op == self.OP_SHUTDOWN:
-      event_poll = None
-      event_check = None
-
-      # The timeout is only used when OpenSSL requests polling for a condition.
-      # It is not advisable to have no timeout for shutdown.
-      timeout = self.WRITE_TIMEOUT
-
-    else:
-      raise AssertionError("Invalid socket operation")
-
-    # No override by default
-    event_override = 0
-
-    while True:
-      # Poll only for certain operations and when asked for by an override
-      if (event_override or
-          op in (self.OP_SEND, self.OP_RECV, self.OP_CLOSE_CHECK)):
-        if event_override:
-          wait_for_event = event_override
-        else:
-          wait_for_event = event_poll
-
-        event = WaitForSocketCondition(self.sock, self.poller, wait_for_event,
-                                       timeout)
-        if event is None:
-          raise _HttpClientTimeout(timeout_msg)
-
-        if (op == self.OP_RECV and
-            event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
-          return ""
-
-        if not event & wait_for_event:
-          continue
-
-      # Reset override
-      event_override = 0
-
-      try:
-        try:
-          if op == self.OP_SEND:
-            return self.sock.send(arg1)
-
-          elif op in (self.OP_RECV, self.OP_CLOSE_CHECK):
-            return self.sock.recv(arg1)
-
-          elif op == self.OP_SHUTDOWN:
-            if self._using_ssl:
-              # PyOpenSSL's shutdown() doesn't take arguments
-              return self.sock.shutdown()
-            else:
-              return self.sock.shutdown(arg1)
-
-        except OpenSSL.SSL.WantWriteError:
-          # OpenSSL wants to write, poll for POLLOUT
-          event_override = select.POLLOUT
-          continue
-
-        except OpenSSL.SSL.WantReadError:
-          # OpenSSL wants to read, poll for POLLIN
-          event_override = select.POLLIN | select.POLLPRI
-          continue
-
-        except OpenSSL.SSL.WantX509LookupError:
-          continue
-
-        except OpenSSL.SSL.SysCallError, err:
-          if op == self.OP_SEND:
-            # arg1 is the data when writing
-            if err.args and err.args[0] == -1 and arg1 == "":
-              # errors when writing empty strings are expected
-              # and can be ignored
-              return 0
-
-          elif op == self.OP_RECV:
-            if err.args == (-1, _SSL_UNEXPECTED_EOF):
-              return ""
-
-          raise socket.error(err.args)
-
-        except OpenSSL.SSL.Error, err:
-          raise socket.error(err.args)
-
-      except socket.error, err:
-        if err.args and err.args[0] == errno.EAGAIN:
-          # Ignore EAGAIN
-          continue
-
-        raise _HttpClientError("%s: %s" % (error_msg, str(err)))
-
   def _Connect(self):
     """Non-blocking connect to host with timeout.
 
@@ -1185,7 +1197,7 @@ class HttpClientRequestExecutor(_HttpSocketBase):
 
     if not connected:
       # Wait for connection
-      event = WaitForSocketCondition(self.sock, self.poller,
+      event = WaitForSocketCondition(self.poller, self.sock,
                                      select.POLLOUT, self.CONNECT_TIMEOUT)
       if event is None:
         raise _HttpClientError("Timeout while connecting to server")
@@ -1213,9 +1225,13 @@ class HttpClientRequestExecutor(_HttpSocketBase):
       # Send only 4 KB at a time
       data = buf[:4096]
 
-      sent = self._SocketOperation(self.OP_SEND, data,
-                                   "Error while sending request",
-                                   "Timeout while sending request")
+      try:
+        sent = SocketOperation(self.poller, self.sock, SOCKOP_SEND, data,
+                               self.WRITE_TIMEOUT)
+      except _HttpSocketTimeout:
+        raise _HttpClientError("Timeout while sending request")
+      except socket.error, err:
+        raise _HttpClientError("Error sending request: %s" % err)
 
       # Remove sent bytes
       buf = buf[sent:]
@@ -1231,9 +1247,13 @@ class HttpClientRequestExecutor(_HttpSocketBase):
     buf = ""
     eof = False
     while self.parser_status != self.PS_COMPLETE:
-      data = self._SocketOperation(self.OP_RECV, 4096,
-                                   "Error while reading response",
-                                   "Timeout while reading response")
+      try:
+        data = SocketOperation(self.poller, self.sock, SOCKOP_RECV, 4096,
+                               self.READ_TIMEOUT)
+      except _HttpSocketTimeout:
+        raise _HttpClientError("Timeout while reading response")
+      except socket.error, err:
+        raise _HttpClientError("Error while reading response: %s" % err)
 
       if data:
         buf += data
@@ -1263,17 +1283,21 @@ class HttpClientRequestExecutor(_HttpSocketBase):
       # Wait for server to close
       try:
         # Check whether it's actually closed
-        if not self._SocketOperation(self.OP_CLOSE_CHECK, 1,
-                                     "Error", "Timeout"):
+        if not SocketOperation(self.poller, self.sock, SOCKOP_RECV, 1,
+                               self.CLOSE_TIMEOUT):
           return
-      except (socket.error, _HttpClientError):
+      except (socket.error, _HttpClientError, _HttpSocketTimeout):
         # Ignore errors at this stage
         pass
 
     # Close the connection from our side
-    self._SocketOperation(self.OP_SHUTDOWN, socket.SHUT_RDWR,
-                          "Error while shutting down connection",
-                          "Timeout while shutting down connection")
+    try:
+      SocketOperation(self.poller, self.sock, SOCKOP_SHUTDOWN,
+                      socket.SHUT_RDWR, self.WRITE_TIMEOUT)
+    except _HttpSocketTimeout:
+      raise _HttpClientError("Timeout while shutting down connection")
+    except socket.error, err:
+      raise _HttpClientError("Error while shutting down connection: %s" % err)
 
 
 class _HttpClientPendingRequest(object):