How can I detect if a cookie exists using the Ruby programming language? - ruby

I know how to read cookies using CGI and Ruby but the problem is, if I try to read cookies.value[0] when it does not exists, it breaks my program. So I need to check if the cookie is there to read first. I can't find this answer anywhere on the internet.
Please help, thank you,
Henry.

The Ruby CGI doc says:
HTTP Cookies are automatically parsed from the request. They are available from the cookies() accessor, which returns a hash from cookie name to CGI::Cookie object.
If that's the case, then the cookies are simply stored in a regular hash. You can use the regular Hash API to check for the presence of the target cookie, including Hash.key?():
if cgi.cookies().key?("mycookie")
p "Cookie value is #{cgi.cookies()["mycookie"].value}"
else
p "Cookie does not exist."
end

This works for me using slim.
- if cookies().key?("cookieName")
p Cookie value is #{cookies()["cookieName"]}
- else
p "Cookie does not exist."
end
First will result in true if cookie present.

Related

setting cookie for use in warden. "invalid cookie value"

I am writing specs for my api and am manually writing a http request.
I am trying to set a cookie by adding the following key-val header
cookies
cookies: {
'warden.user.user.key' => ActiveSupport::JSON.encode(
[[session_data[0]], session_data[1]]
)
}
That's a String-String key-val pair, but the value is invalid. I get ArgumentError: Invalid cookie value for the JSON-serialized value (which ends up as
"\"[[Xy2LppWrQ53yHmpxVOkF7w], $2a$10$a/kS05VaSlNv2wwBXPfGU.]\""
I honestly have no idea how to fix this. I am trying to make a cookie with this format because in my Controller, I figured out that the session cookie is stored in warden.user.user.key and the value is a nested array of [[object_uid], session_token]
Appreciate whatever help! thanks
If it makes any difference, I am using airborne to make the requests (which uses rest-client under the hood, but doesn't throw errors on non-OK status codes.)
In the bigger picture I'm just trying to pass a session token to warden, which is used by devise.

How to tell Faraday to preserve hashbang in site URL?

I'm working on a fork of a library that implements Faraday to build URLs.
site = "https://example.io/#/"
path = "oauth/authorize"
connection = Faraday.new(site)
resource = Faraday::Utils.URI(path)
URL = connection.build_url(resource)
Notice that my site URL ends with a hashbang. But when the above code is executed, Faraday strips out the hashbang entirely:
https://example.io/oauth/authorize
But my application requires it to build this URL (with the hashbang):
https://example.io/#/oauth/authorize
Now before I go ripping out Faraday and monkey-patching something terrible.. can I do this by setting an option on Faraday?
I think the answer here would be to quit trying to preserve the hash portion of the URL in Faraday since that portion is ignored for HTTP requests.
The hash part of the URL (also known as URI "fragment identifier") is never sent to the server. It can only have a meaning in the client. Typically, when the HTTP client is a web browser, the fragment identifier holds the name of the element to scroll to. Or, hashbang tricks can be employed with some JavaScript interaction.
But to use such URLs in Faraday doesn't make sense because the hash portion will never get sent to the server anyway.
Having '#' in path variable instead of site variable i am getting the output as you require.
site = "https://example.io/"
path = "#/oauth/authorize"
connection = Faraday.new(site)
resource = Faraday::Utils.URI(path)
URL = connection.build_url(resource)
Please try the above code and let me know the result.

check duplication of cookies in Ruby

I am writing automated test scripts to check the duplication of cookies in Ruby. I am using the following code to obtain the value of a particular cookie.
browser = Capybara.current_session.driver.browser
cookie = browser.manage.cookie_named("__utma")
if cookie[:value].eql? $tracking_parameter
else
puts cookie[:value]
exit
end
I would like to know if the cookie __utma is present twice or duplicated, then how the code can be changed in order to test?

Ruby's open-uri and cookies

I would like to store the cookies from one open-uri call and pass them to the next one. I can't seem to find the right docs for doing this. I'd appreciate it if you could tell me the right way to do this.
NOTES: w3.org is not the actual url, but it's shorter; pretend cookies matter here.
h1 = open("http://www.w3.org/")
h2 = open("http://www.w3.org/People/Berners-Lee/", "Cookie" => h1.FixThisSpot)
Update after 2 nays: While this wasn't intended as rhetorical question I guarantee that it's possible.
Update after tumbleweeds: See (the answer), it's possible. Took me a good while, but it works.
I thought someone would just know, but I guess it's not commonly done with open-uri.
Here's the ugly version that neither checks for privacy, expiration, the correct domain, nor the correct path:
h1 = open("http://www.w3.org/")
h2 = open("http://www.w3.org/People/Berners-Lee/",
"Cookie" => h1.meta['set-cookie'].split('; ',2)[0])
Yes, it works. No it's not pretty, nor fully compliant with recommendations, nor does it handle multiple cookies (as is).
Clearly, HTTP is a very straight-forward protocol, and open-uri lets you at most of it. I guess what I really needed to know was how to get the cookie from the h1 request so that it could be passed to the h2 request (that part I already knew and showed). The surprising thing here is how many people basically felt like answering by telling me not to use open-uri, and only one of those showed how to get a cookie set in one request passed to the next request.
You need to add a "Cookie" header.
I'm not sure if open-uri can do this or not, but it can be done using Net::HTTP.
# Create a new connection object.
conn = Net::HTTP.new(site, port)
# Get the response when we login, to set the cookie.
# body is the encoded arguments to log in.
resp, data = conn.post(login_path, body, {})
cookie = resp.response['set-cookie']
# Headers need to be in a hash.
headers = { "Cookie" => cookie }
# On a get, we don't need a body.
resp, data = conn.get(path, headers)
Thanks Matthew Schinckel your answer was really useful. Using Net::HTTP I was successful
# Create a new connection object.
site = "google.com"
port = 80
conn = Net::HTTP.new(site, port)
# Get the response when we login, to set the cookie.
# body is the encoded arguments to log in.
resp, data = conn.post(login_path, body, {})
cookie = resp.response['set-cookie']
# Headers need to be in a hash.
headers = { "Cookie" => cookie }
# On a get, we don't need a body.
resp, data = conn.get(path, headers)
puts resp.body
Depending on what you are trying to accomplish, check out webrat. I know it is usually used for testing, but it can also hit live sites, and it does a lot of the stuff that your web browser would do for you, like store cookies between requests and follow redirects.
you would have to roll your own cookie support by parsing the meta headers when reading and adding a cookie header when submitting a request if you are using open-uri. Consider using httpclient http://raa.ruby-lang.org/project/httpclient/ or something like mechanize instead http://mechanize.rubyforge.org/ as they have cookie support built in.
There is a RFC 2109 and RFC 2965 cookie jar implementation to be found here for does that want standard compliant cookie handling.
https://github.com/dwaite/cookiejar

How do I pass data using sessions in Ruby CGI?

I am working on a guess-a-number game with Ruby that will be online. I know I need to pass the SESSION somehow to keep the number that they are guessing, but I have tried a ton of methods with no luck. My code is here.
Any thoughts on what I can do get this code working? I have declared each of my sections.
A session is, usually, a combination of a cookie (session cookie), or some session id tacked onto the url, which has some unique identification of the current "session" and a way to save the data on the server and retrieve it when given the id from the cookie.
So I would set a cookie based on for example ip + Time.now.to_i and then save that ID and the values I want set into a database or a text file on the hard drive. Note that there is probably a lot better ways to create a unique ID but aim for the simple stuff first. :)
I also recommend that you look into CGI::Session which you require with require 'cgi/session'.

Resources