diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py
index 62e1585dade..9a7dbbee225 100644
--- a/openerp/service/__init__.py
+++ b/openerp/service/__init__.py
@@ -57,7 +57,6 @@ def start_services():
# Initialize the HTTP stack.
#http_server.init_servers()
- #http_server.init_xmlrpc()
#http_server.init_static_http()
netrpc_server.init_servers()
diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py
index 9bfb9397d19..63bd991ee35 100644
--- a/openerp/service/http_server.py
+++ b/openerp/service/http_server.py
@@ -64,53 +64,6 @@ try:
except ImportError:
class SSLError(Exception): pass
-class ThreadedHTTPServer(ConnThreadingMixIn, SimpleXMLRPCDispatcher, HTTPServer):
- """ A threaded httpd server, with all the necessary functionality for us.
-
- It also inherits the xml-rpc dispatcher, so that some xml-rpc functions
- will be available to the request handler
- """
- encoding = None
- allow_none = False
- allow_reuse_address = 1
- _send_traceback_header = False
- i = 0
-
- def __init__(self, addr, requestHandler, proto='http',
- logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
- self.logRequests = logRequests
-
- SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
- HTTPServer.__init__(self, addr, requestHandler)
-
- self.numThreads = 0
- self.proto = proto
- self.__threadno = 0
-
- # [Bug #1222790] If possible, set close-on-exec flag; if a
- # method spawns a subprocess, the subprocess shouldn't have
- # the listening socket open.
- if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
- flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
- flags |= fcntl.FD_CLOEXEC
- fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
-
- def handle_error(self, request, client_address):
- """ Override the error handler
- """
-
- logging.getLogger("init").exception("Server error in request from %s:" % (client_address,))
-
- def _mark_start(self, thread):
- self.numThreads += 1
-
- def _mark_end(self, thread):
- self.numThreads -= 1
-
-
- def _get_next_name(self):
- self.__threadno += 1
- return 'http-client-%d' % self.__threadno
class HttpLogHandler:
""" helper class for uniform log handling
Please define self._logger at each class that is derived from this
@@ -129,136 +82,6 @@ class HttpLogHandler:
def log_request(self, code='-', size='-'):
self._logger.log(netsvc.logging.DEBUG_RPC, '"%s" %s %s',
self.requestline, str(code), str(size))
-
-class MultiHandler2(HttpLogHandler, MultiHTTPHandler):
- _logger = logging.getLogger('http')
-
-
-class SecureMultiHandler2(HttpLogHandler, SecureMultiHTTPHandler):
- _logger = logging.getLogger('https')
-
- def getcert_fnames(self):
- tc = tools.config
- fcert = tc.get('secure_cert_file', 'server.cert')
- fkey = tc.get('secure_pkey_file', 'server.key')
- return (fcert,fkey)
-
-class BaseHttpDaemon(threading.Thread, netsvc.Server):
- _RealProto = '??'
-
- def __init__(self, interface, port, handler):
- threading.Thread.__init__(self, name='%sDaemon-%d'%(self._RealProto, port))
- netsvc.Server.__init__(self)
- self.__port = port
- self.__interface = interface
-
- try:
- self.server = ThreadedHTTPServer((interface, port), handler, proto=self._RealProto)
- self.server.logRequests = True
- self.server.timeout = self._busywait_timeout
- logging.getLogger("web-services").info(
- "starting %s service at %s port %d" %
- (self._RealProto, interface or '0.0.0.0', port,))
- except Exception, e:
- logging.getLogger("httpd").exception("Error occured when starting the server daemon.")
- raise
-
- @property
- def socket(self):
- return self.server.socket
-
- def attach(self, path, gw):
- pass
-
- def stop(self):
- self.running = False
- self._close_socket()
-
- def run(self):
- self.running = True
- while self.running:
- try:
- self.server.handle_request()
- except (socket.error, select.error), e:
- if self.running or e.args[0] != errno.EBADF:
- raise
- return True
-
- def stats(self):
- res = "%sd: " % self._RealProto + ((self.running and "running") or "stopped")
- if self.server:
- res += ", %d threads" % (self.server.numThreads,)
- return res
-
-# No need for these two classes: init_server() below can initialize correctly
-# directly the BaseHttpDaemon class.
-class HttpDaemon(BaseHttpDaemon):
- _RealProto = 'HTTP'
- def __init__(self, interface, port):
- super(HttpDaemon, self).__init__(interface, port,
- handler=MultiHandler2)
-
-class HttpSDaemon(BaseHttpDaemon):
- _RealProto = 'HTTPS'
- def __init__(self, interface, port):
- try:
- super(HttpSDaemon, self).__init__(interface, port,
- handler=SecureMultiHandler2)
- except SSLError, e:
- logging.getLogger('httpsd').exception( \
- "Can not load the certificate and/or the private key files")
- raise
-
-httpd = None
-httpsd = None
-
-def init_servers():
- global httpd, httpsd
- if tools.config.get('xmlrpc'):
- httpd = HttpDaemon(tools.config.get('xmlrpc_interface', ''),
- int(tools.config.get('xmlrpc_port', 8069)))
-
- if tools.config.get('xmlrpcs'):
- httpsd = HttpSDaemon(tools.config.get('xmlrpcs_interface', ''),
- int(tools.config.get('xmlrpcs_port', 8071)))
-
-import SimpleXMLRPCServer
-class XMLRPCRequestHandler(FixSendError,HttpLogHandler,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- rpc_paths = []
- protocol_version = 'HTTP/1.1'
- _logger = logging.getLogger('xmlrpc')
-
- def _dispatch(self, method, params):
- try:
- service_name = self.path.split("/")[-1]
- auth = getattr(self, 'auth_provider', None)
- return netsvc.dispatch_rpc(service_name, method, params, auth)
- except netsvc.OpenERPDispatcherException, e:
- raise xmlrpclib.Fault(tools.exception_to_unicode(e.exception), e.traceback)
-
- def handle(self):
- pass
-
- def finish(self):
- pass
-
- def setup(self):
- self.connection = dummyconn()
- self.rpc_paths = map(lambda s: '/%s' % s, netsvc.ExportService._services.keys())
-
-
-def init_xmlrpc():
- if tools.config.get('xmlrpc', False):
- # Example of http file serving:
- # reg_http_service('/test/', HTTPHandler)
- reg_http_service('/xmlrpc/', XMLRPCRequestHandler)
- logging.getLogger("web-services").info("Registered XML-RPC over HTTP")
-
- if tools.config.get('xmlrpcs', False) \
- and not tools.config.get('xmlrpc', False):
- # only register at the secure server
- reg_http_service('/xmlrpc/', XMLRPCRequestHandler, secure_only=True)
- logging.getLogger("web-services").info("Registered XML-RPC over HTTPS only")
class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler):
_logger = logging.getLogger('httpd')
diff --git a/openerp/service/websrv_lib.py b/openerp/service/websrv_lib.py
index 1efab672eb3..3df441458fd 100644
--- a/openerp/service/websrv_lib.py
+++ b/openerp/service/websrv_lib.py
@@ -232,305 +232,3 @@ class HttpOptions:
"""
return opts
-class MultiHTTPHandler(FixSendError, HttpOptions, BaseHTTPRequestHandler):
- """ this is a multiple handler, that will dispatch each request
- to a nested handler, iff it matches
-
- The handler will also have *one* dict of authentication proxies,
- groupped by their realm.
- """
-
- protocol_version = "HTTP/1.1"
- default_request_version = "HTTP/0.9" # compatibility with py2.5
-
- auth_required_msg = """
Authorization required
- You must authenticate to use this service\r\r"""
-
- def __init__(self, request, client_address, server):
- self.in_handlers = {}
- SocketServer.StreamRequestHandler.__init__(self,request,client_address,server)
- self.log_message("MultiHttpHandler init for %s" %(str(client_address)))
-
- def _handle_one_foreign(self, fore, path):
- """ This method overrides the handle_one_request for *children*
- handlers. It is required, since the first line should not be
- read again..
-
- """
- fore.raw_requestline = "%s %s %s\n" % (self.command, path, self.version)
- if not fore.parse_request(): # An error code has been sent, just exit
- return
- if fore.headers.status:
- self.log_error("Parse error at headers: %s", fore.headers.status)
- self.close_connection = 1
- self.send_error(400,"Parse error at HTTP headers")
- return
-
- self.request_version = fore.request_version
- if hasattr(fore, 'auth_provider'):
- try:
- fore.auth_provider.checkRequest(fore,path)
- except AuthRequiredExc,ae:
- # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the
- # authorisation features of HTTP/1.1
- if self.request_version != 'HTTP/1.1' and ('Darwin/9.' not in fore.headers.get('User-Agent', '')):
- self.log_error("Cannot require auth at %s", self.request_version)
- self.send_error(403)
- return
- self._get_ignore_body(fore) # consume any body that came, not loose sync with input
- self.send_response(401,'Authorization required')
- self.send_header('WWW-Authenticate','%s realm="%s"' % (ae.atype,ae.realm))
- self.send_header('Connection', 'keep-alive')
- self.send_header('Content-Type','text/html')
- self.send_header('Content-Length',len(self.auth_required_msg))
- self.end_headers()
- self.wfile.write(self.auth_required_msg)
- return
- except AuthRejectedExc,e:
- self.log_error("Rejected auth: %s" % e.args[0])
- self.send_error(403,e.args[0])
- self.close_connection = 1
- return
- mname = 'do_' + fore.command
- if not hasattr(fore, mname):
- if fore.command == 'OPTIONS':
- self.do_OPTIONS()
- return
- self.send_error(501, "Unsupported method (%r)" % fore.command)
- return
- fore.close_connection = 0
- method = getattr(fore, mname)
- try:
- method()
- except (AuthRejectedExc, AuthRequiredExc):
- raise
- except Exception, e:
- if hasattr(self, 'log_exception'):
- self.log_exception("Could not run %s", mname)
- else:
- self.log_error("Could not run %s: %s", mname, e)
- self.send_error(500, "Internal error")
- # may not work if method has already sent data
- fore.close_connection = 1
- self.close_connection = 1
- if hasattr(fore, '_flush'):
- fore._flush()
- return
-
- if fore.close_connection:
- # print "Closing connection because of handler"
- self.close_connection = fore.close_connection
- if hasattr(fore, '_flush'):
- fore._flush()
-
-
- def parse_rawline(self):
- """Parse a request (internal).
-
- The request should be stored in self.raw_requestline; the results
- are in self.command, self.path, self.request_version and
- self.headers.
-
- Return True for success, False for failure; on failure, an
- error is sent back.
-
- """
- self.command = None # set in case of error on the first line
- self.request_version = version = self.default_request_version
- self.close_connection = 1
- requestline = self.raw_requestline
- if requestline[-2:] == '\r\n':
- requestline = requestline[:-2]
- elif requestline[-1:] == '\n':
- requestline = requestline[:-1]
- self.requestline = requestline
- words = requestline.split()
- if len(words) == 3:
- [command, path, version] = words
- if version[:5] != 'HTTP/':
- self.send_error(400, "Bad request version (%r)" % version)
- return False
- try:
- base_version_number = version.split('/', 1)[1]
- version_number = base_version_number.split(".")
- # RFC 2145 section 3.1 says there can be only one "." and
- # - major and minor numbers MUST be treated as
- # separate integers;
- # - HTTP/2.4 is a lower version than HTTP/2.13, which in
- # turn is lower than HTTP/12.3;
- # - Leading zeros MUST be ignored by recipients.
- if len(version_number) != 2:
- raise ValueError
- version_number = int(version_number[0]), int(version_number[1])
- except (ValueError, IndexError):
- self.send_error(400, "Bad request version (%r)" % version)
- return False
- if version_number >= (1, 1):
- self.close_connection = 0
- if version_number >= (2, 0):
- self.send_error(505,
- "Invalid HTTP Version (%s)" % base_version_number)
- return False
- elif len(words) == 2:
- [command, path] = words
- self.close_connection = 1
- if command != 'GET':
- self.log_error("Junk http request: %s", self.raw_requestline)
- self.send_error(400,
- "Bad HTTP/0.9 request type (%r)" % command)
- return False
- elif not words:
- return False
- else:
- #self.send_error(400, "Bad request syntax (%r)" % requestline)
- return False
- self.request_version = version
- self.command, self.path, self.version = command, path, version
- return True
-
- def handle_one_request(self):
- """Handle a single HTTP request.
- Dispatch to the correct handler.
- """
- self.request.setblocking(True)
- self.raw_requestline = self.rfile.readline()
- if not self.raw_requestline:
- self.close_connection = 1
- # self.log_message("no requestline, connection closed?")
- return
- if not self.parse_rawline():
- self.log_message("Could not parse rawline.")
- return
- # self.parse_request(): # Do NOT parse here. the first line should be the only
-
- if self.path == '*' and self.command == 'OPTIONS':
- # special handling of path='*', must not use any vdir at all.
- if not self.parse_request():
- return
- self.do_OPTIONS()
- return
- vdir = find_http_service(self.path, self.server.proto == 'HTTPS')
- if vdir:
- p = vdir.path
- npath = self.path[len(p):]
- if not npath.startswith('/'):
- npath = '/' + npath
-
- if not self.in_handlers.has_key(p):
- self.in_handlers[p] = vdir.instanciate_handler(noconnection(self.request),self.client_address,self.server)
- hnd = self.in_handlers[p]
- hnd.rfile = self.rfile
- hnd.wfile = self.wfile
- self.rlpath = self.raw_requestline
- try:
- self._handle_one_foreign(hnd, npath)
- except IOError, e:
- if e.errno == errno.EPIPE:
- self.log_message("Could not complete request %s," \
- "client closed connection", self.rlpath.rstrip())
- else:
- raise
- else: # no match:
- self.send_error(404, "Path not found: %s" % self.path)
-
- def _get_ignore_body(self,fore):
- if not fore.headers.has_key("content-length"):
- return
- max_chunk_size = 10*1024*1024
- size_remaining = int(fore.headers["content-length"])
- got = ''
- while size_remaining:
- chunk_size = min(size_remaining, max_chunk_size)
- got = fore.rfile.read(chunk_size)
- size_remaining -= len(got)
-
-
-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()
- try:
- self.connection = ssl.wrap_socket(self.request,
- server_side=True,
- 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)
- except Exception:
- self.request.shutdown(socket.SHUT_RDWR)
- raise
-
- 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)
- try:
- self.connection.shutdown(socket.SHUT_RDWR)
- except Exception:
- pass
-
-import threading
-class ConnThreadingMixIn:
- """Mix-in class to handle each _connection_ in a new thread.
-
- This is necessary for persistent connections, where multiple
- requests should be handled synchronously at each connection, but
- multiple connections can run in parallel.
- """
-
- # Decides how threads will act upon termination of the
- # main process
- daemon_threads = False
-
- def _get_next_name(self):
- return None
-
- def _handle_request_noblock(self):
- """Start a new thread to process the request."""
- if not threading: # happens while quitting python
- return
- t = threading.Thread(name=self._get_next_name(), target=self._handle_request2)
- if self.daemon_threads:
- t.setDaemon (1)
- t.start()
-
- def _mark_start(self, thread):
- """ Mark the start of a request thread """
- pass
-
- def _mark_end(self, thread):
- """ Mark the end of a request thread """
- pass
-
- def _handle_request2(self):
- """Handle one request, without blocking.
-
- I assume that select.select has returned that the socket is
- readable before this function was called, so there should be
- no risk of blocking in get_request().
- """
- try:
- self._mark_start(threading.currentThread())
- request, client_address = self.get_request()
- if self.verify_request(request, client_address):
- try:
- self.process_request(request, client_address)
- except Exception:
- self.handle_error(request, client_address)
- self.close_request(request)
- except socket.error:
- return
- finally:
- self._mark_end(threading.currentThread())
-
-#eof