295 lines
9.0 KiB
Markdown
295 lines
9.0 KiB
Markdown
Nav: [Workbook](../workbook.md) :: [Generating Responses](../generating_response/generating_response.md)
|
||
|
||
# Handling Cookies
|
||
|
||
- [Cookie](#cookie)
|
||
- [Cookie Porperties](#properties)
|
||
- [Write and Read Cookies](#set_get)
|
||
- [How to set a cookie](#set_cookie)
|
||
- [How to read a cookie](#read_cookie)
|
||
- [Examples](#examples)
|
||
|
||
<a name="cookie"></a>
|
||
|
||
## Cookie
|
||
A [cookie](http://httpwg.github.io/specs/rfc6265.html) is a piece of data that can be stored in a browser's cache. If you visit a web site and then revisit it, the cookie data can be used to identify you as a return visitor. Cookies enable state information, such as an online shopping cart, to be remembered. A cookie can be short term, holding data for a single web session, that is, until you close the browser, or a cookie can be longer term, holding data for a week or a year.
|
||
|
||
Cookies are used a lot in web client-server communication.
|
||
|
||
- HTTP State Management With Cookies
|
||
|
||
- Personalized response to the client based on their preference, for example we can set background color as cookie in client browser and then use it to customize response background color, image etc.
|
||
|
||
Server send cookies to the client
|
||
|
||
>Set-Cookie: _Framework=EWF; Path=/; Expires=Tue, 10 Mar 2015 13:28:10 GMT; HttpOnly%R
|
||
|
||
|
||
Client send cookies to server
|
||
|
||
>Cookie: _Framework=EWF
|
||
|
||
|
||
|
||
<a name="properties"></a>
|
||
|
||
### Cookie properties
|
||
|
||
- Comment: describe the purpose of the cookie. Note that server doesn’t receive this information when client sends cookie in request header.
|
||
- Domain: domain name for the cookie.
|
||
- Expiration/MaxAge: Expiration time of the cookie, we could also set it in seconds. (At the moment Max-Age attribute is not supported)
|
||
- Name: name of the cookie.
|
||
- Path: path on the server to which the browser returns this cookie. Path instruct the browser to send cookie to a particular resource.
|
||
- Secure: True, if the browser is sending cookies only over a secure protocol, False in other case.
|
||
- Value: Value of th cookie as string.
|
||
- HttpOnly: Checks whether this Cookie has been marked as HttpOnly.
|
||
- Version:
|
||
|
||
<a name="set_get"></a>
|
||
|
||
## Write and Read Cookies.
|
||
|
||
To send a cookie to the client we should use the **HTTP_HEADER** class, and call ```h.put_cookie``` feature or
|
||
```h.put_cookie_with_expiration_date``` feature, see `How to set Cookies` to learn the details, and the set it to response object **WSF_RESPONSE** as we saw previously.
|
||
|
||
We will show an example.
|
||
|
||
To Read incomming cookies we can read all the cookies with
|
||
|
||
```
|
||
cookies: ITERABLE [WSF_VALUE]
|
||
-- All cookies.
|
||
```
|
||
which return an interable of WSF_VALUE objects corresponding to the cookies the browser has associated with the web site.
|
||
We can also check if a particular cookie by name using
|
||
|
||
```
|
||
WSF_REQUEST.cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||
-- Field for name `a_name'.
|
||
```
|
||
feature.
|
||
|
||
|
||
<a name="set_cookie"></a>
|
||
|
||
### How to set Cookies
|
||
Here we have the feature definitions to set cookies
|
||
|
||
```eiffel
|
||
deferred class interface
|
||
HTTP_HEADER_MODIFIER
|
||
|
||
feature -- Cookie
|
||
|
||
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||
-- Set a cookie on the client's machine
|
||
-- with key 'key' and value 'value'.
|
||
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
||
-- since they are not always handled by browser (for instance Chrome)
|
||
require
|
||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
|
||
|
||
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||
-- Set a cookie on the client's machine
|
||
-- with key 'key' and value 'value'.
|
||
require
|
||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||
```
|
||
|
||
Example of use:
|
||
|
||
```eiffel
|
||
response_with_cookies (res: WSF_RESPONSE)
|
||
local
|
||
l_message: STRING
|
||
l_header: HTTP_HEADER
|
||
l_time: HTTP_DATE
|
||
do
|
||
create l_header.make
|
||
create l_time.make_now_utc
|
||
l_time.date_time.day_add (40)
|
||
l_header.put_content_type_text_html
|
||
l_header.put_cookie_with_expiration_date ("EWFCookie", "EXAMPLE",l_time.date_time, "/", Void, False, True)
|
||
res.put_header_text (l_header.string)
|
||
res.put_string (web_page)
|
||
end
|
||
```
|
||
<a name="read_cookie"></a>
|
||
|
||
### How to read Cookies
|
||
|
||
Reading a particular cookie
|
||
```eiffel
|
||
if req.cookie ("EWFCookie") = Void then
|
||
do_something
|
||
end
|
||
````
|
||
|
||
Reading all the cookies
|
||
|
||
```Eiffel
|
||
across req.cookies as ic loop
|
||
print (ic.item.name)
|
||
end
|
||
```
|
||
|
||
|
||
<a name="examples"></a>
|
||
|
||
### Example
|
||
The following EWF service shows a basic use of cookies.
|
||
1. It display a message to first-time visitors.
|
||
2. Display a welcome back message if a visitor return.
|
||
3. A visitor page, counting the number of visits to the page (track user access counts).
|
||
4. A cookie with an expiration of 120 seconds.
|
||
5. A cookie with an session level, valid in browser session.
|
||
|
||
```eiffel
|
||
note
|
||
description : "Basic Service that build a generic front to demonstrate the use of Cookies"
|
||
date : "$Date$"
|
||
revision : "$Revision$"
|
||
|
||
class
|
||
APPLICATION_EXECUTION
|
||
|
||
inherit
|
||
WSF_EXECUTION
|
||
|
||
create
|
||
make
|
||
|
||
feature -- Basic operations
|
||
|
||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||
-- Execute the incomming request
|
||
local
|
||
l_message: STRING
|
||
l_header: HTTP_HEADER
|
||
l_time: HTTP_DATE
|
||
l_cookies: STRING
|
||
l_answer: STRING
|
||
do
|
||
-- all the cookies
|
||
create l_cookies.make_empty
|
||
across req.cookies as ic loop
|
||
l_cookies.append (ic.item.name)
|
||
l_cookies.append("<br>")
|
||
end
|
||
|
||
if req.path_info.same_string ("/") then
|
||
create l_header.make
|
||
create l_answer.make_from_string (web_page)
|
||
if req.cookie ("_EWF_Cookie") = Void then
|
||
-- First access the the home page, find a cookie with specific name `_EWF_Cookie'
|
||
l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess")
|
||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||
create l_time.make_now_utc
|
||
l_time.date_time.day_add (40)
|
||
l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True)
|
||
else
|
||
-- No a new access
|
||
l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!")
|
||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||
end
|
||
l_header.put_content_type_text_html
|
||
l_header.put_content_length (l_answer.count)
|
||
res.put_header_text (l_header.string)
|
||
res.put_string (l_answer)
|
||
|
||
elseif req.path_info.same_string ("/visitors") then
|
||
create l_header.make
|
||
create l_answer.make_from_string (visit_page)
|
||
if req.cookie ("_visits") = Void then
|
||
-- First access the the visit page, find a cookie with specific name `_visits'
|
||
l_answer.replace_substring_all ("$visit", "1")
|
||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||
create l_time.make_now_utc
|
||
l_time.date_time.day_add (40)
|
||
l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True)
|
||
|
||
else
|
||
if attached {WSF_STRING} req.cookie ("_visits") as l_visit then
|
||
create l_time.make_now_utc
|
||
l_time.date_time.day_add (40)
|
||
l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out )
|
||
l_answer.replace_substring_all ("$cookies", l_cookies)
|
||
l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True)
|
||
end
|
||
end
|
||
create l_time.make_now_utc
|
||
l_time.date_time.second_add (120)
|
||
l_header.put_content_type_text_html
|
||
-- This cookie expires in 120 seconds, its valid for 120 seconds
|
||
l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True)
|
||
-- This is a session cookie, valid only to the current browsing session.
|
||
l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True)
|
||
l_header.put_content_length (l_answer.count)
|
||
res.add_header_text (l_header.string)
|
||
res.put_string (l_answer)
|
||
end
|
||
|
||
end
|
||
|
||
feature -- Home Page
|
||
|
||
web_page: STRING = "[
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>EWF Handling Cookies</title>
|
||
</head>
|
||
<body>
|
||
<div class="right">
|
||
<h2>$header_title</h2>
|
||
</div>
|
||
|
||
<div class="right">
|
||
<a href="/visitors">Visitors</a>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Cookies for the home page</h3>
|
||
$cookies
|
||
</div>
|
||
</body>
|
||
</html>
|
||
]"
|
||
|
||
|
||
visit_page: STRING = "[
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>EWF Handling Visit Page</title>
|
||
</head>
|
||
<body>
|
||
<div class="right">
|
||
<h2>The number of visits is $visit</h2>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Cookies for the Visit page</h3>
|
||
$cookies
|
||
</div>
|
||
</br>
|
||
|
||
<div>
|
||
Back to <a href="/"> Home </a>
|
||
</div>
|
||
|
||
<div id="footer">
|
||
<p>EWF Example Cookies</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
]"
|
||
|
||
end
|
||
|
||
```
|
||
|
||
|
||
Nav: [Workbook](../workbook.md) :: [Generating Responses](../generating_response/generating_response.md)
|