Bitty HTTP

Development » Cookies

1Using Cookies

This example will show reading and setting cookies from the server. Reading cookies are basically the same as GET vars but using WS_COOKIE() instead of WS_GET()

Bitty HTTP stores cookie values in a block of RAM as the headers are processed (just after the POST vars). This means it needs to know the names of all the COOKIES before the page is requested. This is done by filling in the struct WSPageProp.Cookies variable when the page properties are requested.

The Cookies property (just like the Gets) is an array of pointers to strings with the last one being set to NULL to mark the end of the list. This list is scanned when the page is requested and the value of any vars in this list are added to a RAM array.

You then call WS_COOKIE() to get the value that was saved (or NULL if it wasn't found).

Using things this way means a low memory foot print as we only remember vars that we are going to pull out later.

Files

FileServer.c

The file server is changed to display the number of times the page has been reloaded. It uses a session cookie for the reload count, and a cookie set to expire in 7 days for the all time reload count.

const char *CookieArgs[]= { "LoadCount", "LoadCountAllTime", NULL };

We add a list of COOKIES that we may want to read when processing a page later. We end the list with NULL to mark the end of the list. The code will loop though this list looking for a NULL entry to stop at.

When a match is made the value of the var will be copied to an internal RAM buffer.

struct FileInfo m_Files[]= { /* Filename, Dynamic, Cookies, Gets, Posts, Callback */ {"/",true,CookieArgs,NULL,NULL,File_Root}, {"/SomeStyle.css",false,NULL,NULL,NULL,File_SomeStyle}, {"/quit.html",true,NULL,NULL,NULL,File_Quit}, };

This include only the normal pages (SomeStyle.css, quit.html, and root) The root page includes a pointer to the Cookies as the 3'rd argument. If you wanted to use GET or POST vars as well you would provide pointers to different arrays (one for POST or one for the GET vars).

const char DisplayHTML_Start[]= "<!DOCTYPE html>" "<html>" "<head>" "<title>Bitty HTTP - Root</title>" "<link rel='stylesheet' href='/SomeStyle.css'>" "</head>" "<body>" "<div id='top'>Bitty HTTP Example - Root</div>" "<div id='quitbttn'><a href='/quit.html'>QUIT</a></div>" "<div id='content'>"; const char DisplayHTML_End[]= "</div>" "<div id='bottom'></div>" "</body>" "</html>"; void File_Root(struct WebServer *Web) { char buff[100]; const char *LoadCount; const char *LoadCountAllTime; int LoadCountInt; int LoadCountAllTimeInt; LoadCount=WS_COOKIE(Web,"LoadCount"); if(LoadCount==NULL) LoadCountInt=0; else LoadCountInt=atoi(LoadCount); LoadCountAllTime=WS_COOKIE(Web,"LoadCountAllTime"); if(LoadCountAllTime==NULL) LoadCountAllTimeInt=0; else LoadCountAllTimeInt=atoi(LoadCountAllTime); LoadCountInt++; sprintf(buff,"%d",LoadCountInt); WS_SetCookie(Web,"LoadCount",buff,0,NULL,NULL,false,false); LoadCountAllTimeInt++; sprintf(buff,"%d",LoadCountAllTimeInt); /* Expires in a week (60 sec * 60 min * 24 hours * 7 days) */ WS_SetCookie(Web,"LoadCountAllTime",buff,time(NULL)+60*60*24*7,NULL, NULL,false,false); WS_WriteChunk(Web,DisplayHTML_Start,sizeof(DisplayHTML_Start)-1); sprintf(buff,"Page loaded:%d times this session, and %d this week<br/>", LoadCountInt,LoadCountAllTimeInt); WS_WriteChunk(Web,buff,strlen(buff)); WS_WriteChunk(Web,DisplayHTML_End,sizeof(DisplayHTML_End)-1); }

This page starts by reading the LoadCount cookie. Using the WS_COOKIE() function. WS_COOKIES() returns a string so it will need to be converted to an int before we can work with it.

We first check that this cookie was found, and if not we set our var LoadCountInt to 0. If it was found then we use atoi() to convert it to an int.

Next we do the same for the LoadCountAllTime cookie placing the int in LoadCountAllTimeInt.

We then add 1 to LoadCountInt and convert it back to a string in buff. We then call WS_SetCookie() to output a cookie.

The WS_SetCookie() has the following prototype:

bool WS_SetCookie(struct WebServer *Web,const char *Name,const char *Value,time_t Expire,const char *Path,const char *Domain,bool Secure,bool HttpOnly);

Name is the name of the cookie
Value is the value to set the cookie to as a string
Expire is a unix timestamp of when this cookie will expire. If it is set to 0 then it will be a session cookie.
Path is the path that this cookie is valid, NULL means it will be ignored.
Domain is domain that this cookie is valid, NULL means it will be ignored.
Secure is a bool that makes this cookie a secure cookie
HttpOnly is a bool that makes this cookie only avaiable to the server.

For more details see the auto doc for WS_SetCookie()

We set the LoadCount cookie as a session cookie and set it's value to the buffer we just made.

We repeat the same thing for the LoadCountAllTime cookie, except with this cookie we set the expiry date as a week from now. We do this by calling the time.h function time() and add the number of seconds in a week (60*60*24*7 or 604800 seconds).

Because the cookies must be set before the body is written we do this all before we call WS_WriteChunk() with the top part of the web page.

We then output a string telling the user how many times this page has been loaded, and finish off the page.