Last Comment Bug 455721 - xmlrpc faultcode should be integer
: xmlrpc faultcode should be integer
Status: RESOLVED FIXED
:
Product: Testopia
Classification: Server Software
Component: API (show other bugs)
: unspecified
: x86 Linux
: -- normal (vote)
: ---
Assigned To: Greg Hendricks
:
:
Mentors:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2008-09-17 09:33 PDT by Nathan Parrish
Modified: 2009-08-19 12:53 PDT (History)
2 users (show)
See Also:
QA Whiteboard:
Iteration: ---
Points: ---


Attachments
wireshark trace of string and int faultcodes in xmlrpc responses (5.91 KB, application/octet-stream)
2008-09-17 09:36 PDT, Nathan Parrish
no flags Details
Patch for Bug 455721, same as Bugzilla project ones (817 bytes, patch)
2009-04-02 05:58 PDT, nuabaranda
no flags Details | Diff | Splinter Review

Description Nathan Parrish 2008-09-17 09:33:51 PDT
User-Agent:       Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.10) Gecko/20071128 Fedora/2.0.0.10-2.fc7 Firefox/2.0.0.10
Build Identifier: Testopia 2.1

in some cases, testopia xmlrpc server is returning a string faultcode instead of an integer, which blows up some xmlrpc client libraries, consequently making error handling nigh impossible.  

in a network trace I will attach, we see that when TestRun.create is fed an additional parameter 'bogusness', it sets the faultCode to the string 'Server', which causes the xmlrpc library (apache xmlrpc v3) to puke with 'java.lang.ClassCastException: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer'.
however, if I instead feed the arguments meant for TestCaseRun.create to TestRun.create, the faultCode is properly set to integer -32000, and the xmlrpc library happily raises an XmlRpcException with the faultString.  




Reproducible: Always

Steps to Reproduce:
- using sun java 1.6.0
- xmlrpc v3 library
- actually calling methods with jython 2.2
>>> import org.apache.commons.httpclient.HttpClient
>>> import org.apache.commons.httpclient.HttpState
>>> import org.apache.xmlrpc.client.XmlRpcClient
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransport
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory
>>> 
>>> import java.net.URL
>>> import java.util
>>> 
>>> client = org.apache.xmlrpc.client.XmlRpcClient()
>>> httpClient = org.apache.commons.httpclient.HttpClient()
>>> factory = org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory(client)
>>> 
>>> factory.setHttpClient(httpClient)
>>> client.setTransportFactory(factory)
>>> client.config.setServerURL(java.net.URL("http://bugstest/tr_xmlrpc.cgi"))
>>> 
>>> login = java.util.Hashtable();
>>> login.put("login","automator@sproutsys.com")
>>> login.put("password","automator")
>>> params = java.util.Vector()
>>> params.add(login)
1
>>> user_id = client.execute("User.login", params)
>>> query = java.util.Hashtable();
>>> query.put("run_id", 945);
>>> query.put("case_id", 767);
>>> query.put("build", 1);
>>> query.put("environment", 1);
>>> query.put("case_text_version", 1);
>>> query.put("environment", 1);
1
>>> params = java.util.Vector()
>>> params.add(query)
1
>>> result = client.execute("TestRun.create", params)
Traceback (innermost last):
  File "<console>", line 1, in ?
    Bugzilla::Testopia::TestPlan::new function.
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.readResponse(XmlRpcStreamTransport.java:186)
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:145)
        at org.apache.xmlrpc.client.XmlRpcHttpTransport.sendRequest(XmlRpcHttpTransport.java:94)
        at org.apache.xmlrpc.client.XmlRpcClientWorker.execute(XmlRpcClientWorker.java:53)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:166)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:157)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:146)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:623)

org.apache.xmlrpc.XmlRpcException: org.apache.xmlrpc.XmlRpcException: Bad argument param sent to
    Bugzilla::Testopia::TestPlan::new function.
>>> 




