Freigeben über


HOWTO: ISAPI Filter which rejects requests from SF_NOTIFY_PREPROC_HEADERS based on HTTP Referer

There was a recent question about how to reject requests (based on the HTTP Referer header in this case) in SF_NOTIFY_PREPROC_HEADERS.

Question:

Hello everyone,

I'm trying to solve a problem of referer spam: People will fake requests to the web server using online casino, "drug" retailers and other questionable web sites as referer. Not only does that messes up my web stats but I also happen to run a blog software that keeps track of these referer and actually display them to users.

Anyway, in order to solve that problem, I wrote a small ISAPI filter in Delphi 6. it works well so far with one problem: when it blocks a request, it sends back a 401.4 response: "A filter denied access to this resource".

I would like to send back a "403" which has a better chance to be properly interpreted as a "get out of my yard, buddy".

What I'm doing now:

1/ Calling SetLastError with ERROR_ACCESS_DENIED as parameter
2/ Returning SF_STATUS_REQ_ERROR as the result of the filter callback.

Since I'm filtering the even as soon as possible, when I get a SF_NOTIFY_PREPROC_HEADERS notification, I don't seem to have access to the return code itself.

Is there a way to send back that 403 without modifing to filter to run in the SF_NOTIFY_END_OF_REQUEST notification ? I'd like to minimize the impact of the request on the server and I see no reason to run multiple DB queries to generate a web page that will be truncated by the filter.

Thank you,

Answer:

Unfortunately, for an ISAPI Filter, there is no API call to send an IIS-configured custom error page. The same for ISAPI Extension until in IIS 6.0 when the HSE_REQ_SEND_CUSTOM_ERROR ServerSupportFunction was introduced to allow it to send IIS-configured custom error page by explicitly specifying HTTP status/sub-status code.

However, ISAPI Filter does have an "arbitrary" behavior which can cause a couple of HTTP responses to be sent when you call SetLastError() with the following values and return SF_STATUS_REQ_ERROR from SF_NOTIFY_PREPROC_HEADERS.

  1. ERROR_FILE_NOT_FOUND - returns 404 error
  2. ERROR_PATH_NOT_FOUND - returns 404 error
  3. ERROR_ACCESS_DENIED - returns 401.4 error
  4. Any other Win32 error code - returns 500 error with FormatMessage of the error code

Personally, from a security perspective, I would send back a 404 response using ERROR_FILE_NOT_FOUND instead of sending back 401.4 (tells attacker that you have an ISAPI Filter looking at responses, which can induce more attacks) or 403 (tells attacker that they are doing something the server does not want to do).

Of course, if you must send back the 403, you can certainly call SF_REQ_SEND_RESPONSE_HEADER with a 403 status string and return SF_REQ_STATUS_FINISHED from SF_NOTIFY_PREPROC_HEADERS, which would be just as efficient.

For example, UrlScan does this - SetLastError( ERROR_FILE_NOT_FOUND ) and return SF_REQ_STATUS_FINISHED from SF_NOTIFY_PREPROC_HEADERS for the fast path rejection.

Regarding your other question about "when I get a SF_NOTIFY_PREPREC_HEADERS notification, I don't seem to have access to the return code itself". I am not certain what return code you are referring to, but it is probably not needed.

There is no "return code" in SF_NOTIFY_PREPROC_HEADERS because it happens as IIS is parsing the request headers and before processing the request. Since an ISAPI Filter can write arbitrary data via WriteClient or SF_REQ_SEND_RESPONSE_HEADER to the client and terminate the request processing right then and there, you really do not need access to any return code. You have control of the entire request/response right then and there.

Also, rejecting a request in SF_NOTIFY_END_OF_REQUEST is not optimal. You have already done all the request processing, and you also need to consume response data in SF_NOTIFY_SEND_RAW_DATA (so that the client gets a proper HTTP response) as well as send the entire rejection response in SF_NOTIFY_END_OF_REQUEST. Too much work for a rejection.

Here is a complete filter sample in C (sorry, I really do not know Delphi) that requires that all requests have a Referer header whose value starts with "https://myserver". It has a whole bunch of comments that show how to send a 404 or a 403 response as well as how to filter on the Referer header.

Enjoy.

//David

 #include <windows.h>
#include <httpfilt.h>

#define DEFAULT_BUFFER_SIZE         1024
#define MAX_BUFFER_SIZE             4096

DWORD
OnPreprocHeaders(
    IN HTTP_FILTER_CONTEXT *            pfc,
    IN HTTP_FILTER_PREPROC_HEADERS *    pPPH
);

BOOL
WINAPI
GetFilterVersion(
    HTTP_FILTER_VERSION *           pVer
    )
/*++

Purpose:

    Required entry point for ISAPI filters.  This function
    is called when the server initially loads this DLL.

Arguments:

    pVer - Points to the filter version info structure

Returns:

    TRUE on successful initialization
    FALSE on initialization failure

--*/
{
    pVer->dwFilterVersion = HTTP_FILTER_REVISION;
    lstrcpyn( pVer->lpszFilterDesc,
             "Filter to reject based on HTTP Referer header",
             SF_MAX_FILTER_DESC_LEN );
    pVer->dwFlags =
        SF_NOTIFY_ORDER_HIGH |
        SF_NOTIFY_PREPROC_HEADERS
        ;

    return TRUE;
}

DWORD
WINAPI
HttpFilterProc(
    IN HTTP_FILTER_CONTEXT *        pfc,
    DWORD                           dwNotificationType,
    LPVOID                          pvNotification
    )
