/* This web application demonstrates using cookies to store state. */ webapp cookie; import Webapp; import HTMLDocument; // this stores the user state data User(String username, Int visited); globals { // this isn't ideal, but it makes the rest of the code simpler HTMLDocument doc; } HTMLDocument webmain() { doc = new(HTML4Strict,"Cookie demonstration"); // for simplicity, the entire page is generated in the handler // in a real application, there'd probably be some template code // above and below this call appendExisting(doc.body, retrieveFunction(@notLoggedIn, cookieRetriever, "cookie_example_login")); source = addParagraph(doc.body,"Read the "); void(appendInlineElement(source,Hyperlink("../files/cookie.k"),"source code")); return doc; } // this is the default function if the cookie doesn't exist. ElementTree notLoggedIn() { // if the form has been submitted if (incomingExists("username",DataPost)) { // then log in user = incomingValue("username",DataPost); // and switch to the logged-in handler return loggedIn(User(user,0)); } else { // otherwise display the log in form content = anonymousBlock; void(addHeading(content,1,"Please log in")); void(addParagraph(content,"You are not logged in. Please make up a username and log in to see the rest of this application.")); form = addLocalForm(content); f1 = addFieldset(form,"Log in"); void(addLabelledInput(f1,"Username",InputText,"username","",10)); void(addRemoteControlInput(f1,InputSubmit,"","Log in")); return content; } } ElementTree loggedIn(User user) { if (incomingExists("logout",DataGet) && !incomingExists("username",DataPost)) { // erase the login cookie if (incomingExists("logout",DataGet)) { addHTTPHeader(doc,setCookie("cookie_example_login","")); } // the second half of the condition should always be false, but // if it's not included, someone could mischievously send the // application into an infinite loop. return notLoggedIn(); // anyway, if they're logging out, print the log in form // we've already deleted the cookie above. } else { // but usually, it'll just be a page. content = anonymousBlock(); // keep track of the number of pages visited, just to prove that // state can be updated as the user navigates the application user.visited++; void(addParagraph(content,"Hello "+user.username+". You have viewed "+user.visited+" pages this session.")); // while logged in, the page parameter says what page to view. if (incomingExists("page",DataGet)) { pageid = Int(incomingValue("page",DataGet)); } else { pageid = 100; } // now show the page-specific content showPage(content,pageid); logout = addParagraph(content,"When you're finished, "); void(appendInlineElement(logout,Hyperlink(webappName()+"?logout"),"log out")); void(storeFunction(cookieStorer@(doc),@loggedIn,user)); return content; } } Void linkToPage(ElementTree list, Int linkid) { li = pushListItem(list,"Go to "); void(appendInlineElement(li,Hyperlink(webappName()+"?page="+linkid),"page "+linkid)); } Void showPage(ElementTree content, Int pageid) { cpage = addParagraph(content,"You are now on page "+pageid+"."); if (pageid == 1) { addString(cpage," Well done - you found page 1! You can log out and try to find it again in fewer moves if you're really bored."); // Exercise for the reader: modify this application so that a visitor // can't cheat and go straight to page 1 by changing the URL. Fixing // things like this is a crucial part of web application security. // Hint: you will probably need to expand the state data type a bit } else { addString(cpage," If you get bored, try to find page 1."); } // add some navigation to simulate links to the next stages of the // application. ul = addList(content,Unordered,0); if (pageid % 2 == 0) { linkToPage(ul,pageid/2); } else { linkToPage(ul,(pageid*7)+1); } if (pageid % 5 == 1) { linkToPage(ul,pageid+4); } else { linkToPage(ul,pageid+10); } if (pageid % 3 == 0) { linkToPage(ul,(pageid*2)-1); } else if (pageid % 3 == 1) { linkToPage(ul,pageid-13); } else { linkToPage(ul,pageid/3); } if (pageid < 10) { linkToPage(ul,pageid*pageid); } else if (pageid > 1000) { linkToPage(ul,pageid/20); } } String cookieStorer(HTMLDocument hdoc, String state) { cookie = setCookie("cookie_example_login",state); addHTTPHeader(hdoc,cookie); return "cookie_example_login"; } String cookieRetriever(String key) { return incomingValue(key,DataCookie); }