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
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
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
. Yes, you will use POSTMAN
to request that
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
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!
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:
Ok, maybe that cURL
7.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
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 Guzzle
3 is buggy! and BADUM-TSSS!! SAME FU.. ERROR!!! WHAT!?!?
You're definitelly done. Guzzle
5 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"
5 it is a bit easier, but there are lots of information in the docs
Hope it helps!