Skip to content

Instantly share code, notes, and snippets.

@JamoCA
Last active March 12, 2024 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamoCA/bc34e27704eac277fcaf7053c54912b6 to your computer and use it in GitHub Desktop.
Save JamoCA/bc34e27704eac277fcaf7053c54912b6 to your computer and use it in GitHub Desktop.
ColdFusion SetCookie UDF to add support for samesite. 2024-03-12 Updated to CFScript, removed pre-CF2016 rules, add initial support for CHIPS
<cfscript>
/* 9/15/2010 http://www.modernsignal.com/coldfusionhttponlycookie
<cfset SetCookie(name="logintoken", value="sometoken", secure=true, httponly=true)>
11/1/2019 Updated to add preserveCase & samesite support
Replacement for cfcookie that handles httponly & samesite cookies
3/12/2024 Support for CHIPS Partitioned https://developers.google.com/privacy-sandbox/3pcd/chips
https://community.adobe.com/t5/coldfusion-discussions/setting-partition-with-cfcookie/m-p/14484584#M197250 */
void function setCookie(required string name, required string value, any expires="", boolean secure=false, string path="/", string domain="", boolean httpOnly=false, boolean encodeValue=true, boolean preserveCase=false, string samesite="", boolean partitioned=false) output=false hint="Replacement for cfcookie that handles httponly & samesite cookies" {
// None, Strict, Lax
if (request.isFlushed()){
return;
}
local.cookieData = [];
local.expDate = "";
arguments.name = (arguments.preserveCase) ? arguments.name : ucase(arguments.name);
if (arguments.partitioned){
arguments.secure = true;
arguments.samesite = "none";
arguments.httpOnly = false;
arguments.path = "/";
arguments.name = "__Host-#arguments.name#";
arguments.preserveCase = true;
}
if (arguments.encodeValue){
arrayappend(local.cookieData, "#arguments.name#=#urlencodedformat(arguments.value)#");
} else {
arrayappend(local.cookieData, "#arguments.name#=""#replace(argumments.value,'"','\"')#""");
arrayappend(local.cookieData, "Version=1");
}
switch (arguments.expires){
case "":
break;
case "now":
local.expDate = dateadd("d", -1, now());
break;
case "never":
local.expDate = dateadd("yyyy", 30, now());
break;
case "session":
local.expDate = "";
break;
default:
if (isvalid("date", arguments.expires)){
local.expDate = arguments.expires;
} else if (isnumeric(arguments.expires)){
local.expDate = dateadd("d", arguments.expires, now());
}
break;
}
if (isvalid("date", local.expDate)){
local.expDate = dateconvert("local2Utc", local.expDate);
arrayappend(local.cookieData, "Expires=#datetimeformat(local.expDate, 'ddd, dd mmm yyyy HH:nn:ss')# -0000");
}
if (len(arguments.domain)){
arrayappend(local.cookieData, "Domain=#arguments.domain#");
}
if (len(arguments.path)){
arrayappend(local.cookieData, "Path=#arguments.path#");
}
if (arguments.httponly){
arrayappend(local.cookieData, "HttpOnly");
}
if (listfindnocase("none,strict,lax", trim(arguments.samesite))){
arrayappend(local.cookieData, "SameSite=#trim(arguments.samesite)#");
}
if (arguments.partitioned){
arrayappend(local.cookieData, "Partitioned");
}
if (!len(arguments.expires)){
structdelete(arguments, "Expires");
}
if (arguments.secure || listfindnocase("none", trim(arguments.samesite))){
arrayappend(local.cookieData, "Secure");
}
// generate cfcookie (using params that it allows); Don't use cfcookie to create CHIPS partitioned cookies.
if (!arguments.partitioned){
structdelete(arguments, "partitioned");
cfcookie( attributecollection=arguments );
}
// generate cookie header (this will overwrite cfcookie)
cfheader( name="Set-Cookie", value=trim(arraytolist(local.cookieData, '; ')) & ";");
}
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment