【问题标题】:Faulting DLL (ISAPI Filter)错误的 DLL(ISAPI 过滤器)
【发布时间】:2010-03-12 21:30:00
【问题描述】:

我编写了这个 ISAPI 过滤器来重写 URL,因为我们有一些移动位置的网站......基本上过滤器会查看引荐来源网址,如果是本地服务器,它会查看请求的 URL 并将其与完整的 URL 进行比较推荐人。如果第一个路径相同,则不执行任何操作,但如果不是,则从完整引用者中获取第一个路径并将其添加到 URL 前面。例如:来自 http://myserver/wr/apps/default.htm 的引用者的 /Content/imgs/img.jpg 将被重写为 /wr/Content/imgs/img.jpg。

当我查看日志文件时,一切看起来都很好。但是,DLL 不断出现以下信息错误:错误应用程序 w3wp.exe,版本 6.0.3790.3959,错误模块 URLRedirector.dll,版本 0.0.0.0,错误地址 0x0002df25。

代码如下:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <httpfilt.h>
#include <time.h>
#include <string.h>


#ifdef _DEBUG
#define TO_FILE  // uncomment out to use a log file
#ifdef TO_FILE
#define DEST ghFile
#define DebugMsg(x) WriteToFile x;
HANDLE ghFile;
#define LOGFILE "W:\\Temp\\URLRedirector.log"
void WriteToFile (HANDLE hFile, char *szFormat, ...) {
    char szBuf[1024];
    DWORD dwWritten;
    va_list list;
    va_start (list, szFormat);
    vsprintf (szBuf, szFormat, list);
    hFile = CreateFile (LOGFILE, GENERIC_WRITE, 
                        0, NULL, OPEN_ALWAYS, 
                        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        SetFilePointer (hFile, 0, NULL, FILE_END);
        WriteFile (hFile, szBuf, lstrlen (szBuf), &dwWritten, NULL);
        CloseHandle (hFile);
    }
    va_end (list);
}
#endif
#endif

BOOL WINAPI __stdcall GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
    /* Specify the types and order of notification */

    pVer->dwFlags = (SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT
                     | SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_END_OF_NET_SESSION);

    pVer->dwFilterVersion = HTTP_FILTER_REVISION;

    strcpy(pVer->lpszFilterDesc, "URL Redirector, Version 1.0");

    return TRUE;
}

DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData)
{
    CHAR *pPhysPath;
    PHTTP_FILTER_URL_MAP pURLMap;
    PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo;
    CHAR szReferrer[255], szServer[255], szURL[255], szNewURL[255];
    DWORD dwRSize = sizeof(szReferrer);
    DWORD dwSSize = sizeof(szServer);
    DWORD dwUSize = sizeof(szURL);
    int iTmp, iTmp2;
    CHAR *pos, tmp[255], *tmp2;

    switch (NotificationType) {

        case SF_NOTIFY_PREPROC_HEADERS :
            pHeaderInfo = (PHTTP_FILTER_PREPROC_HEADERS)pvData;

            if (pfc->GetServerVariable(pfc, "HTTP_REFERER", szReferrer, &dwRSize))
            {
                DebugMsg(( DEST,
                           "Referrer: %s\r\n", szReferrer ));

                if (pfc->GetServerVariable(pfc, "SERVER_NAME", szServer, &dwSSize))
                    DebugMsg(( DEST,
                               "Server Name: %s\r\n", szServer ));

                if (pHeaderInfo->GetHeader(pfc, "URL", szURL, &dwUSize))
                    DebugMsg(( DEST,
                               "URL: %s\r\n", szURL ));

                iTmp = strnstr(szReferrer, szServer, strlen(szReferrer));
                if(iTmp > 0)
                {
                    //Referred is our own server...
                    strcpy(tmp, szReferrer + iTmp);
                    DebugMsg(( DEST,
                               "tmp: %s - %d\r\n", tmp, strlen(tmp) ));
                    pos = strchr(tmp+1, '/');
                    DebugMsg(( DEST,
                               "pos: %s - %d\r\n", pos, strlen(pos) ));

                    iTmp2 = strlen(tmp) - strlen(pos) + 1;

                    strncpy(tmp2, tmp, iTmp2);
                    tmp2[iTmp2] = '\0';
                    DebugMsg(( DEST,
                               "tmp2: %s\r\n", tmp2));

                    if(strncmp(szURL, tmp2, iTmp2) != 0)
                    {
                        //First paths don't match, create new URL...
                        strncpy(szNewURL, tmp2, iTmp2-1);
                        strcat(szNewURL, szURL);
                        DebugMsg(( DEST,
                                   "newURL: %s\r\n", szNewURL));
                        pHeaderInfo->SetHeader(pfc, "URL", szNewURL);
                        return SF_STATUS_REQ_HANDLED_NOTIFICATION;
                    }
                }
            }

            break;

        default :

            break;    
    }

    return SF_STATUS_REQ_NEXT_NOTIFICATION;
}


