diff --git a/trytond/netsvc.py b/trytond/netsvc.py index 947707e346..5f26746aa6 100644 --- a/trytond/netsvc.py +++ b/trytond/netsvc.py @@ -1,143 +1,14 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. -import time import threading -import SimpleXMLRPCServer, signal, sys, xmlrpclib import SocketServer import socket import logging import os -from pysocket import PySocket -import traceback -import select import BaseHTTPServer from trytond.protocols.sslsocket import SSLSocket from config import CONFIG -# convert decimal to float before marshalling: -from decimal import Decimal -xmlrpclib.Marshaller.dispatch[Decimal] = \ - lambda self, value, write: self.dump_long(float(value), write) - - -#-- XMLRPC Handler - -class GenericXMLRPCRequestHandler: - - def _dispatch(self, method, params): - host, port = self.client_address[:2] - logging.getLogger('web-service').info( - 'connection from %s:%d' % (host, port)) - try: - from protocols.dispatcher import dispatch - database_name, object_type, object_name = self.path.split("/")[-3:] - args = (database_name, params[0], params[1], object_type, - object_name, method) + params[2:] - res = dispatch(*args) - return res - except: - tb_s = '' - for line in traceback.format_exception(*sys.exc_info()): - try: - line = line.encode('utf-8', 'ignore') - except: - continue - tb_s += line - for path in sys.path: - tb_s = tb_s.replace(path, '') - if CONFIG['debug_mode']: - import pdb - traceb = sys.exc_info()[2] - pdb.post_mortem(traceb) - raise xmlrpclib.Fault(1, str(sys.exc_value) + '\n' + tb_s) - - -class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, - SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): - rpc_paths = None - - -class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): - - def setup(self): - self.connection = SSLSocket(self.request) - self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) - self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) - -#-- XMLRPC Server - -class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, - SimpleXMLRPCServer.SimpleXMLRPCServer): - - def server_bind(self): - self.socket.setsockopt(socket.SOL_SOCKET, - socket.SO_REUSEADDR, 1) - SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self) - - -class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer): - - def __init__(self, server_address, HandlerClass, logRequests=1): - SimpleThreadedXMLRPCServer.__init__(self, server_address, HandlerClass, - logRequests) - self.socket = SSLSocket(socket.socket(self.address_family, - self.socket_type)) - self.server_bind() - self.server_activate() - - -#-- HTPP Daemon - -class HttpDaemon(threading.Thread): - - def __init__(self, interface, port, secure=False): - threading.Thread.__init__(self) - self.secure = secure - self.running = False - ipv6 = False - if socket.has_ipv6: - try: - socket.getaddrinfo(interface or None, port, socket.AF_INET6) - ipv6 = True - except: - pass - if secure: - handler_class = SecureXMLRPCRequestHandler - server_class = SecureThreadedXMLRPCServer - if ipv6: - server_class = SecureThreadedXMLRPCServer6 - else: - handler_class = SimpleXMLRPCRequestHandler - server_class = SimpleThreadedXMLRPCServer - if ipv6: - server_class = SimpleThreadedXMLRPCServer6 - self.server = server_class((interface, port), handler_class, 0) - - def stop(self): - self.running = False - if os.name != 'nt': - if hasattr(socket, 'SHUT_RDWR'): - self.server.socket.shutdown(socket.SHUT_RDWR) - else: - self.server.socket.shutdown(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 - - # If the server need to be run recursively - # - #signal.signal(signal.SIGALRM, self.my_handler) - #signal.alarm(6) - #while True: - # self.server.handle_request() - #signal.alarm(0) # Disable the alarm - #-- WebDAV server @@ -205,23 +76,12 @@ class WebDAVServerThread(threading.Thread): self.server.handle_request() return True -#-- MixIn classes -- - -class IPv6MixIn(object): - address_family = socket.AF_INET6 - #--- IPv6 Servers -class BaseThreadedHTTPServer6(BaseThreadedHTTPServer, IPv6MixIn): - pass -class SecureThreadedHTTPServer6(SecureThreadedHTTPServer, IPv6MixIn): - pass -class SimpleThreadedXMLRPCServer6(SimpleThreadedXMLRPCServer, IPv6MixIn): - pass +class BaseThreadedHTTPServer6(BaseThreadedHTTPServer): + address_family = socket.AF_INET6 #--- Secure IPv6 Servers -class SecureThreadedXMLRPCServer6(SecureThreadedXMLRPCServer, IPv6MixIn): - pass -class SecureThreadedHTTPServer6(SecureThreadedHTTPServer, IPv6MixIn): - pass +class SecureThreadedHTTPServer6(SecureThreadedHTTPServer): + address_family = socket.AF_INET6 diff --git a/trytond/protocols/xmlrpc.py b/trytond/protocols/xmlrpc.py new file mode 100644 index 0000000000..fae1044658 --- /dev/null +++ b/trytond/protocols/xmlrpc.py @@ -0,0 +1,131 @@ +#This file is part of Tryton. The COPYRIGHT file at the top level of +#this repository contains the full copyright notices and license terms. +from trytond.protocols.sslsocket import SSLSocket +from trytond.protocols.dispatcher import dispatch +from trytond.config import CONFIG +import SimpleXMLRPCServer +import SocketServer +import xmlrpclib +import threading +import traceback +import socket +import sys +import logging +import os + +# convert decimal to float before marshalling: +from decimal import Decimal +xmlrpclib.Marshaller.dispatch[Decimal] = \ + lambda self, value, write: self.dump_long(float(value), write) + + +class GenericXMLRPCRequestHandler: + + def _dispatch(self, method, params): + host, port = self.client_address[:2] + logging.getLogger('xmlrpc').info('connection from %s:%d' % (host, port)) + try: + database_name, object_type, object_name = self.path.split("/")[-3:] + args = (database_name, params[0], params[1], object_type, + object_name, method) + params[2:] + res = dispatch(*args) + return res + except: + tb_s = '' + for line in traceback.format_exception(*sys.exc_info()): + try: + line = line.encode('utf-8', 'ignore') + except: + continue + tb_s += line + for path in sys.path: + tb_s = tb_s.replace(path, '') + if CONFIG['debug_mode']: + import pdb + traceb = sys.exc_info()[2] + pdb.post_mortem(traceb) + raise xmlrpclib.Fault(1, str(sys.exc_value) + '\n' + tb_s) + + +class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, + SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): + rpc_paths = None + + +class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): + + def setup(self): + self.connection = SSLSocket(self.request) + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + + +class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, + SimpleXMLRPCServer.SimpleXMLRPCServer): + + def server_bind(self): + self.socket.setsockopt(socket.SOL_SOCKET, + socket.SO_REUSEADDR, 1) + SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self) + + +class SimpleThreadedXMLRPCServer6(SimpleThreadedXMLRPCServer): + address_family = socket.AF_INET6 + + +class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer): + + def __init__(self, server_address, HandlerClass, logRequests=1): + SimpleThreadedXMLRPCServer.__init__(self, server_address, HandlerClass, + logRequests) + self.socket = SSLSocket(socket.socket(self.address_family, + self.socket_type)) + self.server_bind() + self.server_activate() + + +class SecureThreadedXMLRPCServer6(SecureThreadedXMLRPCServer): + address_family = socket.AF_INET6 + + +class HttpDaemon(threading.Thread): + + def __init__(self, interface, port, secure=False): + threading.Thread.__init__(self) + self.secure = secure + self.running = False + ipv6 = False + if socket.has_ipv6: + try: + socket.getaddrinfo(interface or None, port, socket.AF_INET6) + ipv6 = True + except: + pass + if secure: + handler_class = SecureXMLRPCRequestHandler + server_class = SecureThreadedXMLRPCServer + if ipv6: + server_class = SecureThreadedXMLRPCServer6 + else: + handler_class = SimpleXMLRPCRequestHandler + server_class = SimpleThreadedXMLRPCServer + if ipv6: + server_class = SimpleThreadedXMLRPCServer6 + self.server = server_class((interface, port), handler_class, 0) + + def stop(self): + self.running = False + if os.name != 'nt': + if hasattr(socket, 'SHUT_RDWR'): + self.server.socket.shutdown(socket.SHUT_RDWR) + else: + self.server.socket.shutdown(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 diff --git a/trytond/server.py b/trytond/server.py index aa166a8b7f..e4c0e4893c 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -141,7 +141,8 @@ class TrytonServer(object): # Launch Server if CONFIG['xmlrpc']: - httpd = netsvc.HttpDaemon(CONFIG['interface'], CONFIG['xmlport'], + from trytond.protocols.xmlrpc import HttpDaemon + httpd = HttpDaemon(CONFIG['interface'], CONFIG['xmlport'], CONFIG['secure_xmlrpc']) self.logger.info("starting XML-RPC%s protocol, port %d" % \ (CONFIG['secure_xmlrpc'] and ' Secure' or '',