C++ 如何在ISAPI筛选器中设置多个cookie

C++ 如何在ISAPI筛选器中设置多个cookie,c++,winapi,iis,cookies,isapi,C++,Winapi,Iis,Cookies,Isapi,我在ISAPI过滤器中设置多个cookie时遇到了一个问题。我想在所有cookie中添加HttpOnly标志 因此,在我的第一次尝试中,我分割cookies值并添加HttpOnly标志,然后将它们组合成一个字符串,调用pResponse->SetHeader(pfc,“Set Cookie:,szNewValue),最后,浏览器只获得第一个Cookie值 第一次尝试的代码: cbValue = sizeof(szValue) / sizeof(szValue[0]); if (p

我在ISAPI过滤器中设置多个cookie时遇到了一个问题。我想在所有cookie中添加
HttpOnly
标志

因此,在我的第一次尝试中,我分割cookies值并添加
HttpOnly
标志,然后将它们组合成一个字符串,调用
pResponse->SetHeader(pfc,“Set Cookie:,szNewValue)
,最后,浏览器只获得第一个Cookie值

第一次尝试的代码:

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:","");
            }
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);
            }
在第二次尝试中,我分割了cookie值,并为每个cookie调用
pResponse->SetHeader(pfc,“Set cookie:”,szNewValue)
,但在这种情况下,浏览器只获取最后一个cookie

第二次尝试的代码:

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:","");
            }
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);
            }
我在IE10+Win2008 R2中这样做。在这两种情况下,结果cookie字符串的格式都正确。有人对此有任何线索吗


这个问题的存在主要是因为当您调用
GetHeader
时,您会在一个逗号分隔的字符串中收到所有cookie。使用
SetHeader
方法将所有Cookie设置回响应的最佳方法是什么?

您的第一次尝试比第二次更好,因为您应该只设置一次头。我认为您的字符串解析算法有点不正确。我会尽量简化一些。首先将每个cookie的头拆分为字符串。然后根据需要修改cookie以添加http only属性,然后将cookie合并回单个头中

我正在寻找这个问题的解决方案,发现了很多不正确的回答

这篇文章让我找到了解决办法

原始发布的解决方案不起作用,因为它对每个cookie使用SetHeader。SetHeader每次调用时都会替换“Set Cookie:”标头,因此只设置了最后一个Cookie。我没有使用SetHeader,而是对每个cookie使用AddHeader。但是,在第一次使用AddHeader之前,我使用带有“”的SetHeader来“清空”Set Cookie:“header”

这对我使用IIS5.1和IIS7.0有效

此解决方案也适用于ASP会话Id cookie

我知道经典ASP是一项古老的技术,但它仍然在使用,我们需要这样的解决方案

这是我的完整代码:

#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;
}
#包括
#包括
#包括
#包括
BOOL-WINAPI\uuustdcall-getfiltervision(HTTP\ufilter\uversion*pVer)
{
pVer->dwFlags=SF_NOTIFY_SEND_RESPONSE | SF_NOTIFY_ORDER|u HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT;
pVer->dwfiltervision=HTTP\u FILTER\u REVISION;
strcpy_s(pVer->lpszFilterDesc,sizeof(pVer->lpszFilterDesc),“httpOnly过滤器,版本1.0.jcgalvevzv”);
返回TRUE;
}
DWORD WINAPI标准调用HttpFilterProc(HTTP过滤器上下文*pfc,DWORD通知类型,VOID*pvData)
{
德沃德缓冲区;
char-lszBuffer[2000],lszNewBuffer[2000];
HTTP_FILTER_PREPROC_HEADERS*pFPH=(HTTP_FILTER_PREPROC_HEADERS*)pvData;
开关(NotificationType)
{
案例SF\u通知\u发送\u响应:
cbBuffer=sizeof(lszBuffer);
if(pFPH->GetHeader(pfc,“设置Cookie:”、lszBuffer和cbBuffer))
{
char*token=NULL;
char*context=NULL;
char delim[]=“,”;
//删除以前的Cookie
pFPH->SetHeader(pfc,“设置Cookie:”,”);
令牌=strtok_s(lszBuffer、delim和context);
while(令牌!=NULL)
{
strcpy_s(lszNewBuffer,sizeof(lszNewBuffer),令牌);
如果(!strstr(令牌,“httpOnly”))
strcat_s(LSZNEWBUFER,sizeof(LSZNEWBUFER),“仅限httpOnly”);
//AddHeader而不是SetHeader。
pFPH->AddHeader(pfc,“设置Cookie:”,lszNewBuffer);
//下一个标记
token=strtok_s(NULL、delim和context);
}
}
打破
违约:
打破
}
返回SF_状态_请求_下一个_通知;
}

我遇到了同样的问题,我需要与Microsoft联系以解决此问题。当您收到多个cookie时,您将收到一个完整的字符串,其中所有cookie用逗号分隔。 这项工作包括分离每个cookie,然后分别为每个cookie调用SetHeader方法

重要的是,每个cookie必须具有唯一的名称-值对(),以便可以正确映射每个更改

伪码的求解

pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue)

// split cookies here

foreach separated cookie
    pResponse->SetHeader(pfc, "Set-Cookie:", oneCookie)
这样,您就不需要清除所有cookie来再次添加它们。

您应该使用
\u countof(lszNewBuffer)
而不是
sizeof(lszNewBuffer)
使用
strcpy\u s
strcat\u s
,因为它需要的是字符数,而不是字节数。在这里它起作用是因为两个字符串是相等的。