/*++

Purpose:

    Required filter notification entry point.  This function is called
    whenever one of the events (as registered in GetFilterVersion) occurs.

Arguments:

    pfc              - A pointer to the filter context for this notification
    NotificationType - The type of notification
    pvNotification   - A pointer to the notification data

Returns:

    One of the following valid filter return codes:
    - SF_STATUS_REQ_FINISHED
    - SF_STATUS_REQ_FINISHED_KEEP_CONN
    - SF_STATUS_REQ_NEXT_NOTIFICATION
    - SF_STATUS_REQ_HANDLED_NOTIFICATION
    - SF_STATUS_REQ_ERROR
    - SF_STATUS_REQ_READ_NEXT

--*/
{
    switch ( dwNotificationType )
    {
    case SF_NOTIFY_PREPROC_HEADERS:
        return OnPreprocHeaders(
            pfc,
            (HTTP_FILTER_PREPROC_HEADERS *) pvNotification );
    }

    return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

DWORD
OnPreprocHeaders(
    HTTP_FILTER_CONTEXT *           pfc,
    HTTP_FILTER_PREPROC_HEADERS *   pPPH
)
{
    DWORD                           dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
    BOOL                            fRet = FALSE;
    CHAR                            pBuf[ DEFAULT_BUFFER_SIZE ];
    CHAR *                          pszBuf = pBuf;
    DWORD                           cbBuf = DEFAULT_BUFFER_SIZE;
    CHAR                            szReferer[] = "Referer:";
    CHAR                            szMyServerABS[] = "https://myserver";
    CHAR                            cbMyServerABS = 15;

    SetLastError( NO_ERROR );

    if ( pfc == NULL ||
         pPPH == NULL )
    {
        SetLastError( ERROR_INVALID_PARAMETER );
        goto Finished;
    }

    fRet = pPPH->GetHeader( pfc, szReferer, pszBuf, &cbBuf );
    if ( fRet == FALSE )
    {
        if ( GetLastError() == ERROR_INVALID_INDEX )
        {
            //
            // Referer header was not given
            // Two options:
            //
            // If not having Referer header is ok.
            //
            // OutputDebugString( "Nothing to do.\n" );
            // SetLastError( NO_ERROR );
            //
            // If Referer header is required
            //
            // OutputDebugString( "Referer header was not found.\n" );
            // SetLastError( ERROR_ACCESS_DENIED );
            //
            goto Finished;
        }
        else if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
                  cbBuf < MAX_BUFFER_SIZE )
        {
            pszBuf = new CHAR[ cbBuf ];
            if ( pszBuf == NULL )
            {
                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                goto Finished;
            }

            fRet = pPPH->GetHeader( pfc, szReferer, pszBuf, &cbBuf );
            if ( fRet == FALSE )
            {
                goto Finished;
            }

            OutputDebugString( "Found Referer header.\n" );
         }
         else
         {
             goto Finished;
         }
    }

    //
    // At this point, pszBuf points to the value of Referer header.
    // Figure out what to do.
    //
    OutputDebugString( pszBuf );
    OutputDebugString( "\n" );

    //
    // If it is not an absolute URL from my server, reject it
    //
    if ( _strnicmp( pszBuf, szMyServerABS, cbMyServerABS ) != 0 )
    {
        //
        // Option 1: Send a 404 response
        //
        // SetLastError( ERROR_FILE_NOT_FOUND );
        // goto Finished;
        //
        // Options 2: Send a 403 response
        //
        fRet = pfc->ServerSupportFunction( pfc,
                                           SF_REQ_SEND_RESPONSE_HEADER,
                                           (PVOID)"403 Forbidden",
                                           (ULONG_PTR)"Content-Length: 0\r\n"
                                           "Content-Type: text/html\r\n\r\n",
                                           NULL );
        if ( fRet == FALSE )
        {
            goto Finished;
        }

        dwRet = SF_STATUS_REQ_FINISHED;
    }

    SetLastError( NO_ERROR );

Finished:

    if ( pszBuf != pBuf )
    {
        delete pszBuf;
    }

    if ( GetLastError() != NO_ERROR )
    {
        OutputDebugString( "Error!\n" );
        dwRet = SF_STATUS_REQ_ERROR;
    }

    return dwRet;
}

