Skip to content

Commit

Permalink
fix wsgi_xmlrpc for python3, add test for it
Browse files Browse the repository at this point in the history
  • Loading branch information
binux committed Mar 5, 2016
1 parent f1d7370 commit dd8562a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 15 deletions.
37 changes: 22 additions & 15 deletions pyspider/libs/wsgi_xmlrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Origin: https://code.google.com/p/wsgi-xmlrpc/


from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
from six.moves.xmlrpc_server import SimpleXMLRPCDispatcher
import logging

logger = logging.getLogger(__name__)


class WSGIXMLRPCApplication(object):
"""Application to handle requests to the XMLRPC service"""

Expand All @@ -33,24 +37,30 @@ def __init__(self, instance=None, methods=[]):
self.dispatcher.register_function(method)
self.dispatcher.register_introspection_functions()

def register_instance(self, instance):
return self.dispatcher.register_instance(instance)

def register_function(self, function, name=None):
return self.dispatcher.register_function(function, name)

def handler(self, environ, start_response):
"""XMLRPC service for windmill browser core to communicate with"""

if environ['REQUEST_METHOD'] == 'POST':
return self.handle_POST(environ, start_response)
else:
start_response("400 Bad request", [('Content-Type','text/plain')])
start_response("400 Bad request", [('Content-Type', 'text/plain')])
return ['']

def handle_POST(self, environ, start_response):
"""Handles the HTTP POST request.
Attempts to interpret all HTTP POST requests as XML-RPC calls,
which are forwarded to the server's _dispatch method for handling.
Most code taken from SimpleXMLRPCServer with modifications for wsgi and my custom dispatcher.
"""

try:
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
Expand All @@ -59,28 +69,25 @@ def handle_POST(self, environ, start_response):

length = int(environ['CONTENT_LENGTH'])
data = environ['wsgi.input'].read(length)

max_chunk_size = 10*1024*1024
size_remaining = length

# In previous versions of SimpleXMLRPCServer, _dispatch
# could be overridden in this class, instead of in
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
# check to see if a subclass implements _dispatch and
# check to see if a subclass implements _dispatch and
# using that method if present.
response = self.dispatcher._marshaled_dispatch(
data, getattr(self.dispatcher, '_dispatch', None)
)
response += '\n'
except: # This should only happen if the module is buggy
data, getattr(self.dispatcher, '_dispatch', None)
)
response += b'\n'
except Exception as e: # This should only happen if the module is buggy
# internal error, report as HTTP server error
logger.exception(e)
start_response("500 Server error", [('Content-Type', 'text/plain')])
return []
else:
# got a valid XML RPC response
start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)),)])
start_response("200 OK", [('Content-Type', 'text/xml'), ('Content-Length', str(len(response)),)])
return [response]


def __call__(self, environ, start_response):
return self.handler(environ, start_response)
56 changes: 56 additions & 0 deletions tests/test_xmlrpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) 2006-2007 Open Source Applications Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Origin: https://code.google.com/p/wsgi-xmlrpc/

import unittest2 as unittest
import tornado.wsgi
import tornado.ioloop
import tornado.httpserver
from pyspider.libs import utils

class TestXMLRPCServer(unittest.TestCase):
@classmethod
def setUpClass(self):
from pyspider.libs import wsgi_xmlrpc

def test_1():
return 'test_1'

class Test2(object):
def test_3(self, obj):
return obj

test = Test2()

application = wsgi_xmlrpc.WSGIXMLRPCApplication()
application.register_instance(Test2())
application.register_function(test_1)

container = tornado.wsgi.WSGIContainer(application)
http_server = tornado.httpserver.HTTPServer(container)
http_server.listen(3423)
utils.run_in_thread(tornado.ioloop.IOLoop.current().start)

@classmethod
def tearDownClass(self):
tornado.ioloop.IOLoop.current().stop()

def test_xmlrpc_server(self, uri='http://localhost:3423'):
from six.moves.xmlrpc_client import ServerProxy

client = ServerProxy(uri)

assert client.test_1() == 'test_1'
assert client.test_3({'asdf':4}) == {'asdf':4}

0 comments on commit dd8562a

Please sign in to comment.