Rewriting Bookmarks for Atlas?

I have not checked out the AJAX craze surrounding Atlas, so I am not certain what is the goal here. However, that does not stop me from making observations about how the user's code is not exactly doing what is hoped... ;-)

Question:

When I have a URL that includes a bookmark (#) referencing a named anchor tag, I want to convert that portion into a part of the Querystring. (Can enable ATLAS pages to use the browser's Back/Forward buttons.) Here's my code:

 DWORD CRedirectorFilter::OnPreprocHeaders(CHttpFilterContext* pCtxt, PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo)
{
    char buf[2048];
    DWORD bufSize = sizeof(buf);
    BOOL bHeader = pHeaderInfo->GetHeader(pCtxt->m_pFC, "url", buf, &bufSize); 
    CString url(buf);

    if (url.Find("#") != -1)
    {
        url.Replace("#","&bkmk=");         // Bookmarks turn into a querystring item
        pHeaderInfo->SetHeader(pCtxt->m_pFC, "url", url.GetBuffer(url.GetLength()));
        return SF_STATUS_REQ_HANDLED_NOTIFICATION;   // We've got it
    }
    return SF_STATUS_REQ_NEXT_NOTIFICATION;          // Let IIS handle it
}

Apparently tying into OnPreprocHeaders doesn't give me what I want. At that point anything from the pound symbol onwards is already gone, even though the log file shows it.

Since # shows up in the log, I'm wondering if it's possible to tie in when it's logging to snag the bookmarked piece, then write it out somehow back as a new server header. Any way that the ASPX page can pick it up, that would work wonderfully!

Answer:

Actually, I do not think that you wrote the filter to do what you wanted.

Your filter returns SF_STATUS_REQ_HANDLED_NOTIFICATION from SF_NOTIFY_PREPROC_HEADERS, which depending on configured FilterLoadOrder relative to the ASP.Net ISAPI Filter, you could be short-circuiting it from also performing its tasks (which include cookieless session state maintenance, /bin filtering, etc). In general, do not return SF_STATUS_REQ_HANDLED_NOTIFICATION unless you completely control all ISAPI Filters running on the server or know how they all work.

Snagging the bookmark during logging will never work because logging happens AFTER the request has been processed. You are interested in making this transformation prior to request execution.

It is trivial to add a new Request Header and later use GetServerVariable() to retrieve the request header. You can do this with the following code snippet.

Enjoy.

//David

 DWORD
CRedirectorFilter::OnPreprocHeaders(
    CHttpFilterContext*             pCtxt, 
    PHTTP_FILTER_PREPROC_HEADERS    pHeaderInfo
)
{
    CHAR*   pCursor = NULL
    CHAR    buf[ 2048 ];
    DWORD   dwBufSize = sizeof( buf );
    BOOL    fHeader = FALSE;

    fHeader = pHeaderInfo->GetHeader( pCtxt->m_pFC, "url", buf, &dwBufSize ); 
    if ( FALSE == bHeader )
    {
        // Failed to retrieve URL
        if ( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
        {
            // 2048 bytes is not big enough. You decide whether to resize or not
            goto Finished;
        }
        else
        {
            goto Finished;
        }
    }

    // Actually retrieved the URL

    pCursor = strchr( buf, '#' );
    if ( NULL != pCursor )
    {
        //
        // found #, now save its value as a header called "BOOKMARK"
        // that can be retrieved as HTTP_BOOKMARK. Be careful of using
        // headers that include "_" or "-" because some cannot be
        // retrieved by ASP.Net ISAPI, by design of CGI 1.1 compatibility,
        // unless you are running on IIS6 and take advantage of some new
        // documuented features...
        //
        fHeader = pHeaderInfo->SetHeader( pCtxt->m_pFC, "BOOKMARK:", pCursor + 1 ); 
        if ( FALSE == fHeader )
        {
            // Failed to store the bookmark. You decide what happens.
            goto Finished;
        }
    }

    SetLastError( NO_ERROR );
Finished:
    //
    // Optional - check if GetLastError() is NO_ERROR
    // If not, you can return SF_STATUS_REQ_ERROR to halt processing
    //
    return NO_ERROR == GetLestError() ? 
           SF_STATUS_REQ_ERROR : 
           SF_STATUS_REQ_NEXT_NOTIFICATION;
}