LUSetInstanceParams: nic parameters
[ganeti-local] / lib / http / server.py
index 6a359df..b74eb36 100644 (file)
@@ -86,6 +86,10 @@ class _HttpServerRequest(object):
     # Response attributes
     self.resp_headers = {}
 
+    # Private data for request handler (useful in combination with
+    # authentication)
+    self.private = None
+
 
 class _HttpServerToClientMessageWriter(http.HttpMessageWriter):
   """Writes an HTTP response to client.
@@ -98,7 +102,7 @@ class _HttpServerToClientMessageWriter(http.HttpMessageWriter):
     @param sock: Target socket
     @type request_msg: http.HttpMessage
     @param request_msg: Request message, required to determine whether
-                        response may have a message body
+        response may have a message body
     @type response_msg: http.HttpMessage
     @param response_msg: Response message
     @type write_timeout: float
@@ -203,12 +207,13 @@ class _HttpClientToServerMessageReader(http.HttpMessageReader):
     return http.HttpClientToServerStartLine(method, path, version)
 
 
-class _HttpServerRequestExecutor(object):
+class HttpServerRequestExecutor(object):
   """Implements server side of HTTP.
 
-  This class implements the server side of HTTP. It's based on code of Python's
-  BaseHTTPServer, from both version 2.4 and 3k. It does not support non-ASCII
-  character encodings. Keep-alive connections are not supported.
+  This class implements the server side of HTTP. It's based on code of
+  Python's BaseHTTPServer, from both version 2.4 and 3k. It does not
+  support non-ASCII character encodings. Keep-alive connections are
+  not supported.
 
   """
   # The default request version.  This only affects responses up until
@@ -249,7 +254,7 @@ class _HttpServerRequestExecutor(object):
     # Operate in non-blocking mode
     self.sock.setblocking(0)
 
-    logging.info("Connection from %s:%s", client_addr[0], client_addr[1])
+    logging.debug("Connection from %s:%s", client_addr[0], client_addr[1])
     try:
       request_msg_reader = None
       force_close = True
@@ -282,7 +287,7 @@ class _HttpServerRequestExecutor(object):
       self.sock.close()
       self.sock = None
     finally:
-      logging.info("Disconnected %s:%s", client_addr[0], client_addr[1])
+      logging.debug("Disconnected %s:%s", client_addr[0], client_addr[1])
 
   def _ReadRequest(self):
     """Reads a request sent by client.
@@ -308,22 +313,30 @@ class _HttpServerRequestExecutor(object):
     handler_context = _HttpServerRequest(self.request_msg)
 
     try:
-      result = self.server.HandleRequest(handler_context)
-    except (http.HttpException, KeyboardInterrupt, SystemExit):
-      raise
-    except Exception, err:
-      logging.exception("Caught exception")
-      raise http.HttpInternalServerError(message=str(err))
-    except:
-      logging.exception("Unknown exception")
-      raise http.HttpInternalServerError(message="Unknown error")
-
-    # TODO: Content-type
-    encoder = http.HttpJsonConverter()
-    self.response_msg.start_line.code = http.HTTP_OK
-    self.response_msg.body = encoder.Encode(result)
-    self.response_msg.headers = handler_context.resp_headers
-    self.response_msg.headers[http.HTTP_CONTENT_TYPE] = encoder.CONTENT_TYPE
+      try:
+        # Authentication, etc.
+        self.server.PreHandleRequest(handler_context)
+
+        # Call actual request handler
+        result = self.server.HandleRequest(handler_context)
+      except (http.HttpException, KeyboardInterrupt, SystemExit):
+        raise
+      except Exception, err:
+        logging.exception("Caught exception")
+        raise http.HttpInternalServerError(message=str(err))
+      except:
+        logging.exception("Unknown exception")
+        raise http.HttpInternalServerError(message="Unknown error")
+
+      # TODO: Content-type
+      encoder = http.HttpJsonConverter()
+      self.response_msg.start_line.code = http.HTTP_OK
+      self.response_msg.body = encoder.Encode(result)
+      self.response_msg.headers = handler_context.resp_headers
+      self.response_msg.headers[http.HTTP_CONTENT_TYPE] = encoder.CONTENT_TYPE
+    finally:
+      # No reason to keep this any longer, even for exceptions
+      handler_context.private = None
 
   def _SendResponse(self):
     """Sends the response to the client.
@@ -392,8 +405,18 @@ class _HttpServerRequestExecutor(object):
     headers[http.HTTP_CONTENT_TYPE] = self.error_content_type
     self.response_msg.headers = headers
 
-    self.response_msg.body = self.error_message_format % values
+    self.response_msg.body = self._FormatErrorMessage(values)
 
+  def _FormatErrorMessage(self, values):
+    """Formats the body of an error message.
+
+    @type values: dict
+    @param values: dictionary with keys code, message and explain.
+    @rtype: string
+    @return: the body of the message
+
+    """
+    return self.error_message_format % values
 
 class HttpServer(http.HttpBase):
   """Generic HTTP server class
@@ -404,7 +427,8 @@ class HttpServer(http.HttpBase):
   MAX_CHILDREN = 20
 
   def __init__(self, mainloop, local_address, port,
-               ssl_params=None, ssl_verify_peer=False):
+               ssl_params=None, ssl_verify_peer=False,
+               request_executor_class=None):
     """Initializes the HTTP server
 
     @type mainloop: ganeti.daemon.Mainloop
@@ -416,12 +440,20 @@ class HttpServer(http.HttpBase):
     @type ssl_params: HttpSslParams
     @param ssl_params: SSL key and certificate
     @type ssl_verify_peer: bool
-    @param ssl_verify_peer: Whether to require client certificate and compare
-                            it with our certificate
+    @param ssl_verify_peer: Whether to require client certificate
+        and compare it with our certificate
+    @type request_executor_class: class
+    @param request_executor_class: an class derived from the
+        HttpServerRequestExecutor class
 
     """
     http.HttpBase.__init__(self)
 
+    if request_executor_class is None:
+      self.request_executor = HttpServerRequestExecutor
+    else:
+      self.request_executor = request_executor_class
+
     self.mainloop = mainloop
     self.local_address = local_address
     self.port = port
@@ -492,7 +524,7 @@ class HttpServer(http.HttpBase):
     if pid == 0:
       # Child process
       try:
-        _HttpServerRequestExecutor(self, connection, client_addr)
+        self.request_executor(self, connection, client_addr)
       except Exception:
         logging.exception("Error while handling request from %s:%s",
                           client_addr[0], client_addr[1])
@@ -501,6 +533,13 @@ class HttpServer(http.HttpBase):
     else:
       self._children.append(pid)
 
+  def PreHandleRequest(self, req):
+    """Called before handling a request.
+
+    Can be overriden by a subclass.
+
+    """
+
   def HandleRequest(self, req):
     """Handles a request.