A very weird problem with Guzzle

Problem (2) in the Chunked-Encoded data

Computer Science & Black magic. What's the difference?


Yarp. I'm pretty sure you have wondered it many times. Specially when a stupid problem comes up and probably you are in a hurry. Well this is one of those crazy ones.

Here's the problem. You have a web app in the backend, a JSON RESTful api. A front-end web app consumes these resources. Apart of your front-end web app a mobile app is using this api as well. Your web app is using Guzzle to snugly communicate with the api. All works perfectly during months. And you add a small functionality which basically adds a flag to one of the resources.

Ok, imagine a typical request like that returning this JSON object

GET /users/1
{
id: 1,
name: 'Jose',
is_subscriptor: 0
}

The new functionally is just something like that, a user can be a subscriptor(1) or not(0). You change your code and all works nicely in your local vagrant machines. Ok, time to go to your staging/testing server. Git deploy first test. Ok! Now you subscribe the user and you just expect to get the same object with a 1 in the 'is_subscriptor' property but you get a scaring error:
Problem (2) in the Chunked-Encoded data

Story mode [Start] Go to solution

Defcon 4


Obviously, you forgot something, it's strange, but surely you did something wrong so, you take it easy and review your code, but, all is in place. You google about the problem and you see http protocol in cURL, SETOPT, libcurl, cURL 7.35 problem, S3 delete object problems... come on, forget this, obviously your returned object is wrong. You are doing something wrong in the API
POSTMAN. Yes, you will use POSTMAN to request that GET /users/1 and you'll see what's going wrong... but, surprisingly, your api returns the json well-formed and data types are ok.
CURL. Just to be sure, run this on cURL on the terminal, yes, the terminal you are a pro. And yes, it works too. Ok let's repeat the request in your front-end web, it was a temporary problem... You do it and...
Problem (2) in the Chunked-Encoded data

Defcon 3


You starting to get nervous. All works ok in local (vagrant) and works ok in local and staging via curl/POSTMAN. Now, the weird thing. You set manually the flag "is_subscriptor" to 0 in the DB and magically all works, it can not be. Set to 1, error, set to 0, works! set to 1, error... BUT ONLY IN THE STAGING SERVER AND ONLY IN THE TEST/STAGING SERVER! WTF!

Defcon 2


A Guzzle bug? Shit, your are using Guzzle 3.9.3 you are up-to-date. https://github.com/guzzle/guzzle3
...Guzzle 3 is only maintained for bug and security fixes. Guzzle 3 will be EOL at some point in late 2015...

Crap! Google time:
https://github.com/jackalope/jackalope-jackrabbit/issues/89
http://stackoverflow.com/questions/29146515/curl-problem-2-in-the-chunked-encoded-data
http://mtdowling.com/blog/2012/01/27/chunked-encoding-in-php-with-guzzle/
http://stackoverflow.com/questions/18766946/php-curl-response-differs-based-on-network-encoding-issue
Ok, maybe that cURL7.35 is the problem, you install 7.36 from a ppa which works for someone, no luck and reinstall 7.35 (last stable)
What about using http1.0? Jesus, you don't know how to set your Guzzle client to use http1.0 and, also, Guzzle 5 is there, and Guzzle 3...

Defcon 1


Refactor your code, go Guzzle 5. This is good option, and by the way is pretty well documented. You refactor some of your code and do your final test, of course it will work because Guzzle3 is buggy! and BADUM-TSSS!! SAME FU.. ERROR!!! WHAT!?!?
You're definitelly done. Guzzle5 and the same error? and only in the same scenario? data dependent? very very weird... Ok, no choice, use http1.0, might be the solution... so you change the version protocol and
CONGRATULATIONS, HAPPY DAYS!
Story mode [End]


Origin of the problem


However I'm not sure about it, it seems something is wrong probably in lib-curl in the version that currently is installed in EC2 servers (ubuntu 14.04) trhough the standard apt repositories or maybe Guzzle has a problem common in version 3 and 5. It is unlikely since the same code works perfectly in Vagrant machines (my cURL version in Vagrant is 7.22). The thing is curl runs the request and the server (RESTFUL API) is acting normally (returns 200 and the json object). If you try the cURL request form terminal by ssh'ing the EC2 it works perfectly, so it is higher level problem, once guzzle gets the response and post-process it, and only if the response is chuncked (http1.0 doesn't chunck data) and ONLY for some specific data sets, it crashes.

The only solution to me


Just set 1.0 as protocol version. Honestily, I'm not really sure about the deeper impact of using http/1.0, but, is the only possible solution right now to me. To do so, if you are using Guzzle 3 then when you create your Client you must do this:
$client = new Client('http://your.base.url', [
'curl.options' => [
"CURLOPT_HTTP_VERSION" => "CURL_HTTP_VERSION_1_0"
]
]);

In Guzzle 5 it is a bit easier, but there are lots of information in the docs
Hope it helps!