Skip to content

Commit

Permalink
Add persistent cookies
Browse files Browse the repository at this point in the history
  • Loading branch information
Tharuja committed Jan 13, 2020
1 parent c917ba1 commit 7bfacf0
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 39 deletions.
9 changes: 5 additions & 4 deletions stdlib/http/src/main/ballerina/src/http/client_endpoint.bal
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public type Client client object {
var cookieConfigVal = self.config.cookieConfig;
if (cookieConfigVal is CookieConfig) {
if (cookieConfigVal.enabled) {
self.cookieStore = new;
self.cookieStore = new(cookieConfigVal?.persistentStore);
}
}
var result = initialize(url, self.config, self.cookieStore);
Expand Down Expand Up @@ -374,15 +374,16 @@ public type OutboundAuthConfig record {|
# + maxCookiesPerDomain - Maximum number of cookies per domain, which is 50
# + maxTotalCookieCount - Maximum number of total cookies allowed to be stored in cookie store, which is 3000
# + blockThirdPartyCookies - User can block cookies from third party responses and refuse to send cookies for third party requests, if needed
# + enablePersistence - Users are provided with a mechanism for enabling or disabling persistent cookies, which are stored until a specific expiration date.
# If false, only session cookies are used
# + persistentStore - To manage persistent cookies, users are provided with a mechanism for specifying a persistent cookie store with thier own mechanism
# which references the persistent cookie handler or specifying a file path name to be used in the default persistent cookie handler.
# If not specified any, only session cookies are used
public type CookieConfig record {|
boolean enabled = false;
int maxSizePerCookie = 4096;
int maxCookiesPerDomain = 50;
int maxTotalCookieCount = 3000;
boolean blockThirdPartyCookies = true;
boolean enablePersistence = false;
PersistentCookieHandler | string persistentStore?;
|};

function initialize(string serviceUrl, ClientConfiguration config, CookieStore? cookieStore) returns HttpClient|error {
Expand Down
105 changes: 71 additions & 34 deletions stdlib/http/src/main/ballerina/src/http/cookie/cookieStore.bal
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,25 @@
// under the License.

import ballerina/time;
import ballerina/log;

# Represents the cookie store.
#
# + allSessionCookies - Array to store all the session cookies
# + persistentCookieHandler - Persistent cookie handler to manage persistent cookies
public type CookieStore object {

Cookie[] allSessionCookies = [];
PersistentCookieHandler? persistentCookieHandler = ();

public function __init(PersistentCookieHandler | string? persistentStore) {
if (persistentStore is string) {
self.persistentCookieHandler = new DefaultPersistentCookieHandler(persistentStore);
}
if (persistentStore is PersistentCookieHandler) {
self.persistentCookieHandler = persistentStore;
}
}

# Adds a cookie to the cookie store according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.3).
#
Expand All @@ -37,7 +49,7 @@ public type CookieStore object {
path = requestPath.substring(0,index);
}
lock {
Cookie? identicalCookie = getIdenticalCookie(cookie, self.allSessionCookies);
Cookie? identicalCookie = getIdenticalCookie(cookie, self);
if (!isDomainMatched(cookie, domain, cookieConfig)) {
return;
}
Expand All @@ -51,10 +63,10 @@ public type CookieStore object {
return;
}
if (cookie.isPersistent()) {
if (!cookieConfig.enablePersistence) {
return;
var persistentCookieHandler = self.persistentCookieHandler;
if (persistentCookieHandler is PersistentCookieHandler) {
addPersistentCookie(identicalCookie, cookie, url, persistentCookieHandler, self);
}
addPersistentCookie(identicalCookie, cookie, url, self);
} else {
addSessionCookie(identicalCookie, cookie, url, self);
}
Expand Down Expand Up @@ -86,9 +98,12 @@ public type CookieStore object {
if (index is int) {
path = requestPath.substring(0,index);
}
Cookie[] allCookies = self.getAllCookies();
lock {
// Gets the session cookies.
foreach var cookie in self.allSessionCookies {
foreach var cookie in allCookies {
if (isExpired(cookie)) {
continue;
}
if (!((url.startsWith(HTTPS) && cookie.secure) || cookie.secure == false)) {
continue;
}
Expand All @@ -114,7 +129,18 @@ public type CookieStore object {
#
# + return - Array of all the cookie objects
public function getAllCookies() returns Cookie[] {
return self.allSessionCookies;
var persistentCookieHandler = self.persistentCookieHandler;
Cookie[] allCookies = [];
foreach var cookie in self.allSessionCookies {
allCookies.push(cookie);
}
if (persistentCookieHandler is PersistentCookieHandler) {
Cookie[] persistentCookies = persistentCookieHandler.getCookies();
foreach var cookie in persistentCookies {
allCookies.push(cookie);
}
}
return allCookies;
}

# Removes a specific cookie.
Expand All @@ -124,29 +150,40 @@ public type CookieStore object {
# + path - Path of the cookie to be removed
# + return - Return true if the relevant cookie is removed, false otherwise
public function removeCookie(string name, string domain, string path) returns boolean {
lock {
// Removes the session cookie in the cookie store, which is matched with the given name, domain and path.
int k = 0;
while (k < self.allSessionCookies.length()) {
if (name == self.allSessionCookies[k].name && domain == self.allSessionCookies[k].domain && path == self.allSessionCookies[k].path) {
int j = k;
while (j < self.allSessionCookies.length()-1) {
self.allSessionCookies[j] = self.allSessionCookies[j + 1];
j = j + 1;
}
_ = self.allSessionCookies.pop();
return true;
}
k = k + 1;
}
return false;
}
lock {
// Removes the session cookie if it is in the session cookies array, which is matched with the given name, domain and path.
int k = 0;
while (k < self.allSessionCookies.length()) {
if (name == self.allSessionCookies[k].name && domain == self.allSessionCookies[k].domain && path == self.allSessionCookies[k].path) {
int j = k;
while (j < self.allSessionCookies.length()-1) {
self.allSessionCookies[j] = self.allSessionCookies[j + 1];
j = j + 1;
}
_ = self.allSessionCookies.pop();
return true;
}
k = k + 1;
}
// Removes the persistent cookie if it is in the persistent cookie store, which is matched with the given name, domain and path.
var persistentCookieHandler = self.persistentCookieHandler;
if (persistentCookieHandler is PersistentCookieHandler) {
return persistentCookieHandler.removeCookie(name, domain, path);
} else {
log:printError("No such cookie to remove");
return false;
}
}
}

# Removes all the cookies.
public function clear() {
var persistentCookieHandler = self.persistentCookieHandler;
lock {
self.allSessionCookies = [];
if (persistentCookieHandler is PersistentCookieHandler) {
persistentCookieHandler.clearAllCookies();
}
}
}
};
Expand Down Expand Up @@ -177,14 +214,14 @@ function getDomain(string url) returns string {
# Identical cookie is the cookie, which has the same name, domain and path as the given cookie.
#
# + cookieToCompare - Cookie to be compared
# + allSessionCookies - Array which stores all the session cookies
# + cookieStore - Cookie store of the client
# + return - Identical cookie if one exists, else `()`
function getIdenticalCookie(Cookie cookieToCompare, Cookie[] allSessionCookies) returns Cookie? {
// Searches for the session cookies.
function getIdenticalCookie(Cookie cookieToCompare, CookieStore cookieStore) returns Cookie? {
Cookie[] allCookies = cookieStore.getAllCookies();
int k = 0 ;
while (k < allSessionCookies.length()) {
if (cookieToCompare.name == allSessionCookies[k].name && cookieToCompare.domain == allSessionCookies[k].domain && cookieToCompare.path == allSessionCookies[k].path) {
return allSessionCookies[k];
while (k < allCookies.length()) {
if (cookieToCompare.name == allCookies[k].name && cookieToCompare.domain == allCookies[k].domain && cookieToCompare.path == allCookies[k].path) {
return allCookies[k];
}
k = k + 1;
}
Expand Down Expand Up @@ -262,7 +299,7 @@ function isExpiresAttributeValid(Cookie cookie) returns boolean {
}

// Adds a persistent cookie to the cookie store according to the rules in [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.3 , https://tools.ietf.org/html/rfc6265#section-4.1.2).
function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url, CookieStore cookieStore) {
function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url, PersistentCookieHandler persistentCookieHandler, CookieStore cookieStore) {
if (identicalCookie is Cookie) {
var temp1 = identicalCookie.name;
var temp2 = identicalCookie.domain;
Expand All @@ -275,15 +312,15 @@ function addPersistentCookie(Cookie? identicalCookie, Cookie cookie, string url,
_ = cookieStore.removeCookie(temp1, temp2, temp3);
cookie.creationTime = identicalCookie.creationTime;
cookie.lastAccessedTime = time:currentTime();
// TODO:insert into the database.
persistentCookieHandler.storeCookie(cookie);
}
}
} else {
// If cookie is not expired adds that cookie.
if (!isExpired(cookie)) {
cookie.creationTime = time:currentTime();
cookie.lastAccessedTime = time:currentTime();
// TODO:insert into the database.
persistentCookieHandler.storeCookie(cookie);
}
}
}
Expand Down Expand Up @@ -322,7 +359,7 @@ function addSessionCookie(Cookie? identicalCookie, Cookie cookie, string url, Co
cookie.creationTime = identicalCookie.creationTime;
cookie.lastAccessedTime = time:currentTime();
cookieStore.allSessionCookies.push(cookie);
}
}
} else {
// Adds the session cookie.
cookie.creationTime = time:currentTime();
Expand Down
Loading

0 comments on commit 7bfacf0

Please sign in to comment.