(* Mosmlcookie.sml v 2.0 2000-01-12 (c) Hans Molin, Computing Science Dept., Uppsala University, 1999. http://www.csd.uu.se/~d97ham/ d97ham@csd.uu.se Documentation, cleanup and efficiency improvements by sestoft@dina.kvl.dk Anyone is granted the right to copy and/or use this code, provided that this note is retained, also in modified versions. The code is provided as is with no guarantee about any functionality. I take no responsibility for its proper function. *) exception CookieError of string type cookiedata = { name : string, value : string, expiry : Date.date option, domain : string option, path : string option, secure : bool } val http_cookie = Process.getEnv("HTTP_COOKIE"); local fun is c1 c2 = c1 = c2 (* Create list of all name=value pairs *) val allCookies : string list = let open Substring fun removeBWS sus = concat (fields (is #" ") sus) in List.map removeBWS (tokens (is #";") (all (Option.getOpt(http_cookie, "")))) end (* Return (name, value) for the desired cookie name *) fun lookupcookie cookie : (string * substring) option = let open Substring fun matchCookie (x::xr)= let val (pref, suff) = position "=" (all x) in if string pref = cookie then SOME (x, suff) else matchCookie xr end | matchCookie [] = NONE in matchCookie allCookies end in fun getCookieValue cookie : string option = let fun (f o g) x = f (g x) open Substring Option in map (string o triml 1 o #2) (lookupcookie cookie) end fun getCookie cookie : string option = let open Substring Option in map #1 (lookupcookie cookie) end val allCookies = allCookies end (* Note that Date is a record. The ctime(3) format Wdy Mon DD HH:MM:SS YYYY (as generated by Date.toString) is not acceptable because it is not a valid RFC-822 date. No whitespaces are allowed in any string. *) fun concatOpt s NONE = "" | concatOpt s (SOME t) = s ^ t fun setCookie { name : string, value : string, expiry : Date.date option, domain : string option, path : string option, secure : bool } = let fun datefmt date = Date.fmt "%A, %d-%b-%Y %H:%M:%S %Z" date in if name = "" orelse value= "" then raise CookieError "Name or value empty in call to setCookie" else String.concat ["Set-cookie: ", name, "=", value, concatOpt "; expires=" (Option.map datefmt expiry), concatOpt "; domain=" domain, concatOpt "; path=" path, "; secure=", Bool.toString secure, "\n"] end (* To set multiple cookies *) fun setCookies cookies = String.concat (List.map setCookie cookies) (* To set one cookie *) fun setCookie cookie = setCookies [cookie] (* A CGI script can delete a cookie by returning (setting) a cookie with the same name and an expiry time which is in the past. The path and name must match exactly in order for the expiring cookie to replace the valid cookie. This requirement makes it difficult for anyone but the originator of a cookie to delete a cookie. *) fun deleteCookie { name : string, path : string option } : string = String.concat["Set-cookie: ", name, "=deleted;", "expires=Friday, 11-Feb-77 12:00:00 GMT", concatOpt "; path=" path, "\n"]