Hi!

I've recently noticed two related bugs which are also present in the
most recent version of the XMLRPC library.

First let me describe the circumstances.
*) using Apache HTTPClient to communicate with XMLRPC Servlet
*) between them can optionally be a HTTP proxy
*) ...and there is an Apache server with reverse proxying enabled to
forward requests to server into protected network
*) configuration of XmlRpcClient instance: enabledForExtensions
enabled; GZIP replies enabled; GZIP requests enabled; Content-length
header is not optional

This configuration does not work. Apache throws away the request as
erroneous. If there is a proxy, it also does.

I was diving into the code and noticed this part:

(code from org.apache.xmlrpc.client.XmlRpcHttpTransport:102)

    protected ReqWriter newReqWriter(XmlRpcRequest pRequest)
            throws XmlRpcException, IOException, SAXException {
        final XmlRpcHttpClientConfig config = (XmlRpcHttpClientConfig)
pRequest.getConfig();
        if (isUsingByteArrayOutput(config)) {
            ByteArrayReqWriter reqWriter = new ByteArrayReqWriter(pRequest);
            setContentLength(reqWriter.getContentLength());
            if (isCompressingRequest(config)) {
                return new GzipReqWriter(reqWriter);
            }
            return reqWriter;
        } else {
            return super.newReqWriter(pRequest);
        }
    }

which must be wrong, because it sets the ContentLength header to be
the length of the _uncompressed_ request, but returning the compressed
message. This is bad according to the HTTP spec.
If I'm right, a "trivial" fix would be like this:

    protected ReqWriter newReqWriter(XmlRpcRequest pRequest)
             throws XmlRpcException, IOException, SAXException {
         final XmlRpcHttpClientConfig config =
(XmlRpcHttpClientConfig) pRequest.getConfig();
         ReqWriter reqWriter = super.newReqWriter(pRequest);
         if (isUsingByteArrayOutput(config)) {
            ByteArrayReqWriter baReqWriter = new ByteArrayReqWriter(reqWriter);
            setContentLength(baReqWriter.getContentLength());
            return baReqWriter;
          }
          return reqWriter;
     }

Of course the constructor ByteArrayReqWriter(reqWriter) needs to be
implemented, and ByteArrayReqWriter rewritten to wrap an existing
ReqWriter.

I certainly hope that this fix does not break anything.

------------------

The other bug I encountered is not so easily reproducible, but it
occured at least once nonetheless. The configuration can be the same,
then only thing that counts is that the Content-length header must be
optional. I tried it without compression of course because with
compression, it would trigger the former bug.

The Apache HTTPClient threw the following exception, which caused
XmlRpcClient to fail:

"I/O exception (org.apache.commons.httpclient.NoHttpResponseException)
caught when processing request: The server xxxxxx.xx failed to respond
Retrying request causes "I/O error while communicating with HTTP
server: Unbuffered entity enclosing request can not be repeated."

I traced the problem to this place:

(code from org.apache.xmlrpc.client.XmlRpcCommonsTransport:144)

        protected void writeRequest(final ReqWriter pWriter) throws 
XmlRpcException {
                method.setRequestEntity(new RequestEntity(){
-                       public boolean isRepeatable() { return contentLength != 
-1; }
+                       public boolean isRepeatable() { return true; }
                        public void writeRequest(OutputStream pOut) throws 
IOException {
                                try {

The HTTPClient got an EOFException while transmitting the request or
receiving the reply. It couldn't retry, because isRepeatable()
returned false. I went through the code to find (if I'm right, again)
that there is nothing to prevent the writeRequest() method to be
called more than one time, every time writing the same result. So my
proposal is to simply return true so that the HTTPClient may call
writeRequest() more than once if it fails.

thanks for your time,
regards,
Balázs Póka
lead developer
iData kft.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to