16. Cookies and Local Storage¶
You make have heard about cookies and web pages. What is a cookie, and what is it used for?
A cookie allows us to track a user from one web page request to the other. Do people log into your web site? Do you keep information on a per-user basis? You need cookies!
A cookie allows us to store a simple key/value pair. We can “set” the value. Each web request made by the user’s computer afterwards will contain the key and the value.
We could set a cookie like this:
useraccount = paul_craven
But that would be a terrible idea. Why? Cookies can be changed by the client. All a user would need to do is change the cookie and then they’d be someone else.
What is usually done?
session_id = 2304some_really_long_random_string2034902
We create a session id. This session id is a long randomized string that would be statistically impossible to guess. Then, on the web server (either in memory or in a database) we store a table that has session id, a key, and a value.
It is important that if we use a session id, we also use https for our communications. That will help prevent a person from “sniffing” the session id and pretending to be a different person.
16.1. HTML5 Local Storage¶
Starting with HTML5, web browsers added three new kinds of storage in addition to cookies:
Storage | Format | Scope | Persistence |
---|---|---|---|
Session | Key/value | Session only | Session only |
Local | Key/value | Across sessions | Across sessions |
Database | Structured | Across sessions | Across sessions |
16.2. What websites are storing cookies?¶
Web browsers store the data on your computer. Typically the data will be buried in a spot like:
C:\Users\myusername\AppData\Local\Google\Chrome\User Data\Default
However, there are a couple spots in the web browser where you can look at the sites that are storing data.
16.2.1. Firefox¶
Click the drop down menu and hit “Options”
Then select Privacy and Security, find the “Cookies and Site Data” section, and finally “Manage Data.”
Then you can see what sites have stored data. Unfortunately with Firefox you can’t quickly browse that data without a browser plug-in.
16.2.2. Chrome¶
For Chrome, select the drop-down menu in the upper right and click “Settings.”
Then find “Privacy and security”, followed by “Cookies and other site data.”
Finally “See all cookies and site data.”
Finally, find some cookies, expand them out and see the content.
16.3. How do you look at cookies from the developer console?¶
- Firefox: F12, find “Storage” tab. Look on left side for cookies.
- Chrome: F12, find “Application” tab. Look on left side for cookies.
- Edge: F12, find “Debugger” tab. Look on left side for cookies.
16.4. How are cookies really set and transmitted?¶
Remember how HTML has a “head” section? Confusingly, so does HTTP. So if we use HTTP to transfer HTML, the HTTP has a head, and the HTML has a head. They are totally different things.
In the image below, we use the packet tracing tool called Wireshark to see the data. The “red” data is what comes from the web browser. The “blue” data is what comes from the web server. It doesn’t look like HTML because it is compressed/zipped.
There are two major parts to a request from the client, and a response from the server. There’s a request head, and a request body. THen there’s a response head and a response body. The body is optional in some cases, such as this request for a page. There might be a request body if I was sending form data to the server.
Cookies are set and passed back in the HEAD section of the HTTP response.
It is up to the client browser to get that cookie, then send it for every subsequent HTTP request head.
See below for a trace of setting a cookie:
16.5. Cookie Demo¶
We want to show how to read and set cookies two different ways.
- With JavaScript on the front-end.
- With Java on the back-end.
16.5.1. Cookies In Javascript¶
Here’s a screen shot of our end application.
Here is the HTML. Nothing really special here. We have a form that takes in values for the cookie id, and the cookie value that we want to set.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous"> <!-- Pick a theme! https://www.bootstrapcdn.com/bootswatch/ --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/cosmo/bootstrap.min.css"> <title>Cookie Demo Page</title> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <a class="navbar-brand" href="#">Simpson College</a> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <a class="nav-link" href="index.html">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="api/name_list_get">Name List JSON</a> </li> <li class="nav-item"> <a class="nav-link" href="name_list.html">Name List</a> </li> <li class="nav-item"> <a class="nav-link" href="form_demo.html">Form Demo</a> </li> <li class="nav-item active"> <a class="nav-link" href="#">Cookie Demo <span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="container"> <h1>Cookie Demo</h1> <h2>Set Cookie</h2> <div> <input type="text" id="cookieName" placeholder="Cookie Name"> <input type="text" id="cookieValue" placeholder="Cookie Value"> </div> <label for="setCookieJavascript">Front-End JavaScript Set Cookie</label> <button id="setCookieJavascript">Go</button><br /> <label for="setCookieJava">Back-End Java Set Cookie</label> <button id="setCookieJava">Go</button><br /> <h2>Get Cookies</h2> <label for="getCookiesJavaScriptButton">Front-End JavaScript Get Cookie</label> <button id="getCookiesJavaScriptButton">Go</button><br /> <label for="getCookiesJava">Back-End Java Get Cookie</label> <button id="getCookiesJava">Go</button><br /> <pre id="getCookiesResult"> </pre> </div> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script> <script src="js/cookie_demo.js"></script> </body> </html> |
You can read about getting and setting cookies more with W3Schools JavaScript Cookie Page.
Here is our example JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | // This function uses JavaScript to print all our cookies. // It does not use the back-end at all. function getCookiesJavaScript() { // Use a variable called "output" and keep adding things // we want to output to it. var output = "Cookie String\n"; // Cookies are stored in a weird it-is-a-string-but-it-isn't called // document.cookie. "document" is the Document Object Model (DOM) // Here we output it. output += document.cookie; output += "\n"; // Wait, all those cookies are on one line! What if we want // to list the cookies individually? $.each(document.cookie.split(/; */), function() { var splitCookie = this.split('='); var name = splitCookie[0]; var value = splitCookie[1]; if (name.length > 0) output += name + "=" + value + "\n"; }); // Now, set out output field with the 'output' variable. $('#getCookiesResult').html(output); } // Although we don't use this function, if you want to just get a cookie // given a cookie name, here's how you do it. function getByCookie(name) { var value = "; " + document.cookie; var parts = value.split("; " + name + "="); if (parts.length == 2) return parts.pop().split(";").shift(); } // This function will make an AJAX call to the servlet engine // which will then list all the cookies. We'll take what the // server returns and output it to the screen. function getCookiesJava() { var url = "api/get_cookies_servlet"; $.post(url, null, function (dataFromServer) { // Put the results of this call in our result field $('#getCookiesResult').html(dataFromServer) }); } // Want to set a cookie with JavaScript? Here's how! function setCookieJavascriptButton() { var cookieName = $("#cookieName").val(); var cookieValue = $("#cookieValue").val(); // I know all the cookies are stored in "document.cookie" as one // long string. So storing 1 cookie in this string clears all the // old cookies? No! It doesn't. So this isn't really a string. document.cookie = cookieName + "=" + cookieValue + "; SameSite=Lax"; // Clear the form fields. $("#cookieName").val(""); $("#cookieValue").val(""); } // Want to set a cookie with the back-end Java? // Here's how! function setCookieJava() { var url = "api/set_cookie_servlet"; // Grab key/value pair var cookieName = $("#cookieName").val(); var cookieValue = $("#cookieValue").val(); var dataToServer = {cookieName : cookieName, cookieValue : cookieValue}; // Send to server. We'll set it in the java code. $.post(url, dataToServer, function (dataFromServer) { console.log("Finished calling servlet."); console.log(dataFromServer); $("#cookieName").val(""); $("#cookieValue").val(""); }); } // Hook up the buttons var button = $('#getCookiesJava'); button.on("click", getCookiesJava); button = $('#getCookiesJavaScriptButton'); button.on("click", getCookiesJavaScript); button = $('#setCookieJavascript'); button.on("click", setCookieJavascriptButton); button = $('#setCookieJava'); button.on("click", setCookieJava); |
Try it! Click here.
16.5.2. Cookies in Java¶
How do we get/set cookies on the server-side?
The HttpServletRequest
object pointed to by the request
variable has
a method called getCookies()
. This will return a list of the all the cookies.
If there is only one that you want, you need to search the list for it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package edu.simpson.craven; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; @WebServlet(name = "GetCookiesServlet") public class GetCookiesServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); // --- Cookies --- // Get all the cookies Cookie [] cookies = request.getCookies(); // Print how many cookies we have out.println(String.format("%d cookies:", cookies.length)); // Print all the cookies for(Cookie cookie: cookies) { out.println(String.format(" %s = %s",cookie.getName(), cookie.getValue())); out.println(String.format(" Domain = %s",cookie.getDomain())); out.println(String.format(" Path = %s",cookie.getPath())); out.println(String.format(" MaxAge = %s",cookie.getMaxAge())); out.println(String.format(" Secure? = %s",cookie.getSecure())); } } } |
Setting a cookie is a two-step process. You create a Cookie
object, then
add it to the response with response.addCookie()
. You can also set a
cookie age, so it will time out after being unused for a while, or when the
browser closes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package edu.simpson.cis320.crud_app; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; @WebServlet(name = "GetCookieServlet", value = "/api/get_cookies_servlet") public class GetCookiesServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); PrintWriter out = response.getWriter(); // --- Cookies --- // Get all the cookies Cookie [] cookies = request.getCookies(); // Print how many cookies we have out.println(String.format("%d cookies:", cookies.length)); // Print all the cookies for(Cookie cookie: cookies) { out.println(String.format(" %s = %s",cookie.getName(), cookie.getValue())); out.println(String.format(" Domain = %s",cookie.getDomain())); out.println(String.format(" Path = %s",cookie.getPath())); out.println(String.format(" MaxAge = %s",cookie.getMaxAge())); out.println(String.format(" Secure? = %s",cookie.getSecure())); } } } |
16.6. Cookie Limits¶
Cookies (both keys and values) are limited to about 4000 bytes. This limit is TOTAL per domain. So if you have two cookies, together they can’t have more than 4000 bytes. For more information see cookie limits.