… really is as uninformative error message you can encounter during a call to some SOAP service. At least at the first glance. Digging deeper into the issue there’s some really interesting causes to that one.
Ok, first some more information. We do a SOAP call and sometimes end up with a SOAP fault ‘error fetching http headers’. Took some time to find the real reason for that.
Simple explanation why this can happen is if you have a default_socket_timeout setting of x seconds on your application and the remote SOAP server takes more than x seconds to answer.
So you system gets no response in time and starts complaining that it got no headers.
Reason one: slow remote SOAP service.
Some additional useful information: apache access log by default logs the time the request was started to be processed by apache, but it end up in log at the time the response is sent out. Requests that are not touched by apache do not end up in access log.
Well, we checked all available logs and could rule out a slow SOAP service for certain. No way it could run into a timeout. We could see logged error messages with ‘error fetching http headers’ on the client, but those requests
never ended up beeing processed by the SOAP server’s apache. After a bit of extended logging all looked like the client even never really sent the requests. So we started to search for a cause why the client thought
it had sent the request but in the same second already logged the empty response error.
At first we suspected some PHP SOAP client or openssl or whatever bug that tricked the client into believing it sent a request when it did not.
Alas, my colleague came up with an interesting link:
which finally gave us the hint about where to look.
The client PHP code does the following: get instance of a class, in the class constructor initialize a SOAP client pointing to our SOAP server, make two SOAP calls. Then do something completely different, namely call a second remote system. After that call is done, the formerly initialized SOAP-Client is reused for another SOAP call and that is what went wrong sometimes.
We had a look at the headers:
Client sent this during request: Connection: keep-alive
SOAP server sent this in reponse: Keep-Alive: timeout=5, max=100
So here we have our reason: the server keeps the connection persistent for 5 seconds which is apache default. The client thinks the connection is persistent and it can call the remote server without sending a handshake first on all subsequent SOAP calls. That is ok if all calls can be done during 5 seconds. But if the call to the second remote system that takes place between SOAP call two and three takes too long, the third SOAP call ends up with ‘error fetching http headers’. Keep in mind, there were no unusual server configurations on any side!
Reason two: default setting of PHP and apache clashing with reusing a SOAP client in PHP.
Here we got, first fix: get a new PHP SOAP client for each call, the wsdl is cached by default so that does not slow the process down. At least it did not look like it did when I tested.
Second fix, but that one we only try to make our customer’s life a bit easier: raise Keep-Alive timeout on the SOAP server. That’s not so easy to be done, because we now might end up with more or longer running apache processes. So in time of high access we might run into trouble with a too high load on our SOAP server.
So note all you PHP developers out there: take care when reusing SOAP client instances, you might get hard to find errors. Playing it safe: never reuse the soap client, if you reuse you can try to try/catch the soap fault and retry with a new instance of SOAP client.
PHP SOAP documentation is not really helpful, maybe there’s some way to force SOAP Client into taking care with connections, but did not yet find it.