Actual Results:  
>>> import org.apache.commons.httpclient.HttpClient
>>> import org.apache.commons.httpclient.HttpState
>>> import org.apache.xmlrpc.client.XmlRpcClient
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransport
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory
>>> 
>>> import java.net.URL
>>> import java.util
>>> 
>>> client = org.apache.xmlrpc.client.XmlRpcClient()
>>> httpClient = org.apache.commons.httpclient.HttpClient()
>>> factory = org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory(client)
>>> 
>>> factory.setHttpClient(httpClient)
>>> client.setTransportFactory(factory)
>>> client.config.setServerURL(java.net.URL("http://bugstest/tr_xmlrpc.cgi"))
>>> 
>>> login = java.util.Hashtable();
>>> login.put("login","automator@sproutsys.com")
>>> login.put("password","automator")
>>> params = java.util.Vector()
>>> params.add(login)
1
>>> query = java.util.Hashtable();
>>> query.put("run_id", 945);
>>> query.put("case_id", 767);
>>> query.put("build_id", 1);
>>> query.put("environment_id", 1);
>>> # query.put("case_text_version_id", 1);
>>> params = java.util.Vector()
>>> params.add(query)
1
>>> result = client.execute("TestCaseRun.create", params)
Traceback (innermost last):
  File "<console>", line 1, in ?
        at org.apache.xmlrpc.parser.XmlRpcResponseParser.addResult(XmlRpcResponseParser.java:58)
        at org.apache.xmlrpc.parser.RecursiveTypeParserImpl.endValueTag(RecursiveTypeParserImpl.java:71)
        at org.apache.xmlrpc.parser.XmlRpcResponseParser.endElement(XmlRpcResponseParser.java:183)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:605)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1749)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2900)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:624)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:485)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:811)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:741)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:111)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1209)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:526)
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.readResponse(XmlRpcStreamTransport.java:175)
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:145)
        at org.apache.xmlrpc.client.XmlRpcHttpTransport.sendRequest(XmlRpcHttpTransport.java:94)
        at org.apache.xmlrpc.client.XmlRpcClientWorker.execute(XmlRpcClientWorker.java:53)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:166)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:157)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:146)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:623)

java.lang.ClassCastException: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
>>> 


Expected Results:  
>>> import org.apache.commons.httpclient.HttpClient
>>> import org.apache.commons.httpclient.HttpState
>>> import org.apache.xmlrpc.client.XmlRpcClient
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransport
>>> import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory
>>> 
>>> import java.net.URL
>>> import java.util
>>> 
>>> client = org.apache.xmlrpc.client.XmlRpcClient()
>>> httpClient = org.apache.commons.httpclient.HttpClient()
>>> factory = org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory(client)
>>> 
>>> factory.setHttpClient(httpClient)
>>> client.setTransportFactory(factory)
>>> client.config.setServerURL(java.net.URL("http://bugstest/tr_xmlrpc.cgi"))
>>> 
>>> login = java.util.Hashtable();
>>> login.put("login","automator@sproutsys.com")
>>> login.put("password","automator")
>>> params = java.util.Vector()
>>> params.add(login)
1
>>> query = java.util.Hashtable();
>>> query.put("run_id", 945);
>>> query.put("case_id", 767);
>>> query.put("build_id", 1);
>>> query.put("environment_id", 1);
>>> query.put("case_text_version", 1);
>>> params = java.util.Vector()
>>> params.add(query)
1
>>> result = client.execute("TestRun.create", params)
Traceback (innermost last):
  File "<console>", line 1, in ?
    Bugzilla::Testopia::TestPlan::new function.
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.readResponse(XmlRpcStreamTransport.java:186)
        at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:145)
        at org.apache.xmlrpc.client.XmlRpcHttpTransport.sendRequest(XmlRpcHttpTransport.java:94)
        at org.apache.xmlrpc.client.XmlRpcClientWorker.execute(XmlRpcClientWorker.java:53)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:166)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:157)
        at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:146)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:623)

org.apache.xmlrpc.XmlRpcException: org.apache.xmlrpc.XmlRpcException: Bad argument param sent to
    Bugzilla::Testopia::TestPlan::new function.
>>>
Comment 1 Nathan Parrish 2008-09-17 09:36:05 PDT
Created attachment 339071 [details]
wireshark trace of string and int faultcodes in xmlrpc responses

packet 9 is the invalid string fault code, packet 21 is the proper int fault code.
Comment 2 Nathan Parrish 2008-09-23 17:16:15 PDT
DBD::Pg::db selectcol_arrayref failed: ERROR:  invalid input syntax for integer: "nada"
 [for Statement "SELECT DISTINCT test_cases.case_id FROM test_cases  INNER JOIN test_case_plans AS case_plans ON (test_cases.case_id = case_plans.case_id) INNER JOIN test_plans ON (case_plans.plan_id = test_plans.plan_id) WHERE ((test_plans.plan_id = 'nada') AND (test_cases.isautomated IN ('1')) AND (test_cases.case_status_id IN ('2')))"] at /var/www/virts/bugs/Bugzilla/Testopia/Table.pm line 118
