Rails 3.2 HTTP streaming fails (Thin server on Windows) - ruby-on-rails

I'm trying to get my pages to stream but I'm getting the following error:
Error 321 (net::ERR_INVALID_CHUNKED_ENCODING): Unknown error
I've tried in both Chrome, IE and Firefox.
def login
redirect_to_stored and return if session[:user]
if request.post?
if session[:user] = User.authenticate(params[:login], params[:password])
redirect_to_stored(notice: 'Login successful') and return
else
flash_now :alert => "Login unsuccessful"
end
end
on_document_load "$('#login').focus();"
render :layout => 'login', :stream => true
end
I get the following response headers:
Cache-Control:must-revalidate, private, max-age=0
Connection:close
Content-Type:text/html; charset=utf-8
Server:thin 1.5.0 codename Knife
Set-Cookie:_rails3.website_session=biglongstringhere; path=/; expires=Sat, 02-Mar-2013 01:44:38 GMT; HttpOnly
Set-Cookie:__profilin=p%3Dt; path=/
Set-Cookie:__profilin=p%3Dt; path=/
Transfer-Encoding:chunked
X-MiniProfiler-Ids:[a bunch of stuff in here (this isn't the actual text)]
X-Request-Id:695da38a40064d87cbd463c83fef0a88
X-Runtime:0.034002
X-UA-Compatible:IE=Edge
Looking in Chrome's inspector, the file 'login' shows the Status as 'failed' but when clicking it, the Status Code is 200 OK. Another thing I've noticed is that if I put the following in before the original render call, the response displays OK, but Chrome inspector still thinks the Status response was in error (like the 1st time). Is the connection being closed before the rest of the body has a chance to be delivered? I don't understand what's wrong here.
render(:text => 'test', :stream => true) and return
As an addendum, the rails log does not show any errors. It renders everything just fine.

I have two servers; one at work and one at home. The one at home doesn't use nginx or any downstream application to communicate with Thin. Thin on its own produces an error...but using nginx in front, the files are served appropriately. Strangely though, when I don't have any streaming explicitly enabled in my rails app, the files are still served as Content Type: chunked.
Heck, even my public website is being served as chunked...but I never had streaming enabled in Rails...so that must mean the final result is chunked but not the actual rendering of the html. How can I actually test this then?

Related

Error when creating tags with Gibbon (Ruby MailChimp client)

I have an issue when trying to create tags/segments with Gibbon, the MailChimp wrapper for Ruby.
I've been using Gibbon successfully for a large production site for 2 years, but need to move away from Merge Fields to tagging subscribers.
I can successfully add tags to a subscriber via Gibbon, but there are over 85,000 users that need to be transitioned and I really don't want to have to make 85,000 individual requests. There are 200+ possible tags, so I wanted to find all the users for each possible tag and then post the email addresses to the segment endpoint... so 200 requests, rather than 85,000.
The issue is that If a tag already exists (i.e. a test tag I created) in the list, then I get 400 error, Tag already exists and if the tag doesn't exist, I get 404 Resource Not Found. This is the same if I supply email addresses within static_segment or not.
I would expect the following to create a tag within MailChimp:
request = Gibbon::Request.lists(<list_id>)
request.tags.create(body: { name: "testing3", static_segment: [] })
However, I recieve the following error (which is the same if I use tags or segmentsin the request):
I, [2019-06-06T10:33:59.711436 #88340] INFO -- request: POST https://us15.api.mailchimp.com/3.0/lists/<list_id>/tags
D, [2019-06-06T10:33:59.711556 #88340] DEBUG -- request: User-Agent: "Faraday v0.15.4"
Authorization: "Basic <key>"
Content-Type: "application/json"
D, [2019-06-06T10:33:59.711605 #88340] DEBUG -- request: {"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/","title":"Resource Not Found","status":404,"detail":"Invalid path","instance":"<instance_id>"}
I, [2019-06-06T10:33:59.711779 #88340] INFO -- response: Status 404
D, [2019-06-06T10:33:59.711839 #88340] DEBUG -- response: server: "openresty"
content-type: "application/problem+json; charset=utf-8"
x-request-id: "<instance_id>"
link: "<https://us15.api.mailchimp.com/schema/3.0/ProblemDetailDocument.json>; rel=\"describedBy\""
vary: "Accept-Encoding"
date: "Thu, 06 Jun 2019 09:33:59 GMT"
content-length: "204"
connection: "close"
set-cookie: "_AVESTA_ENVIRONMENT=prod; path=/, _mcid=1.b9640bf1122e4a9b277bb19e3d72caf6; expires=Fri, 05-Jun-2020 09:33:59 GMT; Max-Age=31536000; path=/; domain=.mailchimp.com"
D, [2019-06-06T10:33:59.711878 #88340] DEBUG -- response: {"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/","title":"Resource Not Found","status":404,"detail":"Invalid path","instance":"<instance_id>"}
Gibbon::MailChimpError: the server responded with status 404 #title="Resource Not Found", #detail="Invalid path", #body={:type=>"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/", :title=>"Resource Not Found", :status=>404, :detail=>"Invalid path", :instance=>"<instance_id>"}, #raw_body="{\"type\":\"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/\",\"title\":\"Resource Not Found\",\"status\":404,\"detail\":\"Invalid path\",\"instance\":\"<instance_id>\"}", #status_code=404
from /Users/Paul/.rvm/gems/<gemset>/gems/gibbon-3.2.0/lib/gibbon/api_request.rb:134:in `handle_error'
Caused by Faraday::ResourceNotFound: the server responded with status 404
from /Users/Paul/.rvm/gems/<gemset>/gems/faraday-0.15.4/lib/faraday/response/raise_error.rb:8:in `on_complete'
I'm using the latest version of Gibbon 3.2.0.
When I byebug'ed inside of the Gibbon::APIRequest.post to see the path that was being generated I see the following:
(byebug) base_api_url
"https://us15.api.mailchimp.com/3.0/"
# For request.segments
(byebug) api_url
"https://us15.api.mailchimp.com/3.0/lists/<list_id>/segments"
# For request.tags
(byebug) api_url
"https://us15.api.mailchimp.com/3.0/lists/<list_id>/tags"
Any help would be much appreciated, as I'm really not sure what I'm doing wrong.
Thank you in advance.
Paul. :)
So for anyone else that might struggle with this, the Gibbon docs don't talk about Segments at all, but do reference tags, which I think is where some of my confusion make from.
request.tags should have been request.segments.
The other issue is that the request cannot be reused, so because I was performing the action inside a loop, by assigning request1 = Gibbon::Request.lists(<list_id>) and trying to use that for the second iteration, Gibbon forwarded the request to the wrong path and returned a 404 error.
Each request needs to be its own instance of Gibbon Request Gibbon::Request. So the following would work:
request = Gibbon::Request
#loop start
request.lists(<list_id>).segments.create(body: { name: "testing", static_segment: [] })
# loop end
Hope that helps someone else.
Gibbon::Request.lists(LIST_ID).segments.create(body: { name: "NAME", static_segment: [] })

Ruby 2.3/Rails - net uri not working anymore after update to Ubuntu 16.04

I used to have a working code in my Admin Panel , checking if a url inputed existed and giving a friendly message to the Administrator in case it did not..
def get_url_response(url)
uri = URI(url)
request = Net::HTTP.get_response(uri)
return request
end
url_response = get_url_response("http://www.example.com").code
if url_response === "200" || url_response === "304"
link_to http://www.example.com, http://www.example.com, target: :blank
else
status_tag("We have a problem ! Response code: "+url_response, :class => 'red')
end
It works great when the address ("http://www.example.com" in the example above) exists, that it to say sends back a 200 code, but as soon as I have a non existing address such as http://www.examplenotexistingotallyfake.com, it should send a 404 code and display ""We have a problem ! Response code:" but it fails with the error message:
SocketError: Failed to open TCP connection to examplenotexistingotallyfake.com:443 (getaddrinfo: Name or service not known)
from /home/mreisner/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/net/http.rb:882:in `rescue in block in connect'
I verified this by opening my Rails console (Rails c) and if I type:
Net::HTTP.get(URI('https://www.examplenotexistingotallyfake.com')).code
I get the same error message:
SocketError: Failed to open TCP connection to examplenotexistingotallyfake.com:443 (getaddrinfo: Name or service not known)
from /home/mreisner/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/net/http.rb:882:in `rescue in block in connect'
How can it work for correct urls and not for non-existing addreses? it should just work but send me back a 404 code, shouldn't it?
I can only see the upgrade to Ubutun 16.04 i made a few days ago, that might have tampered with some critical dns/localhost settings as the source of this issue but not 100% totally sure.
EDIT
After some suggestions, I now try to avoid the app crashing by rescuing this
def get_url_response(url)
begin
uri = URI(url)
request = Net::HTTP.get_response(uri)
return request
rescue SocketError => e
puts "Got socket error: #{e}"
end
end
but the app still crashes with a socket Error message
That's the correct behaviour.
The problem there is that examplenotexistingotallyfake.com doesn't exists in the DNSs entries.
If you look at the description of what the 404: https://en.wikipedia.org/wiki/HTTP_404
to indicate that the client was able to communicate with a given
server, but the server could not find what was requested.
So, in order to get the 404 code you'll need first to be able to communicate with the server in question.
You can double check this behaviour using chrome or even curl, visiting the following urls: examplenotexistingotallyfake.com or google.com/missing
Each will give a different result.
in curl:
$ curl -I examplenotexistingotallyfake.com
curl: (6) Could not resolve host: examplenotexistingotallyfake.com
# google
curl -I google.com/missing
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=UTF-8
Referrer-Policy: no-referrer
Content-Length: 1568
Date: Fri, 12 Jan 2018 09:25:27 GMT
If you want your code to behave in the same way (even though I'd suggest that give the user a different message, you can do the following):
require 'uri'
require 'net/http'
require 'ostruct'
def get_url_response(url)
uri = URI(url)
request = Net::HTTP.get_response(uri)
return request
rescue Errno::ECONNREFUSED => e
OpenStruct.new(code: 404)
end
Its not an issue , the site you are looking for it doesn't exists and can't be reached.
So it will give DNS address is not found issue when you try to hit it directly.Thats why the error:
It directly gives socketError : getaddrinfo: Name or service not known You need to handle this.
But if you want 404 status code, you will get it when the site(address) is present and the page inside that site is not.
To get 404 your address should be valid and error will raise if The requested URL /examples was not found on this server.

ionic doesn't keep session on serve

I'm trying to save user in a session using
session[:user_id] = user_id # comes from ionic via get
but when i'm trying to send another $http.get request, I'm getting:
ActionDispatch::Request::Session:0x7fa8882b2ae0 not yet loaded # when I print session
nil # when I print session[:user_id]
If I run it from my android device it works fine.
Also tries to give it expired_at but still no luck.
Headers:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:close
ETag:W/"b8f8b488bd2e233c017c98f592099e7b"
Server:thin
Set-Cookie:_MyAppServer_session=REVtSTJMYXR0TDRSVSs0VEdvNEF3a2RjR21Hei8wRFBpdFkyR3VOQTgyeXNLNGFvYjdsWjFudG9MNk51NkR2Y25DMUFmL1RsZUhmdHhUeUxTSnJPcHc9PS0tUHlTS3BYT1VOMnFSem4zS1JaeGErUT09--de9f966344e4e90810e428f53bd6cf2783ccf835; path=/; HttpOnly
Vary:Origin
I add $http.defaults.withCredentials = true; to the ionic js.
XmlHttpRequest CORS POST sent without cookies

Rails 4: How to set cookies in redirect?

I have a controller that attempts takes form inputs, set values in a cookie and then redirect to a page that will pull from that cookie.
The problem is that the cookie is never set in the redirect headers.
Notes: I've tested in Chrome and FF. Rails version is 4.0.13. Setting cookies w/o a redirect works as expected.
Here's the controller code:
def create
request.cookies[:foo] = "bar"
# also tried:
# cookies[:foo]="bar"
# cookies.signed[:foo]="bar"
# cookies[:foo] = {
# value: "bar",
# expires: 1.month.from_now,
# domain: ".myapplicationhostname.com"
# }
redirect_to root_url
end
The response header on the redirect doesn't contain a Set-Cookie attribute and as such, the cookie values aren't available in the controller/action in the redirected-to path.
I've found some contradictory evidence that some browsers don't accept cookies in redirects, but it appears that that's not the case anymore? And anyways, neither FF or Chrome are showing a Set-Cookie in the response header, so it doesn't appear this is a browser issue.
Here's the header response from cURL, note the lack of Set-Cookie:
HTTP/1.1 302 Moved Temporarily
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Location: http://app.mydomain.com:3000/
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
X-Request-Id: 1fc1c7e5-7489-4720-bb70-28588f3abcb6
X-Runtime: 4.688166
Connection: close
Server: thin 1.6.2 codename Doc Brown
How do I get rails to set cookies (or at least set the header) on redirects?
It appears that the cause of this is actually CSRF protection kicking in. The controller had instantiated a NullCookieJar which prevents the writing of cookies when there's a potentially forged POST.
This is because my controller was being set up to respond to an off-site form, thus no access to the CSRF token.
So, if you're running into this when submitting an off-site form to your Rails app, you'll need to disable the CSRF check or write your own verification method as described in the answer to the SO question: "Receive POST from External Form".
Summarized here:
Disabling Check
skip_before_filter :verify_authenticity_token, only: :my_action
Custom Check
skip_before_filter :verify_authenticity_token, :only => :my_action
before_filter :verify_custom_authenticity_token, :only => :my_action
def verify_custom_authenticity_token
# checks whether the request comes from a trusted source
end

How to set "Connection: close" header in Rails

To fix issues with Safari frequently hanging when uploading files, I need to make a request to my Rails server and have it return an empty body with a "Connection: close" header. More details about this fix can be found here.
So far, I have tried:
def close
return head :ok, {'Connection' => 'close'}
end
def close
response.headers['Connection'] = 'close'
render :nothing => true
end
def close
response.headers['Connection'] = 'close'
return head :ok
end
None of these approaches seem to work. Inspecting the request in Firebug and Safari's developer console reveals that the response header, Connection, is always set to "keep-alive"
I'm running Rails 2.3.5 with Mongrel and Nginx. Setting a header such as Content-Type does work by the way.
Any ideas on how to fix this?
So I never figured out how to do this in Rails, but I did find out that nginx version 0.7.66+ disables keepalive connections for Safari. See the nginx changelog.
So I upgraded my nginx and all is well with Safari now.

Resources