diff --git a/bin/service/http_server.py b/bin/service/http_server.py index 76cf5b2fc91..74a0f572771 100644 --- a/bin/service/http_server.py +++ b/bin/service/http_server.py @@ -88,6 +88,12 @@ class SecureMultiHandler2(SecureMultiHTTPHandler): def log_message(self, format, *args): netsvc.Logger().notifyChannel('https',netsvc.LOG_DEBUG,format % args) + def getcert_fnames(self): + tc = tools.config + fcert = tc.get_misc('httpsd','sslcert', 'ssl/server.cert') + fkey = tc.get_misc('httpsd','sslkey', 'ssl/server.key') + return (fcert,fkey) + class HttpDaemon(threading.Thread, netsvc.Server): def __init__(self, interface, port): threading.Thread.__init__(self) @@ -141,6 +147,23 @@ class HttpSDaemon(threading.Thread, netsvc.Server): netsvc.Logger().notifyChannel('httpd-ssl', netsvc.LOG_CRITICAL, "Error occur when starting the server daemon: %s" % (e,)) raise + def attach(self, path, gw): + pass + + def stop(self): + self.running = False + if os.name != 'nt': + self.server.socket.shutdown( hasattr(socket, 'SHUT_RDWR') and socket.SHUT_RDWR or 2 ) + self.server.socket.close() + + def run(self): + #self.server.register_introspection_functions() + + self.running = True + while self.running: + self.server.handle_request() + return True + httpd = None httpsd = None @@ -175,7 +198,7 @@ def reg_http_service(hts, secure_only = False): return import SimpleXMLRPCServer -class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): +class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): rpc_paths = [] protocol_version = 'HTTP/1.1' def _dispatch(self, method, params): diff --git a/bin/service/websrv_lib.py b/bin/service/websrv_lib.py index 762cb9d8f2a..fe1db8f7bc9 100644 --- a/bin/service/websrv_lib.py +++ b/bin/service/websrv_lib.py @@ -146,7 +146,32 @@ class dummyconn: def shutdown(self, tru): pass -class MultiHTTPHandler(BaseHTTPRequestHandler): +def _quote_html(html): + return html.replace("&", "&").replace("<", "<").replace(">", ">") + +class FixSendError: + def send_error(self, code, message=None): + #overriden from BaseHTTPRequestHandler, we also send the content-length + try: + short, long = self.responses[code] + except KeyError: + short, long = '???', '???' + if message is None: + message = short + explain = long + self.log_error("code %d, message %s", code, message) + # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201) + content = (self.error_message_format % + {'code': code, 'message': _quote_html(message), 'explain': explain}) + self.send_response(code, message) + self.send_header("Content-Type", self.error_content_type) + self.send_header('Connection', 'close') + self.send_header('Content-Length', len(content) or 0) + self.end_headers() + if self.command != 'HEAD' and code >= 200 and code not in (204, 304): + self.wfile.write(content) + +class MultiHTTPHandler(FixSendError,BaseHTTPRequestHandler): """ this is a multiple handler, that will dispatch each request to a nested handler, iff it matches @@ -304,17 +329,32 @@ class MultiHTTPHandler(BaseHTTPRequestHandler): class SecureMultiHTTPHandler(MultiHTTPHandler): + def getcert_fnames(self): + """ Return a pair with the filenames of ssl cert,key + + Override this to direct to other filenames + """ + return ('server.cert','server.key') + def setup(self): import ssl + certfile, keyfile = self.getcert_fnames() self.connection = ssl.wrap_socket(self.request, server_side=True, - certfile="server.cert", - keyfile="server.key", + certfile=certfile, + keyfile=keyfile, ssl_version=ssl.PROTOCOL_SSLv23) self.rfile = self.connection.makefile('rb', self.rbufsize) self.wfile = self.connection.makefile('wb', self.wbufsize) self.log_message("Secure %s connection from %s",self.connection.cipher(),self.client_address) + def finish(self): + # With ssl connections, closing the filehandlers alone may not + # work because of ref counting. We explicitly tell the socket + # to shutdown. + MultiHTTPHandler.finish(self) + self.connection.shutdown(socket.SHUT_RDWR) + import threading class ConnThreadingMixIn: """Mix-in class to handle each _connection_ in a new thread.