magentomagento-1.7magento-soap-api

Magento Soap API V2 Response Content Length Incorrect


We are trying to connect our magento installation with a third party stock management app(built on .net). But the sync is not working, the third party tells me that the soap api is returning an empty response.

I have been pulling my hear out, because whenever I make anything in PHP the API works fine. In addition inventory updating works fine, but retrieving order/invoice information does not (well it actually does occasionally 1% of the time)

With the intermittent nature we felt that it must be a network issue, but after lots of searching and adding mage::log() into the core api files I can see that the connection is happening and further more the response object is being created by Magento.

So my deduction as that something was not right with the SOAP API (I am using version 2)

I have installed soapUI and setup our integration, it correctly receives the methods from the WSDL file but when I try to access the "login" method I get an empty response, even when I put in the incorrect login details it is empty.

soapUI outputs the following error:

ERROR:An error occured [Premature end of Content-Length delimited message body (expected: 267; received: 266], see error log for details

So it seems as though there is an issue with the http headers, some functions are able to return a response (of course without the login hash it is just invalid, but at least it is a response). From my (exceedingly limited) understanding of java and .net, they are much stricter on these things than php which would indicate why a php integration would have no issues.

Can anyone advise me why this error would occur and how to fix it?


Solution

  • I'm going to assume you are using the WS-I compliant SOAP API v2 as I had this exact same issue; if not, then this still might apply. I was never able to connect to the v2 API without it being WS-I compliant, which is how I found this bug.

    If you have a look at the app/code/core/Mage/Api/Model/Server/Wsi/Adapter/Soap.php file you will see in the public run function that is essentially split into two parts - 1 for the WSDL definition response and 1 for the actual SOAP response.

    In the SOAP response there is a bit of string replacing going on, substituting <soap:operation soapAction=""></soap:operation> for <soap:operation soapAction="" /> and so on. This is evidently causing an issue with the content-length calculation - this is also occurring in the WSDL definition response, but it doesn't seem to be causing an issue.

    I was able to successfully connect to the SOAP API by replacing the code between the try curly brackets with the code below. Basically, I ended up clearing the headers and recalculating the content-length AFTER the string replacement had taken place:

                $this->_instantiateServer();
    
                $content = preg_replace(
                            '/(\>\<)/i',
                            ">\n<",
                            str_replace(
                                    '<soap:operation soapAction=""></soap:operation>',
                                    "<soap:operation soapAction=\"\" />\n",
                                    str_replace(
                                            '<soap:body use="literal"></soap:body>',
                                            "<soap:body use=\"literal\" />\n",
                                            preg_replace(
                                                '/<\?xml version="([^\"]+)"([^\>]+)>/i',
                                                '<?xml version="$1" encoding="'.$apiConfigCharset.'"?>',
                                                $this->_soap->handle()
                                            )
                                    )
                            )
                        );
    
                $this->getController()->getResponse()
                          ->clearHeaders()
                          ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset)
                          ->setHeader('Content-Length',strlen($content))
                          ->setBody($content);
    

    Hope this helps