cloudfoundry / ruby-buildpack

Cloud Foundry buildpack for Ruby, Sinatra and Rails
http://docs.cloudfoundry.org/buildpacks/
Apache License 2.0
65 stars 160 forks source link

Error while accessing a ruby app with an extra "X-Forwarded-Proto" header #74

Closed shoudusse closed 7 years ago

shoudusse commented 7 years ago

Hello,

What version of Cloud Foundry and CF CLI are you using? (i.e. What is the output of running cf curl /v2/info && cf version? CloudFoundry: cf/249 cf version 6.22.2+a95e24c-2016-10-27

What version of the buildpack you are using? ruby_buildpack 2 true false ruby_buildpack-cached-v1.6.28.zip

If you were attempting to accomplish a task, what was it you were attempting to do? I'm trying to make a HTTP request through a reverse proxy.

What did you expect to happen? I was expecting a 200 return code

What was the actual behavior? My app is returning a 400 Bad Request error

Please confirm where necessary:

My app is a simple one page web app:

require 'sinatra'
get '/' do
    'Hello world'
end

If I curl the app without X-Forwarded-Proto header, it's OK

nc 192.168.26.30 80
GET / HTTP/1.1
Host: ruby.apps.fr

HTTP/1.1 200 OK
Content-Length: 11
Content-Type: text/html;charset=utf-8
Date: Tue, 14 Mar 2017 14:09:46 GMT
Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Vcap-Request-Id: 479daad9-be07-4b43-56c5-cc6cc49c3c2c
X-Xss-Protection: 1; mode=block

Hello world

If I add the header, I have a 400 Bad Request

nc 192.168.26.30 80
GET / HTTP/1.1
Host: ruby.apps.fr
X-Forwarded-Proto: https

HTTP/1.1 400 Bad Request
Content-Length: 299
Content-Type: text/html; charset=ISO-8859-1
Date: Tue, 14 Mar 2017 14:10:07 GMT
Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
X-Vcap-Request-Id: 63af39b2-1548-4ac2-4027-fc1342a5ce9e

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
  <HEAD><TITLE>Bad Request</TITLE></HEAD>
  <BODY>
    <H1>Bad Request</H1>
    bad URI `/'.
    <HR>
    <ADDRESS>
     WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26) at
     7b3bda91-3299-4f69-4c3b-c8f7dc92410c:8080
    </ADDRESS>
  </BODY>
</HTML>

I only have this behaviour with the ruby buildpack. If I run the app on my workstation, it's OK Neither no issue with PHP nor Python buildpack

Thanks for your help,

cf-gitbot commented 7 years ago

We have created an issue in Pivotal Tracker to manage this:

https://www.pivotaltracker.com/story/show/141695327

The labels on this github issue will be updated when the story is started.

sclevine commented 7 years ago

I am unable to replicate this with v1.6.28. Can you provide a sample app that always demonstrates the behavior with X-Forwarded-Proto: https? I'm testing with:

$ curl -v -H 'X-Forwarded-Proto: https' testapp.local.pcfdev.io
> GET / HTTP/1.1
> Host: testapp.local.pcfdev.io
> User-Agent: curl/7.43.0
> Accept: */*
> X-Forwarded-Proto: https
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Cache-Control: public, max-age=3600
< Content-Length: 29343
< Content-Type: text/html
< Last-Modified: Thu, 16 Mar 2017 14:52:00 GMT
< Vary: Accept-Encoding
< X-Vcap-Request-Id: 5e6be543-40b0-4ec2-70f7-7d91250896ad
< Date: Thu, 16 Mar 2017 15:41:53 GMT

vs.

$ curl -v testapp.local.pcfdev.io
> GET / HTTP/1.1
> Host: testapp.local.pcfdev.io
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Cache-Control: public, max-age=3600
< Content-Length: 29343
< Content-Type: text/html
< Last-Modified: Thu, 16 Mar 2017 14:52:00 GMT
< Vary: Accept-Encoding
< X-Vcap-Request-Id: 9e40febe-5f33-49ea-5e65-51d6369d8ded
< Date: Thu, 16 Mar 2017 15:41:37 GMT
shoudusse commented 7 years ago

A very simple app was provide in my first comment (so small, you didn't noticed ;-) Here it is:

require 'sinatra'
get '/' do
   'Hello world'
end

If I use curl like you, I still have the problem:

$ curl -v -H "Host: ruby.apps.fr" -H "X-Forwarded-Proto: https" http://192.168.26.30
* Rebuilt URL to: http://192.168.26.30/
*   Trying 192.168.26.30...
* Connected to 192.168.26.30 (192.168.26.30) port 80 (#0)
> GET / HTTP/1.1
> Host: myhost
> User-Agent: curl/7.47.0
> Accept: */*
> X-Forwarded-Proto: https
> 
< HTTP/1.1 400 Bad Request
< Content-Length: 299
< Content-Type: text/html; charset=ISO-8859-1
< Date: Thu, 16 Mar 2017 17:39:01 GMT
< Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
< X-Vcap-Request-Id: 723b9d12-f749-4b59-48db-e5ff10dfe7a6

vs

$ curl -v  -H "Host: myhost" http://192.168.26.30
* Rebuilt URL to: http://192.168.26.30/
*   Trying 192.168.26.30...
* Connected to 192.168.26.30 (192.168.26.30) port 80 (#0)
> GET / HTTP/1.1
> Host: ruby.apps.fr
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Length: 11
< Content-Type: text/html;charset=utf-8
< Date: Thu, 16 Mar 2017 17:37:41 GMT
< Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Vcap-Request-Id: af7f4123-48fa-467a-53c0-19ae568f6f11
< X-Xss-Protection: 1; mode=block
sclevine commented 7 years ago

Okay, I'll assume that file is called app.rb, and that you have a Gemfile with only sinatra as a dependent gem, with ruby 2.3.1 explicitly specified. I'll also assume that you have a Gemfile.lock, and that you created it locally with ruby 2.3.1 and bundler 1.13.6. Furthermore, I'll assume you have a config.ru file with following contents:

require './app'
run Sinatra::Application

I am still unable to replicate:

liberty:ruby-buildpack-74 pivotal$ curl -v -H 'X-Forwarded-Proto: https' testapp.local2.pcfdev.io
* Rebuilt URL to: testapp.local2.pcfdev.io/
*   Trying 192.168.22.11...
* Connected to testapp.local2.pcfdev.io (192.168.22.11) port 80 (#0)
> GET / HTTP/1.1
> Host: testapp.local2.pcfdev.io
> User-Agent: curl/7.43.0
> Accept: */*
> X-Forwarded-Proto: https
>
< HTTP/1.1 200 OK
< Content-Length: 11
< Content-Type: text/html;charset=utf-8
< Date: Tue, 21 Mar 2017 15:54:14 GMT
< Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Vcap-Request-Id: 7c770239-a495-444b-718a-fc588b3bf82e
< X-Xss-Protection: 1; mode=block
<
* Connection #0 to host testapp.local2.pcfdev.io left intact
Hello world

vs

liberty:ruby-buildpack-74 pivotal$ curl -v testapp.local2.pcfdev.io
* Rebuilt URL to: testapp.local2.pcfdev.io/
*   Trying 192.168.22.11...
* Connected to testapp.local2.pcfdev.io (192.168.22.11) port 80 (#0)
> GET / HTTP/1.1
> Host: testapp.local2.pcfdev.io
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 11
< Content-Type: text/html;charset=utf-8
< Date: Tue, 21 Mar 2017 15:54:45 GMT
< Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Vcap-Request-Id: f9662dd7-b4e6-4e58-4925-a105ae9ae183
< X-Xss-Protection: 1; mode=block
<
* Connection #0 to host testapp.local2.pcfdev.io left intact
Hello world

(By the way, not sure if you intended to leave your deployment domain in your second example.)

shoudusse commented 7 years ago

Sorry I did not gave you all this informations, but yes, all your assumptions are good. For the context, I'm having this issue while running smoke tests errand over my cloudfoundry deployment. The smoke tests are using a route via a ha-proxy in front of cloudfoundry and they failed. I will try to find if I have an issue relative to my proxy chain and the "X-Forwarded-For" header. Thanks for your help

sclevine commented 7 years ago

Happy to help! Seems like your issue isn't buildpack related, so I'm going to close this for now.

shoudusse commented 7 years ago

Finaly found the root cause of my issue. It's a webrick issue associated with a miss configured proxy. ruby/webrick issue TL;DR; The haproxy included in cf-release does not verify if "X-Forwarded-Proto" header already exists and appends its own value. Webrick does not support a "X-Forwarded-Proto" header with 2 values The haproxy configuration provided with cf-haproxy-boshrelese verify the existence.

The final solution is not using the haproxy provided with cf-release