/* simple function to compare two strings and return the position at which the compare ended */
static int strnstr ( const char *string, const char *strCharSet, int n)
{
    int len = (strCharSet  != NULL ) ? ((int)strlen(strCharSet )) : 0 ;
    int ret, I, J, found;

    if ( 0 == n || 0 == len )
    {
        return -1;
    }

    ret = -1;
    found = 0;
    for (I = 0 ; I <= n - len && found != 1 ; I++)
    {
        J = 0 ;
        for ( ; J < len ; J++ )
        {
            if (toupper(string[I + J]) != toupper(strCharSet [J]))
            {
                break; // Exit For(J)
            }
        }

        if ( J == len)
        {
            ret = I + (J);
            found = 1;
        } 
    }

    return ret;
}

【问题讨论】:

  • 在出现故障之前,您在日志中的距离是多少?
  • 地址 0x0002df25 是否对应 DLL 源中的特定行?顺便说一句,0x0002df25 是要加载的 DLL 的异常低地址。最后,您能否附加一个调试器(在崩溃时作为 JIT 调试器或在崩溃前附加到 w3wp.exe)?
  • 我实际上让它工作了......我将 tmp2 的定义从 *tmp2 更改为 tmp2[255]。谁能给我解释一下?
  • 您正在对 tmp2 执行 strcpy(),它是一个 char*?没有配置?甚至没有初始化?这只是意味着你正在写进永无止境的地方。
  • 谢谢芝士。这是我第一次尝试 C/C++ 程序,所以我很惊讶我做了这么多工作(我花了 6 个小时)。无论如何,所以如果我将一个变量定义为 char*,我需要对其进行初始化或分配内存?

标签: c memory isapi


【解决方案1】:

如果你真的想编写和维护一个自定义 ISAPI 过滤器,我强烈推荐两件事:

  1. 使用 Visual Studio 进行调试
    .
    如果问题可重现,请使用 Visual Studio 或其他调试器附加到 w3wp.exe 以捕获异常。您需要做的是启动 IIS 并通过它运行请求,以便加载过滤器。确保 DLL 的 pdb 文件与 DLL 位于同一位置。
    .
    然后您需要启动 Visual Studio,然后附加到调试器中的 w3wp.exe 进程。然后运行导致故障的请求。在 Visual Studio 中,调试器将向您显示导致问题的确切行。

  2. 使用 StackWalker
    .
    如果问题不能可靠地重现,您需要安排在问题确实发生时记录调用堆栈转储,包括行号,以帮助诊断。为此,请使用 codeplex Stackwalker 项目。当异常发生时,您的 ISAPI 可以将调用堆栈转储到日志文件中,这样您就可以查明代码中导致错误的行。

【讨论】:

    【解决方案2】:

    我知道您在问一个编程问题,但您可以通过放弃编写 ISAPI 过滤器的工作来避免整个事情,而是使用现成的通用重写器,例如 IIRF

    这是可以做你想做的事情的规则:

    RewriteCond %{HTTP_REFERER} ^http://localserver/([^/]+)/etc/etc$
    RewriteCond $1              !*1
    RewriteRule ^/([^/]+)/([^/]+)\.(jpg|gif|png)$    /*1/$1/$2.$3    [L]
    

    【讨论】:

    • 我想我迷路了,因为 IIS 不允许您开箱即用地执行此操作,而且我无法在我们的公司 Web 服务器上完全安装某些东西,而无需跳过很多圈子并继续前进通过软件评论...
    • 我不明白。您正在编写一个 ISAPI 过滤器,对吧? IIRF 也是一个 isapi 过滤器。您部署它的方式与部署简单过滤器的方式相同。无论您对使用 IIRF 有什么顾虑,都与使用您自己的自定义过滤器相同。不?或者您是说,他们将允许您编写一个简单的过滤器,但不允许像 IIRF 这样的外部来源过滤器?
    【解决方案3】:

    一个潜在的问题是szReferrerszServer 是否是完全相同的值(不确定这是否可能)。但如果确实发生了,那么strnstr 返回字符串值的长度。换句话说,它返回第一个字符串的长度。在那种情况下,我认为tmp 中的strcpy 只将一个零终止字节放入tmp 中。以下strchr(tmp+1, ‘/’); 具有未定义的行为。从它返回的值可以是任何东西(它实际上可能导致访问冲突,因为它可以读取超出它应该读取的内存)。在那之后事情可能会分崩离析。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-11
      • 2013-01-18
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      相关资源
      最近更新 更多