Bugzilla::Testopia::Table::init('Bugzilla::Testopia::Table=HASH(0x7f3133392f08)', 'case', 'tr_xmlrpc.cgi', 'Bugzilla::CGI=HASH(0x7f31331efbe8)', undef, 'SELECT DISTINCT test_cases.case_id FROM test_cases  INNER JOI...') called at /var/www/virts/bugs/Bugzilla/Testopia/Table.pm line 88
Bugzilla::Testopia::Table::new('Bugzilla::Testopia::Table', 'case', 'tr_xmlrpc.cgi', 'Bugzilla::CGI=HASH(0x7f31331efbe8)', undef, 'SELECT DISTINCT test_cases.case_id FROM test_cases  INNER JOI...') called at /var/www/virts/bugs/Bugzilla/WebService/Testopia/TestCase.pm line 71
Bugzilla::WebService::Testopia::TestCase::list('Bugzilla::WebService::Testopia::TestCase', 'HASH(0x7f31331c9b98)') called at /usr/lib/perl5/vendor_perl/5.10.0/SOAP/Lite.pm line 2559
eval {...} called at /usr/lib/perl5/vendor_perl/5.10.0/SOAP/Lite.pm line 2547
eval {...} called at /usr/lib/perl5/vendor_perl/5.10.0/SOAP/Lite.pm line 2516
SOAP::Server::handle('Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI=HASH(0x7f3...', '&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;methodCall&gt;&lt;methodName...') called at /usr/lib/perl5/vendor_perl/5.10.0/SOAP/Transport/HTTP.pm line 327
SOAP::Transport::HTTP::Server::handle('Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI=HASH(0x7f3...') called at /usr/lib/perl5/vendor_perl/5.10.0/SOAP/Transport/HTTP.pm line 423
SOAP::Transport::HTTP::CGI::handle('Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI=HASH(0x7f3...') called at /var/www/virts/bugs/tr_xmlrpc.cgi line 39
ModPerl::ROOT::Bugzilla::ModPerl::ResponseHandler::var_www_virts_bugs_tr_xmlrpc_2ecgi::handler('Apache2::RequestRec=SCALAR(0x7f312f264b68)') called at /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/ModPerl/RegistryCooker.pm line 204
eval {...} called at /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/ModPerl/RegistryCooker.pm line 204
ModPerl::RegistryCooker::run('Bugzilla::ModPerl::ResponseHandler=HASH(0x7f3132b069b0)') called at /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/ModPerl/RegistryCooker.pm line 170
ModPerl::RegistryCooker::default_handler('Bugzilla::ModPerl::ResponseHandler=HASH(0x7f3132b069b0)') called at /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi/ModPerl/Registry.pm line 31
ModPerl::Registry::handler('Bugzilla::ModPerl::ResponseHandler', 'Apache2::RequestRec=SCALAR(0x7f312f264b68)') called at /var/www/virts/bugs/mod_perl.pl line 96
Bugzilla::ModPerl::ResponseHandler::handler('Bugzilla::ModPerl::ResponseHandler', 'Apache2::RequestRec=SCALAR(0x7f312f264b68)') called at -e line 0
eval {...} called at -e line 0

I think the problem is something stupid in SOAP::Lite, around line 2575
    # let application errors pass through with 'Server' code
    die ref $@ ?
      $@ : $@ =~ /^Can\'t locate object method "$method_name"/ ?
        "Failed to locate method ($method_name) in class ($class)" :
          SOAP::Fault->faultcode($SOAP::Constants::FAULT_SERVER)->faultstring($@)

elsewhere in Lite.pm:
  $FAULT_SERVER           = 'Server';
Comment 3 Nathan Parrish 2008-09-24 11:48:06 PDT
filed http://sourceforge.net/tracker/index.php?func=detail&aid=2126937&group_id=66000&atid=513017 on the SOAP::Lite project at SF.
Comment 4 Nathan Parrish 2008-09-24 12:12:47 PDT
hardcoding Lite.pm to return 32000 instead of FAULT_SERVER gets me happy little xmlrpc exceptions instead of java cast exceptions:
SOAP::Fault->faultcode(32000)->faultstring($@)
Comment 5 nuabaranda 2009-03-30 08:49:46 PDT
+1

Bugzilla assures numeric error codes here:

http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService.html#ERRORS
Comment 6 Brian Baker 2009-03-30 19:10:09 PDT
I'm running in to this same issue when using the XML-RPC.NET library from C#.
http://www.xml-rpc.net/
Comment 7 nuabaranda 2009-03-31 05:02:49 PDT
The XML-RPC spec at http://www.xmlrpc.com/spec defines only integer fault codes. But the XML-RPC implementation in the used Perl module XMLRPC::Lite which is part of SOAP::lite and uses its fault constants violates this. There is a bug for this filed at https://sourceforge.net/tracker/?func=detail&aid=2126937&group_id=66000&atid=513017 .
Comment 8 nuabaranda 2009-04-02 05:58:38 PDT
Created attachment 370629 [details] [diff] [review]
Patch for Bug 455721, same as Bugzilla project ones
Comment 9 nuabaranda 2009-04-02 05:59:30 PDT
This SOAP::Lite bug was fixed in Bugzilla by a workaround in xmlrpc.cgi. See the attached patch file https://bugzilla.mozilla.org/attachment.cgi?id=370629.
Comment 10 Greg Hendricks 2009-08-19 12:53:30 PDT
This is now fixed for the Bugzilla 3.4 version as they will both use the same Bugzilla code.

Note You need to log in before you can comment on or make changes to this bug.