Comments

  • Anonymous
    July 04, 2005
    Hello, I'm the one who asked that question. Thanks a lot for your answer. Thanks a lot for your answer. I've implemented the change you suggest (with a few modifications) and it works just as I wanted. Thank you,

  • Anonymous
    July 11, 2005
    People frequently ask about the &quot;Referer Authentication&quot; custom protocol that Apache offers with a custom...

  • Anonymous
    August 08, 2005
    The comment has been removed

  • Anonymous
    August 08, 2005
    Thanks for the compiler check. I made the minor changes so that it should compile clean from copy/paste (well, assuming one adds the necessary .DEF file).

    //David

  • Anonymous
    December 13, 2005
    The comment has been removed

  • Anonymous
    December 13, 2005
    Junaid - you need to design and implement a mechanism to uniquely identify a remote client. This mechanism is commonly known as "authentication".

    Since you are the one designing the system, you need to first come up with the necessary requirements that must be fulfilled by the authentication protocol... then you search and use the minimal necessary protocol.

    After you figure out how to authenticate a remote client on a per-request basis, then you can easily implement restrictions.

    //David

  • Anonymous
    December 25, 2005
    Hi David,

    Please help me out in this issue. For example someone is downloading a file from the server and in the middle the connection gets broke or the user himself cancels the download. How do i know using isapi filter that this has happened. Which event to capture or what will get return if this is the scenario. Please help.

    Thanks & Regards

    Junaid

  • Anonymous
    December 27, 2005
    Junaid - No reliable way to detect this condition in ISAPI. No filter event fires on errors.

    On WS03SP1, you can't detect it. HTTP.SYS will buffer the response such that ISAPI Filter will not know when/if the client disconnects

    Prior to WS03SP1, you can try to count bytes sent via SF_NOTIFY_SEND_RAW_DATA and expected bytes obtained via Content-Length: in SF_NOTIFY_SEND_RESPONSE. But this only works for response entity body that has Content-Length.

    For Transfer-Encoding: chunked entity body or responses without either Content-Length or Transfer-Encoding: chunked headers, I cannot think of a good way.

    Some people have tried GetLastError() in SF_NOTIFY_SEND_RAW_DATA, SF_NOTIFY_END_OF_REQUEST, and SF_NOTIFY_END_OF_NET_SESSION to attempt to get some error code indicating error... but this is not defined in any interface, thus it is not guaranteed to work from version to version.

    //David

  • Anonymous
    February 07, 2006
    Hi David ,

    The problems is.

     I make request to download a file. say www.abc.comhello.wmv
     say hello.wmv is a 5 MB. I want to HTTP byte range to restrict and download only the part of the movie. How can i accomplish the task.

    Regards

    Junaid


     

  • Anonymous
    February 07, 2006
    Junaid - write an ISAPI Extension scriptmapped to handle all .wmv requests, determine the physical file location of the URL (similar to how ASP does it), and then call HSE_REQ_TRANSMIT_FILE (or HSE_REQ_VECTOR_SEND on IIS6) to transmit any portion(s) of the physical file.

    Of course, you are responsible for making the client understand how to receive and use the partial download of the file. IIS just allows you to send the byte stream.

    //David

  • Anonymous
    February 07, 2006
    Thanks David for the info.  If have any link that shows how to use
    HSE_REQ_TRANSMIT_FILE, plese forward to me. As i'm new to this ISAPI stuffs. And Can we use HSE_REQ_TRANSMIT_FILE in ISAPI filter.

    Regards

    Junaid

  • Anonymous
    February 08, 2006
    Junaid - I believe you can read ISAPI Documentation on MSDN for sample code and answers to your latest questions.

    //David

  • Anonymous
    February 12, 2006
    Hi David,

        I tried to write a ISAPI Filter to download the partial content. I have used Addheader Range. But its not working and the full gets downloaded.  

       I have also tried with ISAPI Extension using HSE_REQ_TRANSMIT_FILE. i am able to download part of the file using say byteswritten= 10000000 but when i use offset, i'm not able to play the file after download. Please help me about AddHeader and setheader usage. I am using it as specified in the
    http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2 but i'm able to download the partial content.

    Please need your help.

    Thanks & Regards

    Junaid

  • Anonymous
    February 12, 2006
    Junaid - I suspect you are not adding correct headers to the RESPONSE. Since you are modifying response data stream, you really need to use Network Monitor or tools like that to make sure your altered HTTP response is kosher.

    You can add response headers with an ISAPI Filter either by:
    1. Calling pfc->AddResponseHeader( "header: valuern" ) before SF_NOTIFY_SEND_RESPONSE fires
    2. Calling AddHeader/SetHeader in SF_NOTIFY_SEND_RESPONSE

    But, I do not know why you are trying to write an ISAPI Filter to do this...

    Now, if you are going with the ISAPI Extension solution, you don't need an ISAPI Filter to add the response header - just send the right headers on the HSE_REQ_TRANSMIT_FILE call itself.

    As for what happens with the partial download delivered by HSE_REQ_TRANSMIT_FILE - you need to figure out how to make the resulting partial data playable by the media player. All media formats have a certain layout, and your partial download of a given file needs to remain kosher relative to that layout.

    In other words, suppose hello.wmv is 5MB and contains 1 minute of content. If you want to just deliver content between 0:15s and 0:45s, you obviously need to figure out the right header as well as partial file content to stream.

    You are response for figuring out that "make it work" aspect. After you figure it out, the IIS portion is trivial - HSE_REQ_TRANSMIT_FILE to send the headers and partial file content, and simple Scriptmap setting to wire your ISAPI onto the .wmv requests.

    //David

  • Anonymous
    February 12, 2006
    Thanks a lot for your help. Below is the code that i'm using. I have added AddResponseHeader as you have mentioned. But it not working. Please review the below code.....

    I would be grateful to you.

    Thanks & Regards

    Junaid

    HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
    CRITICAL_SECTION    g_LogFileLock;


    ///////////////////////////////////////////////////////////////////////
    // The one and only CRedirectorFilter object

    CRedirectorFilter theFilter;

    CHAR* CRedirectorFilter::m_pszUserFile = NULL;



    ///////////////////////////////////////////////////////////////////////
    // CRedirectorFilter implementation

    CRedirectorFilter::CRedirectorFilter()
    {

     
    }

    CRedirectorFilter::~CRedirectorFilter()
    {

    }

    BOOL CRedirectorFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
    {



    // Call default implementation for initialization
    CHttpFilter::GetFilterVersion(pVer);

    // Clear the flags set by base class
    pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;

    // Set the flags we are interested in
    pVer->dwFlags |= SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_PREPROC_HEADERS;


    // Initialize the logging critical section
       //
       InitializeCriticalSection( &g_LogFileLock );

    g_hLogFile = CreateFile("D:\MyLog.txt",GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL,
    OPEN_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL
    );

           
      if ( g_hLogFile == INVALID_HANDLE_VALUE )
       {
           //
           // Failed to open log file due to GetLastError(). Bail.
           //
           return FALSE;
       }



       pVer->dwFilterVersion = HTTP_FILTER_REVISION;

       lstrcpyn( pVer->lpszFilterDesc,
                "ISAPI Filter to log request headers based on User-Agent",
                SF_MAX_FILTER_DESC_LEN );
     
       return TRUE;
    }

    DWORD CRedirectorFilter::OnPreprocHeaders(HTTP_FILTER_CONTEXT*  pCtxt,
    PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo)
    {

    DWORD  dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
    BOOL   fRet = FALSE;
       CHAR   pBuf[ DEFAULT_BUFFER_SIZE ];
       CHAR   pBuf2[ DEFAULT_BUFFER_SIZE ];
       CHAR *pszBuf = pBuf;
       CHAR pszBuf2 = pBuf2;
       CHAR  szUserAgent[] = "User-Agent:";
    CHAR  szUrl[] = "url";
       CHAR  szMSNBot[] = "Mozilla/4.0";
    CHAR  cbMSNBot = 11;
       DWORD cbBuf = DEFAULT_BUFFER_SIZE;
    DWORD cbBuf2 = DEFAULT_BUFFER_SIZE;
    DWORD cbBuf3 = DEFAULT_BUFFER_SIZE;
       
    SetLastError( NO_ERROR );



       if ( pCtxt == NULL ||
            pHeaderInfo == NULL )
       {
           SetLastError( ERROR_INVALID_PARAMETER );
           goto Finished;
       }

    //pCtxt->AddResponseHeaders(pCtxt, "Content-Range: bytes 0-1048576rn", 0);


    // pHeaderInfo->AddHeader(pCtxt,"Range:","bytes 0-500");
    // pHeaderInfo->AddHeader(pCtxt,"Content-Range:","bytes 0-500");
    // pHeaderInfo->AddHeader(pCtxt,"Accept-Ranges:","bytes");

    pCtxt->AddResponseHeaders(pCtxt,"Range: bytes 0-500rn",0);
    pCtxt->AddResponseHeaders(pCtxt,"Content-Range: bytes 0-500rn",0);
    pCtxt->AddResponseHeaders(pCtxt,"Accept-Ranges: bytesrn",0);


    fRet = pHeaderInfo->GetHeader(pCtxt,szUserAgent,pszBuf,&cbBuf);

    if ( fRet == FALSE )
           {
    if ( GetLastError() == ERROR_INVALID_INDEX )
    {
    //
    // User-Agent was not given
    // Since we are looking for a particular user-agent,
    // not finding on is ok.
    //
    OutputDebugString( "Nothing to do.n" );
    SetLastError( NO_ERROR );
    goto Finished;
    }

    else if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER && cbBuf < MAX_BUFFER_SIZE )
               {

                   pszBuf = new CHAR[ cbBuf ];
                   if ( pszBuf == NULL )
                   {

                       SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                       goto Finished;
                   }

                   fRet = pHeaderInfo->GetHeader(pCtxt,szUserAgent,pszBuf,&cbBuf);

                   if ( fRet == FALSE )
                   {
           goto Finished;
                   }

                   OutputDebugString( "Found User-Agent header.n" );
               }
               else
               {
      goto Finished;
               }
    }

    //
    // If the User-Agent matches the MSNBot, log request headers
    //
       
    if ( _strnicmp( pszBuf, szMSNBot, cbMSNBot ) == 0 )
       {

    pCtxt->AddResponseHeaders(pCtxt,"Range: bytes 0-500rn",0);
    pCtxt->AddResponseHeaders(pCtxt,"Content-Range: bytes 0-500rn",0);
    pCtxt->AddResponseHeaders(pCtxt,"Accept-Ranges: bytesrn",0);


           fRet = pCtxt->GetServerVariable( pCtxt, "ALL_RAW", pszBuf2, &cbBuf2 );
           if ( fRet == FALSE )
           {
               if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
                    cbBuf2 < MAX_BUFFER_SIZE )
               {
                   pszBuf2 = new CHAR[ cbBuf2 ];
                   if ( pszBuf2 == NULL )
                   {
                       SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                       goto Finished;
                   }

                   fRet = pCtxt->GetServerVariable( pCtxt,
                                                  "ALL_RAW",
                                                  pszBuf2,
                                                  &cbBuf2 );
                   if ( fRet == FALSE )
                   {
                       goto Finished;
                   }

                   OutputDebugString( "Read ALL_RAWn" );
               }
               else
               {
                   goto Finished;
               }
           }

    //
           // At this point, pszBuf2 points to the raw request headers
           // But first, retrieve the URL of this request by reusing pszBuf.
           // Then append it to disk, thread-safe.
           //

    if ( pszBuf != pBuf )
           {
               delete pszBuf;
               pszBuf = pBuf;
           }


    fRet = pHeaderInfo->GetHeader( pCtxt, szUrl, pszBuf, &cbBuf );

           if ( fRet == FALSE )
           {
               if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
                    cbBuf < MAX_BUFFER_SIZE )
               {

                   pszBuf = new CHAR[ cbBuf ];
                   if ( pszBuf == NULL )
                   {

                       SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                       goto Finished;
                   }

                   fRet = pHeaderInfo->GetHeader( pCtxt, szUrl, pszBuf, &cbBuf );
                   if ( fRet == FALSE )
                   {

                       goto Finished;
                   }

                   OutputDebugString( "Found URL.n" );
                }
                else
                {
                    goto Finished;
                }
           }


    //
           // Write the URL and raw headers to disk
           //

    if ( g_hLogFile != INVALID_HANDLE_VALUE )
           {
               EnterCriticalSection( &g_LogFileLock );
               SetFilePointer( g_hLogFile, 0, NULL, FILE_END );
               cbBuf--;
               fRet = WriteFile( g_hLogFile, pszBuf, cbBuf, &cbBuf, NULL );
               cbBuf = 1;
               fRet = WriteFile( g_hLogFile, "n", cbBuf, &cbBuf, NULL );
    cbBuf2--;
               fRet = WriteFile( g_hLogFile, pszBuf2, cbBuf2, &cbBuf2, NULL );
    LeaveCriticalSection( &g_LogFileLock );
           }


           
    }
    SetLastError( NO_ERROR );

    Finished:

       if ( pszBuf != pBuf )
       {
       delete pszBuf;
    }

    if ( GetLastError() != NO_ERROR )
    {
    OutputDebugString( "Error!n" );
    dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
    }

    return dwRet;
    }

    DWORD CRedirectorFilter::OnSendResponse(IN HTTP_FILTER_CONTEXT *   pfc,    IN HTTP_FILTER_SEND_RESPONSE *  pSR)
    {
       DWORD                           dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
       BOOL                            fRet = FALSE;
       CHAR                            pBuf[ DEFAULT_BUFFER_SIZE ];
       CHAR *                          pszBuf = pBuf;
       DWORD                           cbBuf = DEFAULT_BUFFER_SIZE;
       CHAR                            szCacheControl[] = "Content-Range:";
       CHAR                            szPrivate[] = "bytes 0-1048576";

       SetLastError( NO_ERROR );

       if ( pfc == NULL ||
            pSR == NULL )
       {
           SetLastError( ERROR_INVALID_PARAMETER );
           goto Finished;
       }


    //pfc->AddResponseHeaders(pfc,"Content-Range: bytes 0-1048576rn",0);
    //pfc->AddResponseHeaders(pfc,"Content-Type: video/x-ms-wmvrn",0);

    //pSR->AddHeader(pfc,(char ) _T("Accept-Ranges:"),(char ) _T("bytes"));
    //pSR->AddHeader(pfc,(char ) _T("Content-Range:"),(char ) _T("bytes 0-500/1048576"));



       
       //
       // At this point, pszBuf points to the value of Content-Type header.
       // Figure out if the Content-Type matches and if so, add the
       // Cache-Control header.
       //
       

           //
           // Replace any Cache-Control header
           //
           //fRet = pSR->SetHeader( pfc, szCacheControl, szPrivate );

           if ( fRet == FALSE )
           {
               //
               // Failed to set header for some reason
               // Fail the request
               //
               goto Finished;
           }

               

       
    Finished:

       if ( pszBuf != pBuf )
       {
           delete pszBuf;
       }

       if ( GetLastError() != NO_ERROR )
       {
           OutputDebugString( "Error!n" );
           dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
       }

       return dwRet;
    }


    DWORD CRedirectorFilter::TerminateFilter(DWORD dwFlags)
    /
    ++

     Optional filter entry point.  This function is called by the server
     before this DLL is unloaded.

     Arguments:

       dwFlags - No flags have been defined at this time

     Returns:

       Always returns TRUE;

    --
    /
    {
       if ( g_hLogFile != INVALID_HANDLE_VALUE )
       {
           CloseHandle( g_hLogFile );
           g_hLogFile = INVALID_HANDLE_VALUE;
       }

    DeleteCriticalSection( &g_LogFileLock );

       return TRUE;
    }

    DWORD CRedirectorFilter:: HttpFilterProc(
       IN HTTP_FILTER_CONTEXT *      pfc,
       DWORD                      NotificationType,
       PVOID                      pvData )
    /
    ++

     Routine Description:
     
       This is the main function for the filter. It processes all
        filter notifications sent by the server and takes appropriate action.

     Arguments:
       pfc              -   pointer to filter context
       NotificationType -   type of notification
       pvData           -   pointer to data structure specific for the
                             notification

     Returns:
       DWORD value containing the SF_STATUS_TYPE is returned

    --
    /
    {

    CHttpFilter::HttpFilterProc(pfc,NotificationType,pvData);

       DWORD   sfReturn = SF_STATUS_REQ_NEXT_NOTIFICATION;

       switch ( NotificationType) {


         case SF_NOTIFY_PREPROC_HEADERS:
    sfReturn =  OnPreprocHeaders(pfc,(HTTP_FILTER_PREPROC_HEADERS
    ) pvData );
                                        break;
     //case SF_NOTIFY_SEND_RESPONSE:  sfReturn =  OnSendResponse( pfc,(HTTP_FILTER_SEND_RESPONSE *) pvData );
                                break;//

     default:       // No Action to take here. pass it on to other filters in chain.
     break;

       } // switch

       return (sfReturn);
    } // HttpFilterProc()

  • Anonymous
    February 12, 2006
    Junaid - I'm sorry, but this is mostly my code with a couple of copy/paste of your code. Can you clearly describe what you want to accomplish, how are you trying to accomplish it, YOUR concise code to do it, and how is it exactly failing (Network Monitor trace or WFetch output is sufficient).

    But, please do not try to make me write and debug your code for you...

    FYI: What I said earlier still holds true -- I do not see a need for ISAPI Filter, and once you figure out how HTTP and client-side interpretation of partial content works, the ISAPI portion should be easy.

    Finally, I do not support ISAPI using the MFC ISAPI Framework.

    //David

  • Anonymous
    February 12, 2006
    Hi David,

      Yes its your code. What i want is..


     say i make a request www.example.com/movie.wmv

     say if its a 2 MB file. i want to download only the last 1 MB.
     so what  i'm trying to use is Range header. But it seems not  
     working. That's all.  In other words as you told.. as below.

    suppose hello.wmv is 5MB and contains 1 minute  of content. If you want to just deliver content between 0:15s and 0:45s, you obviously need to figure out the right header as well as partial file content to stream.

    I trying to acheive this.

    Sorry for the trouble....and disturbance.

    Thanks & Regards

    Junaid



  • Anonymous
    February 12, 2006
    The comment has been removed

  • Anonymous
    February 12, 2006
    Hi David.

    I'm extreamly sorry............
    Thanks a lot............... for your help. I found the problem why i was not able to get the requested ranges. Its b'coz of some authentication in my IIS server. I downloaded wfetch and then i found out the problem...

    Thanks again...........

    Regards

    Junaid

  • Anonymous
    February 13, 2006
    The comment has been removed

  • Anonymous
    March 07, 2006
    (1) ISAPI filter can not open and write to local disk file on IIS 6.0
    (2) Can I share filter between different web sites by using synchronizing the shared source ?


    I wrote a filter  to log some data into DB and catch the failed DB process into local file.  The DB process is ok, but the process of writing to local file failed.  Is that security problem (I did not singn in as administrator) ?

    The Filter Source Code: (.h and .cpp)



    // LOGCSBJ.H - Header file for your Internet Server
    //    LogCsbj Filter

    #include "resource.h"

    class CLogCsbjFilter : public CHttpFilter
    {
    public:
    CLogCsbjFilter();
    ~CLogCsbjFilter();

    // Overrides
    // ClassWizard generated virtual function overrides
    // NOTE - the ClassWizard will add and remove member functions here.
    //    DO NOT EDIT what you see in these blocks of generated code !
    //{{AFX_VIRTUAL(CLogCsbjFilter)
    public:
    virtual BOOL GetFilterVersion(PHTTP_FILTER_VERSION pVer);
    virtual DWORD OnLog(CHttpFilterContext* pfc, PHTTP_FILTER_LOG pLog);
    //}}AFX_VIRTUAL

    //{{AFX_MSG(CLogCsbjFilter)
    //}}AFX_MSG

    private:
    CString m_CompName;
    CCriticalSection m_cs;
    CString cs2;
    INT counter;

    public:
    void init();
    UINT ComputeThreadProc(CString cs);
    };

    //{{AFX_INSERT_LOCATION}}





    #include "stdafx.h"
    #include "LogCsbj.h"

    ///////////////////////////////////////////////////////////////////////
    // The one and only CLogCsbjFilter object

    CLogCsbjFilter theFilterCsbj;

    ///////////////////////////////////////////////////////////////////////
    // CLogCsbjFilter implementation

    CLogCsbjFilter::CLogCsbjFilter()
    {
    cs2 = _T(" ");
    m_CompName = _T(" ");
    counter = 0;
    init ();
    CStdioFile  f;
    CString pFileName = "f:\logfiltercsbj.txt";
    f.Open( pFileName,  CFile::modeCreate );
    f.Close();
    }


    CLogCsbjFilter::~CLogCsbjFilter()
    {
    }


    void CLogCsbjFilter::init () {

    WSADATA Data;
    INT status = 0;
    status=WSAStartup(MAKEWORD(1, 1), &Data);
    if (status == 0)
    {
    char     szHostname[100];
    INT A = 0;
    A = gethostname( szHostname, sizeof( szHostname ));

    if (A == 0) {
    CString cn(szHostname);
    m_CompName = cn;
    }
    }
    }



    BOOL CLogCsbjFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
    {
    // Call default implementation for initialization
    CHttpFilter::GetFilterVersion(pVer);

    // Clear the flags set by base class
    pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;

    // Set the flags we are interested in
    pVer->dwFlags |= SF_NOTIFY_ORDER_MEDIUM | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT
    | SF_NOTIFY_LOG;

    // Load description string
    TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
    ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
    IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
    _tcscpy(pVer->lpszFilterDesc, sz);
    return TRUE;
    }


    DWORD CLogCsbjFilter::OnLog(CHttpFilterContext *pCtxt, PHTTP_FILTER_LOG pLog)
    {
    CString Ct1(pLog->pszTarget);
    Ct1.MakeLower();
    CString Ct2(pLog->pszParameters);

    if ( Ct1.Find(".jpg") == -1 && Ct1.Find(".gif") == -1 &&
    Ct1.Find(".css") == -1 && Ct1.Find(".js") == -1 &&
    Ct1.Find(".ico") == -1  && Ct1.Find("robots.txt") == -1 &&
    Ct1.Find("akamai.cfm") == -1
      )
    {
    DWORD dwSize = 50;
    char pchVar3[50] = "";
    pCtxt->GetServerVariable("REMOTE_ADDR", pchVar3, &dwSize);
    CString Ct3(pchVar3);

    INT dotP = -1;
    dotP = Ct3.ReverseFind('.');
    CString cstPart1 = Ct3.Left(dotP);

    //if ( cstPart1.Find("10.1." ) == -1 )
    //{
    char pchVar4[50] = "";
    pCtxt->GetServerVariable("SERVER_NAME", pchVar4, &dwSize);
    CString Ct4(pchVar4);
    Ct4.MakeLower();
    //CString siteId ("csbj");
    CString siteId ("pdftest");
    INT A = -1;
    INT B = -1;

    DWORD dwSize0 = 2000;
    char pchVar0[2000] = "";
    pCtxt->GetServerVariable("ALL_HTTP", pchVar0, &dwSize0);
    CString st(pchVar0);
    st.MakeLower();
    INT nLength = 0;
    nLength = st.GetLength();
    CString agent = _T(" ");

    A = st.Find("http_user_agent:");

    if ( A != -1)  {
    CString rightSt = st.Right(nLength - A);
    B = rightSt.Find("n");
    if (B != -1) {
    CString leftSt = rightSt.Left(B);
    leftSt.Replace("http_user_agent:", " ");
    leftSt.TrimLeft();
    leftSt.TrimRight();
    agent = leftSt;
    }
    }

    if (agent.GetLength() < 3  || ( agent.Find("nagios") ==-1 &&  agent.Find("bot") ==-1 &&
    agent.Find("robot") ==-1 && agent.Find("crawler") == -1 &&
    agent.Find("spider") == -1 &&
    agent.Find("/us/ysearch/slurp") == -1 &&
    agent.Find("http://sp.ask.com/") == -1  && agent.Find("mnogosearch") == -1 &&
    agent.Find("sohu-search") == -1 && agent.Find("linkwalker") == -1 &&
    agent.Find("ia_archiver") == -1 && agent.Find("wish-la") == -1 &&
    agent.Find("cfschedule") == -1  && agent.Find("java/1.") ==-1 )
    )
    {
    CTime t = CTime::GetCurrentTime( );
    CString strGmt = t.FormatGmt("%m/%d/%Y %H:%M:%S");

    CString cs1 = "{CALL procLogPdf ('"+ strGmt+ "','" +Ct4 +
    "','"+Ct1+"','"+ Ct2+"','"+Ct3+"','"+agent+"','"+m_CompName+"','"+siteId+"')};";

    CString csToDb(" ");

    BOOL goin = FALSE;

    m_cs.Lock();
    cs2 = cs2 + cs1;
    counter++;

    if ( counter > 99 ) {
    counter = 0;
    csToDb = cs2;
    cs2 = _T(" ");
    goin = TRUE;
    }
    m_cs.Unlock();

    if (goin )
    ComputeThreadProc(csToDb);
    }
    //}
    }
    return SF_STATUS_REQ_NEXT_NOTIFICATION;
    }



    UINT CLogCsbjFilter::ComputeThreadProc(CString cs)
    {

    BOOL lostit = TRUE;
    cs.Delete (cs.GetLength() -1, 1);

    HRESULT hr = ::AfxOleInit();

    if ( !FAILED(hr))
    {
    CSession m_session;
    CDataSource m_db;
    hr = m_db.Open(_T("MSDASQL"), _T("trans_log"), _T("cfUser"), _T("rsfwtny"), DB_MODE_WRITE);

    if (! FAILED(hr)) {
    hr = m_session.Open(m_db);
    if (! FAILED(hr)) {
    CCommand <CNoAccessor, CNoRowset> myCommand;
    hr = myCommand.Open(m_session,cs);
    if (! FAILED(hr)) {
    myCommand.Close();
    lostit = FALSE;
    }
    m_session.Close();
    }
    m_db.Close();
    }
    }

    ::AfxOleTerm(0);

    if ( lostit) {
    CString ct = cs +  " n";
    CStdioFile  f;
    CString pFileName = "f:\logfiltercsbj.txt";
    f.Open( pFileName,  CFile::typeText | CFile::modeWrite );
    f.SeekToEnd();
    f.WriteString(ct);
    f.Close();
    }

    return 0;
    }


    // Do not edit the following lines, which are needed by ClassWizard.
    #if 0
    BEGIN_MESSAGE_MAP(CLogCsbjFilter, CHttpFilter)
    //{{AFX_MSG_MAP(CLogCsbjFilter)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    #endif // 0







    Thanks ,



    Lun



  • Anonymous
    March 07, 2006
    The comment has been removed

  • Anonymous
    March 22, 2006
    The comment has been removed

  • Anonymous
    March 22, 2006
    David:

    I am trying to understand the re-entrant problem.

    If process did not stop between " m_cs.Lock();  ............ m_cs.UnLock(); "  it seems to me that would not be a problem.

    Do you think the process may be stopped betweent CriticalSection time ?

    During the CriticalSection time,   insertion string has been assigned to local CString which local method ProcessLogProc will use.  So, if the process stopped here and then came back later, there is nothing changed.  Why it is not re-entrant ?

    Ok.  If you say the the re-entrant is referring to the local  method "ProcessLogProc".

    for safe, Can I just put the code of ProcessLogProc  into  OnLog and eliminated the local call ProcessLogProc  re-entrant problem ?


    I hered re-entrant before but this is first time deal with it.

    Thanks lot,


    Lun

  • Anonymous
    March 22, 2006
    David:

    Please see better checking error code>

    Thanks lot,

    Lun


    Source code:

    DWORD CPdfLogFilterFilter::OnLog(CHttpFilterContext pCtxt, PHTTP_FILTER_LOG pLog)
    {
    // check page style
    CString page(pLog->pszTarget);    
    page.MakeLower();

    if ( page.Find("akamai.cfm") != -1 || page.Find(".gif") != -1  ||
    page.Find(".jpg") != -1   || page.Find(".css") != -1  ||
    page.Find(".js") != -1        || page.Find(".ico") != -1  ||
    page.Find("robots.txt") != -1
      )
    return SF_STATUS_REQ_NEXT_NOTIFICATION;


    // check ip range
    DWORD dwSize = 50;
    char pchVarIP[50];
    CString clientIP(" ");

    BOOL boolRtAdd = pCtxt->GetServerVariable("REMOTE_ADDR", pchVarIP, &dwSize);

    if ( boolRtAdd == TRUE)
    {
    CString cip(pchVarIP);
    clientIP = cip;

    INT dotP = -1;
    dotP = clientIP.ReverseFind('.');
    CString cstPart1 = clientIP.Left(dotP);

    if ( cstPart1.Find("209.98.226" ) != -1 || cstPart1.Find("216.183.118" ) != -1 ||
    cstPart1.Find("10.1." ) != -1      || cstPart1.Find("66.45.104" ) != -1
    )

    return SF_STATUS_REQ_NEXT_NOTIFICATION;
    }


    dwSize = 2000;
    char pchVarAll[2000];
    BOOL boolAllHttp = pCtxt->GetServerVariable("ALL_HTTP", pchVarAll, &dwSize);

    CString agent = _T(" ");
    CString host = _T(" ");
    CString siteId =_T(" ");
    BOOL found = FALSE;

    if ( boolAllHttp == TRUE)
    {
    CString stAll(pchVarAll);
    stAll.MakeLower();
    INT nLength = 0;
    nLength = stAll.GetLength();

    // check agent style
    INT A = -1;
    INT B = -1;

    A = stAll.Find("http_user_agent:");
    if ( A != -1)  {
    CString rightSt = stAll.Right(nLength - A);
    B = rightSt.Find("n");
    if (B != -1) {
    agent = rightSt.Left(B);
    agent.Replace("http_user_agent:", " ");
    agent.TrimLeft();
    agent.TrimRight();
    } else {
    rightSt.Replace("http_user_agent:", " ");
    rightSt.TrimLeft();
    rightSt.TrimRight();
    agent = rightSt;
    }
    }

    if (agent.GetLength() > 2 ) {
    if ( agent.Find("nagios") !=-1 ||  agent.Find("bot") !=-1 ||
    agent.Find("robot") !=-1 || agent.Find("crawler") != -1 ||
    agent.Find("spider") != -1 || agent.Find("java/1.") !=-1  ||
    agent.Find("/us/ysearch/slurp") != -1 ||  
    agent.Find("http://sp.ask.com/") != -1 || agent.Find("mnogosearch") != -1 ||
    agent.Find("sohu-search") != -1 || agent.Find("linkwalker") != -1 ||
    agent.Find("ia_archiver") != -1 || agent.Find("wish-la") != -1 ||
    agent.Find("cfschedule") != -1
    )

    return SF_STATUS_REQ_NEXT_NOTIFICATION;
    }

    // get domain name
    A = -1;
    B = -1;

    A = stAll.Find("http_host:");

    if ( A != -1)  {
    CString rightSt = stAll.Right(nLength - A);
    B = rightSt.Find("n");
    if (B != -1) {
    host = rightSt.Left(B);
    host.Replace("http_host:", " ");
    } else {
    host = rightSt.Replace("http_host:", " ");
    }
    host.Replace(":80", " ");
    host.TrimLeft();
    host.TrimRight();
    found = m_mapStringToString.Lookup(host, siteId );
    }
    }

    /
    pay much attention to this, otherwise can not find DB table
    host was not reliable to get from  
    "pCtxt->GetServerVariable("SERVER_NAME", pchVarAll, &dwSize0);"
    */
    if (!found )
    siteId = _T("pdftest");

    // do the rest jobs
    CString queryParam(pLog->pszParameters);  
    CTime t = CTime::GetCurrentTime( );
    CString strGmt = t.FormatGmt("%m/%d/%Y %H:%M:%S");

    CString cs1 = "{CALL procLogPdf ('"+ strGmt+ "','" +host +
    "','"+page+"','"+ queryParam+"','"+clientIP+"','"+agent+"','"+m_CompName+"','"+siteId+"')};";

    BOOL goin = FALSE;
    CString csLocal = _T(" ");

    m_cs.Lock();
    csShared = csShared + cs1;
    counter++;

    if ( counter > 99 ) {  // >199
    counter = 0;
    csLocal = csShared;
    csShared = _T(" ");
    goin = TRUE;
    }
    m_cs.Unlock();

    if (goin )
    ProcessLogProc(csLocal);


    return SF_STATUS_REQ_NEXT_NOTIFICATION;
    }



  • Anonymous
    June 12, 2006
    David,
    We have an ISAPI filter that works fine with IIS 6.0 and Framwork1.1, After installing .net Framework 2.0 the Filter is not working properly. Any page i try to open ends up in http 503. I tried to debug and looks like CHttpFilter::GetFilterVersion(pVer); returns null in below code. Can you advice why this would happen.

    BOOL CMavFiltFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
    {
    // Call default implementation for initialization
    CHttpFilter::GetFilterVersion(pVer);

    // Clear the flags set by base class
    pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;

    // Set the flags we are interested in
    pVer->dwFlags |= SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_PREPROC_HEADERS;

    // Set Priority
    pVer->dwFlags |= SF_NOTIFY_ORDER_HIGH;

    // Load description string
    TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
    ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
    IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
    _tcscpy(pVer->lpszFilterDesc, sz);
    //_tcscpy_s(pVer->lpszFilterDesc, sz);
    return TRUE;
    }

    Thx

  • Anonymous
    June 12, 2006
    David,
    I debuged further and looks like the pFilter is null (0X00000). Can you tell me why this would happen.
    extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
    {
    try
    {
    #ifdef _AFXDLL
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    #endif

    BOOL bRet;
    ISAPIASSERT(pFilter != NULL);
    if (pFilter == NULL)
    bRet = FALSE;
    else
    bRet = pFilter->GetFilterVersion(pVer);

    return bRet;
    }
    catch(...)
    {
    ISAPITRACE("Error: unhandled exception caught!n");
    return FALSE;
    }
    }

    Thnx

  • Anonymous
    June 12, 2006
    The comment has been removed

  • Anonymous
    July 10, 2006
    Hi David, I am trying to doing an ISAPI filter for IIS 6.0 to redirect a user  to a particular URL whenever a user clicks on a pdf file.

    For eg : when a user clicks on a link http://localhost/downloads/download.pdf, I want to redirect user as follows

    http://localhost/validate.asp?retUrl=http://localhost/downloads/download.pdf.

    Can you please help me with the code?

  • Anonymous
    November 26, 2007
    Hi david , I have this code , I do not have much (almost nill ) knowledge of ISAPI, i have asked to write clean up code for "OnPreprocHeaders" as the code i have  giving us memory leak . I read your code on ISAPI filters , but still not able to get it much . Please help me in writing cleanup code for "OnPreprocHeaders" . Thanks! // HEADERVALUE4.CPP - Implementation file for your Internet Server //    HeaderValue4 Filter #include <iostream> #include <cstring> #include "stdafx.h" #include "HeaderValue4.h" #include "IniReader.h" #include "conio.h" #include "httpfilt.h" #include "httpext.h" #define DEFAULT_BUFFER_SIZE         1024 #define MAX_BUFFER_SIZE             4096 #define CONFIG_FILENAME                         "C:\inetpub\isapi\HeaderValue\Config.ini" BOOL hasLoadedConfig = false; /////////////////////////////////////////////////////////////////////// // The one and only CHeaderValue4Filter object CHeaderValue4Filter theFilter; /////////////////////////////////////////////////////////////////////// // CHeaderValue4Filter implementation CHeaderValue4Filter::CHeaderValue4Filter() { } CHeaderValue4Filter::~CHeaderValue4Filter() { } BOOL CHeaderValue4Filter::GetFilterVersion(PHTTP_FILTER_VERSION pVer) {        // Call default implementation for initialization        CHttpFilter::GetFilterVersion(pVer);        // Clear the flags set by base class        pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;        // Set the flags we are interested in        pVer->dwFlags |= SF_NOTIFY_ORDER_MEDIUM | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT                         | SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_END_OF_NET_SESSION;        // Load description string        TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];        ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),                        IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));        tcscpy(pVer->lpszFilterDesc, sz);        return TRUE; } DWORD CHeaderValue4Filter::OnPreprocHeaders(CHttpFilterContext* pCtxt,        PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo) {        // TODO: React to this notification accordingly and        // return the appropriate status code        // This line below would add a Reponse Header (..duh...just like it says)        //pCtxt->AddResponseHeaders("X-CustomDebug: OnPreprocHeadersrn", 0);        // Sample insert into the Requet header.  It will always put HTTP in the front        //pHeaderInfo->SetHeader( pCtxt->m_pFC, "USERNAME:", "xxxx\xxxx");    // Check to see if the globals have    // been loaded. If not, then load them //    if (!hasLoadedConfig) {                // Change this from a BOOL to a LastUpdated::DateTime check on the file                // to allow for real-time file updates.  No need to restart the web                // site/pool to re-read the file        // Load the globals from a file        /*                DWORD           dwRet = HSE_STATUS_SUCCESS;                BOOL            fRet = FALSE;                CHAR            pBuf[ DEFAULT_BUFFER_SIZE ];                CHAR *          pszBuf = pBuf;                DWORD           cbBuf = DEFAULT_BUFFER_SIZE;                fRet = pCtxt->GetServerVariable("INSTANCE_ID", pszBuf, &cbBuf);        /                /                              Got the Instance ID (but not checking for a failure) in pszBuf                        Now Read the specific HeaderValue.Instance.Ini and                        Find the Config Value "Headers", then split on | and add each                        to the Headers (escaping "")                                pHeaderInfo->SetHeader( pCtxt->m_pFC, "USERNAME:", "xxxx\xxxx");                /        //  This section is the partial working one                CIniReader iniReader(CONFIG_FILENAME);                char szGLame = iniReader.ReadString("Global", "Keys", "");                //char input[] = _T("Tom,Archer,Programmer/Trainer,CodeGuru");                char input[ DEFAULT_BUFFER_SIZE ];                strcpy(input, szGLame);                char delimiters[] = _T(",");                pHeaderInfo->SetHeader( pCtxt->m_pFC, "ABC-HeaderValue4:", "Alpha Release");                pCtxt->AddResponseHeaders("X-ABC-HeaderValue4: Alpha Releasern", 0);                //pHeaderInfo->SetHeader( pCtxt->m_pFC, "Global:", szGLame);                char tmpResult[100];                char result = NULL;                result = strtok( input, delimiters );                while( result != NULL ) {                        char val =  iniReader.ReadString("Setting", result, "");                        strncpy(tmpResult, result, 99);                        strcat(tmpResult, ":");                        pHeaderInfo->SetHeader( pCtxt->m_pFC, tmpResult, val);                        //printf( "result is "%s"n", result );                        result = strtok( NULL, delimiters );                }                // Add Them                //pHeaderInfo->SetHeader( pCtxt->m_pFC, "W3C_INSTANCE_ID:", pBuf);        hasLoadedConfig=true; //    }        return SF_STATUS_REQ_NEXT_NOTIFICATION; } /        BOOL WINAPI GetServerVariable(                  PHTTP_FILTER_CONTEXT pfc,                  LPSTR lpszVariableName,                  LPVOID lpvBuffer,                  LPDWORD lpdwSize        ); / DWORD CHeaderValue4Filter::OnEndOfNetSession(CHttpFilterContext pCtxt) {        // TODO: React to this notification accordingly and        // return the appropriate status code        return SF_STATUS_REQ_NEXT_NOTIFICATION; } // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CHeaderValue4Filter, CHttpFilter)        //{{AFX_MSG_MAP(CHeaderValue4Filter)        //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif  // 0 /////////////////////////////////////////////////////////////////////// // If your extension will not use MFC, you'll need this code to make // sure the extension objects can find the resource handle for the // module.  If you convert your extension to not be dependent on MFC, // remove the comments arounn the following AfxGetResourceHandle() // and DllMain() functions, as well as the g_hInstance global. /*** static HINSTANCE g_hInstance; HINSTANCE AFXISAPI AfxGetResourceHandle() {        return g_hInstance; } BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason,                                        LPVOID lpReserved) {        if (ulReason == DLL_PROCESS_ATTACH)        {                g_hInstance = hInst;        }        return TRUE; }

  • Anonymous
    February 04, 2010
    Hi David, Is there a way to determine the physical file location of the URL in MFC? I am not using asp.net so that I can't use Server.MapPath(). Thanks, Pratheesh