I faced a problem to set multiple cookies in ISAPI filter. I want to add the HttpOnly
flag into all cookies.
So, in my first attempt, I split the cookies value and add the HttpOnly
flag, then I combine them into one string, invoke pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue)
in the end, the browser only get first cookie value.
Code of 1st attempt:
cbValue = sizeof(szValue) / sizeof(szValue[0]);
if (pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue))
{
char szNewValue[MAX_URI_SIZE] = "";
char* token = NULL;
char* context = NULL;
char delim[] = ",";
// szValue format like
// "Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
// After first split
// token = "Language=en; expires=Sat"
// context = " 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
token = strtok_s(szValue, delim, &context);
while (token != NULL)
{
strcat_s(szNewValue, token);
if (NULL != context)
{
if (' ' != context[0] && !strstr(token, "HttpOnly"))
{
strcat_s(szNewValue, "; HttpOnly");
}
// context[0] = ' ' means it split the one whole cookie, not an entire cookie, we need append ","
// context[0] != '\0' means other cookies after, we need append delimiter ","
if (' ' == context[0] || '\0' != context[0])
{
strcat_s(szNewValue, ",");
}
}
// NULL, function just re-uses the context after the first read.
token = strtok_s(NULL, delim, &context);
}
if (!pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue))
{
// Fail securely - send no cookie!
pResponse->SetHeader(pfc,"Set-Cookie:","");
}
In the second attempt, I split the the cookie value, and invoke pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue)
for every cookie, but the browser only get the last cookie in this case.
Code of 2nd attempt:
cbValue = sizeof(szValue) / sizeof(szValue[0]);
if (pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue))
{
char szNewValue[MAX_URI_SIZE] = "";
char* token = NULL;
char* context = NULL;
char delim[] = ",";
// szValue format like
// "Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
// After first split
// token = "Language=en; expires=Sat"
// context = " 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
token = strtok_s(szValue, delim, &context);
while (token != NULL)
{
strcat_s(szNewValue, token);
if (NULL != context)
{
if (' ' != context[0] && !strstr(token, "HttpOnly"))
{
strcat_s(szNewValue, "; HttpOnly");
}
// context[0] = ' ' means it split the one whole cookie, not an entire cookie, we need append ","
// context[0] != '\0' means other cookies after, we need append delimiter ","
if (' ' == context[0])// || '\0' != context[0])
{
strcat_s(szNewValue, ",");
}
if (' ' != context[0])
{
pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue);
strcpy(szNewValue, "");
}
}
// NULL, function just re-uses the context after the first read.
token = strtok_s(NULL, delim, &context);
}
I do this in IE10+Win2008 R2. In both two cases, the result cookie strings are in correct format. Does anyone have any clue about this?
This problem exists basically because when you invoke GetHeader
, you receive all cookies in one comma delimited string. What would be the best way to use SetHeader
method to set all cookies back to the response?
I was searching for a solution to this issue and found a lot of incorrect responses.
This post was what got me to the solution.
The original posted solution didn't work because it was using SetHeader for each cookie. SetHeader replaces the "Set-Cookie:" header each time it is called so only the last Cookie was set. Instead of using SetHeader, what I did was to use AddHeader for each cookie. But, before using AddHeader for the first time I used SetHeader with "" to "empty" the "Set-Cookie:" header.
This worked for me using IIS5.1 and IIS7.0
This solution works for ASP Session Id cookie too.
I know Classic ASP is an old technology, but it is still in use and we need solutions like this.
Here is my complete code:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <httpfilt.h>
BOOL WINAPI __stdcall GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
pVer->dwFlags = SF_NOTIFY_SEND_RESPONSE | SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT;
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy_s(pVer->lpszFilterDesc, sizeof(pVer->lpszFilterDesc), "httpOnly Filter, Version 1.0. JCGalvezV.");
return TRUE;
}
DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData)
{
DWORD cbBuffer;
char lszBuffer[2000], lszNewBuffer[2000];
HTTP_FILTER_PREPROC_HEADERS *pFPH = (HTTP_FILTER_PREPROC_HEADERS *)pvData;
switch (NotificationType)
{
case SF_NOTIFY_SEND_RESPONSE :
cbBuffer = sizeof(lszBuffer);
if (pFPH->GetHeader(pfc, "Set-Cookie:", lszBuffer, &cbBuffer))
{
char* token = NULL;
char* context = NULL;
char delim[] = ",";
// Delete previous cookies
pFPH->SetHeader(pfc, "Set-Cookie:", "");
token = strtok_s(lszBuffer, delim, &context);
while (token != NULL)
{
strcpy_s(lszNewBuffer, sizeof(lszNewBuffer), token);
if (!strstr(token, "httpOnly"))
strcat_s(lszNewBuffer, sizeof(lszNewBuffer), "; httpOnly");
// AddHeader instead of SetHeader.
pFPH->AddHeader(pfc, "Set-Cookie:", lszNewBuffer);
// next token
token = strtok_s(NULL, delim, &context);
}
}
break;
default :
break;
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
I had the same problem and I needed to contact Microsoft to solve this issue. When you receive multiple cookies, you will receive a full string with all the cookies separated by commas. The work consists of separating each cookie and then call the SetHeader method for each separately.
The important thing is that each cookie must have a unique name-value pair (http://www.quirksmode.org/js/cookies.html) so each change can be properly mapped.
The solution in pseudocode
pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue)
// split cookies here
foreach separated cookie
pResponse->SetHeader(pfc, "Set-Cookie:", oneCookie)
That way, you don't need to clean all cookies to add them again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With