Managing HTTP Cookies in Ballerina

Tharuja Sandeepanie
6 min readApr 20, 2020

--

By this article, I am going to explain you how to manage HTTP Cookies using Ballerina language. If you are interested in using Ballerina language into your project and need to use HTTP Cookies in it, then I hope this article will help you for it in the best way.

Ballerina is a general-purpose programming language designed for network distributed application development.It is currently being developed by WSO2. For more details about Ballerina — link.

From my previous article, I indicated some basic facts regarding HTTP Cookies. You can go through it if you feel ,you have less understanding about HTTP Cookies :- link

Ballerina supports both Server side APIs and Client side APIs to you in order to manage HTTP Cookies. Further more , It gives you to support both session and persistent cookies. All these APIs in Ballerina are developed according to the RfC — 6265 specification (HTTP State Management Mechanism)

I will explain step by step how to use HTTP Cookies using Ballerina language from both server side and client side.But before this I want you to be familiar with HTTP client & server implementations in Ballerina . For that you can refer this site :- link

Server-side APIs

  • Server can create a new cookie , assign values for its attributes and add it to server’s response as follows.
http:Cookie cookie1 = new("SID001", "239d4d34");
cookie1.path = "/sample";
cookie1.domain = "localhost:9253";
cookie1.httpOnly = true;
cookie1.secure = true;
cookie1.expires = "2030-06-26 05:46:22";
cookie1.maxAge = 36000;
http:Response res = new;
res.addCookie(cookie1); // Add a cookie into Response.

Note that Ballerina has provided a separate object called “Cookie” inside the HTTP module to be used when you are managing cookies .

Make sure that you assign valid attribute values according to the RfC-6265 spec , otherwise it will trigger an error message and cookie will not be added into the response. Things to be considered :- Name and Values of the cookie must be given when creating a new cookie……, Blank values can not be assigned to any attribute……, Path value must be started with “/” and it must not contain query strings….., Expires values must conform with the yyyy-mm-dd hh:mm:ss format and maxAge value should not be less than zero.

After add this cookie into the response, It will add a header named “Set-Cookie” with indicating all the cookie values inside the HTTP response.

  • Server can remove a specific cookie from the client’s cookie store as follows. Here, when removing cookies by server, “expires” attribute value of the cookies which server wants to remove will be set to a past date and send those cookies under separate “Set-Cookie” headers in the response.
http:Response res = new;
res.removeCookiesFromRemoteStore(cookie1);
  • Server can obtain cookies from the inbound request as follows. Note that Cookies are sent in the request under “Cookie” header as a string and here an array of cookie objects parsed from this string value will be returned when calling this API.
http:Cookie[] reqstCookies = request.getCookies();

Client-side APIs

  • Client can enable cookies in the client configuration when creating the client as follows.
http:Client cookieClientEndpoint = new ("http://localhost:9253", {cookieConfig: { enabled: true }});

When a user enables for cookies, a cookie store will be initialized for each client. This cookie store acts as a place where all the cookies (both session and persistent) can be stored.

Specificity of the cookie client is when a user sends a request to a server, before sending it, it checks whether there are any cookies in the cookie store which have been sent earlier by that server. If so, it sends those cookies under the “Cookie” header in the request to that server with indicating the cookie name & value. The order of cookies included in the Cookie header is according to the rules in RfC-6265 specification.

After sending the cookies to the server, then server may send the response with or without cookies. So, before returning the response to the client, client gets the cookies from the response if there are and add those cookies into the cookie store (according to the rules in RfC-6265 specification) . Then after the response is returned to the client.

Even though client sends multiple requests concurrently, adding cookies to cookie store for each request is done one after the other because of the concurrency management of cookies in Ballerina.

So, that is the process happening when sending requests and responses when a client enables cookies as above.

  • Client can define maximum number of cookies per domain, maximum total number of cookies stored in the cookie store (according to his needs) and whether to block or unblock third party cookies by using the cookie configurations as below.
http:Client cookieClientEndpoint = new ("http://localhost:9253", {cookieConfig: { enabled: true, 
maxCookiesPerDomain: 20,
maxTotalCookieCount: 1000,
blockThirdPartyCookies: true
}
});

Here, when adding a cookie to cookie store, if cookies per domain or total number of cookies in the cookie store exceeds the above configured values, it will return an error to the user with giving a message.

  • If a client wants to store cookies persistently, he must assign either a CsvPersistentCookieHandler object or his own mechanism used object with referring the PersistentCookieHandler abstract object to the field- “persistentCookieHandler” in cookie configuration record.
// Creates CsvPersistentCookieHandler object.
http:CsvPersistentCookieHandler myPersistentStore = new("./test/myFile.csv");
http:Client cookieClientEndpoint = new ("http://localhost:9253", {cookieConfig: { enabled: true,
persistentCookieHandler : myPersistentStore }
});

Here, when creating CsvPersistentCookieHandler object user must give a csv file name to where the cookies should be stored. Because of this, separate csv files can be created to store cookies for each cookie client.

Note that Ballerina has provided an abstract object named PersistentCookieHandler and also a CsvPersistentCookieHandler object inside HTTP module.

If client wants to store persistent cookies with his own mechanisms ( using a database or a file system…etc) he should create an object by referring the PersistentCookieHandler abstract object with implementing all the following methods.

public function storeCookie(Cookie cookie) returns CookieHandlingError?;public function getAllCookies() returns Cookie[]|CookieHandlingError;public function removeCookie(string name, string domain, string path) returns CookieHandlingError?;public function removeAllCookies() returns CookieHandlingError?;

For the clients who don’t want to write their own implementation, can use CsvPersistentCookieHandler object directly which can store persistent cookies as records in a csv file . (as above example) So that is the default PersistentCookieHandler object given by Ballerina with referring the PersistentCookieHandler abstract object. It has all built in methods to write cookie objects to the file, read cookie objects from the file, remove a specific cookie from the file and clear all persistent cookies. So, you don’t need to write your own methods to store persisgtent cookie because of this.

  • If a client is not configured to use persistent cookies and the server sends persistent cookies, he will get a warning message about persistent cookies for his first request as follows.
log:printWarn ("Client is not configured to use persistent cookies. Hence, persistent cookies from "<domain name>" will be discarded.");
  • Client can remove a specific session or persistent cookie by specifying the cookie name, domain and path respectively.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
var removeResult = myCookieStore.removeCookie("SID001","localhost:9253", "/cookie/cookieBackend_1");
if (removeResult is error) {
io:println(removeResult);
}
}
  • Client can remove all the session and persistent cookies as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
var removeResult = myCookieStore.removeAllCookies();
if (removeResult is error) {
io:println(removeResult);
}
}
  • Client can remove all the expired cookies as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
var result = myCookieStore.removeCookiesByDomain("google.com");
if (result is error) {
io:println(result);
}
}
  • Client can remove cookies by domain as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
var result = myCookieStore.removeCookiesByDomain("google.com");
if (result is error) {
io:println(result);
}
}
  • Client can retrieve all the cookies in the cookie store as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
http:Cookie[] cookies = myCookieStore.getAllCookies();
}
  • Client can get the cookies by domain as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
http:Cookie[] cookies = myCookieStore.getCookiesByDomain("google.com");
}
  • Client can get the cookies by cookie name as follows.
http:CookieStore? myCookieStore = clientEndpoint.getCookieStore()
if (myCookieStore is http:CookieStore) {
http:Cookie[] cookies = myCookieStore.getCookiesByName("SID002");
}

Hope, this will be helpful for you if you have a need to use HTTP Cookies using Ballerina language. Thank You..!!

--

--