0

I'm implementing my custom protocol handler by implementing IInternetProtocol interface and registering COM object in HKEY_CLASSES_ROOT\PROTOCOLS\Handler.

I want to be able to process the request and just leave the browser window as is (i.e. it must stay on the page with the link to my custom protocol).

Such a behavior normally achieved by returning HTTP 204 response.

I have implemented IWinInetHttpInfo interface for this. It processes HTTP_QUERY_REQUEST_METHOD, HTTP_QUERY_CONTENT_TYPE, HTTP_QUERY_VERSION, HTTP_QUERY_RAW_HEADERS_CRLF, HTTP_QUERY_STATUS_CODE requests.

But this does not help. Internet Explorer still switches the original page to a blank one with the URL of my custom protocol.

Any help, please?

Code:

SchemeHandlerImpl::SchemeHandlerImpl()
{
    m_headers =
        "HTTP/1.1 204 No Content\r\n"
        "Content-Length: 0\r\n"
        "Connection: close\r\n"
        "\r\n";

    m_response = "";
}

STDMETHODIMP SchemeHandlerImpl::Abort(HRESULT, DWORD)
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Continue(PROTOCOLDATA *)
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Resume()
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Start(
        LPCWSTR url,
        IInternetProtocolSink *sink,
        IInternetBindInfo *,
        DWORD grfPI,
        HANDLE_PTR)
{
    m_responsePos = 0;
    sink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, L"text/html");
    sink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, (ULONG)m_response.size());
    sink->ReportData(BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
                     (ULONG)m_response.size(), (ULONG)m_response.size());
    sink->ReportResult(S_OK, 0, nullptr);
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Suspend()
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Terminate(DWORD)
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::LockRequest(DWORD)
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::Read(LPVOID pv, ULONG to_read, ULONG *read)
{
    if (to_read > (m_response.size() - m_responsePos))
        to_read = m_response.size() - m_responsePos;
    if (to_read)
    {
        std::memcpy(pv, &m_response.front() + m_responsePos, to_read);
        m_responsePos += to_read;
    }
    *read = to_read;
    return to_read ? S_OK : S_FALSE;
}

STDMETHODIMP SchemeHandlerImpl::Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER*)
{
    return E_NOTIMPL;
}

STDMETHODIMP SchemeHandlerImpl::UnlockRequest()
{
    return S_OK;
}

STDMETHODIMP SchemeHandlerImpl::QueryInfo(
        DWORD dwOption,
        LPVOID pBuffer,
        DWORD  *pcbBuf,
        DWORD  *pdwFlags,
        DWORD *pdwReserved)
{
    if (LOWORD(dwOption) == HTTP_QUERY_REQUEST_METHOD)
    {
        wchar_t result[] = L"GET";
        std::memcpy(pBuffer, result, sizeof(result)-2);
        *pcbBuf = sizeof(result)-2;
        return S_OK;
    }

    if (LOWORD(dwOption) == HTTP_QUERY_CONTENT_TYPE)
    {
        wchar_t result[] = L"text/html";
        std::memcpy(pBuffer, result, sizeof(result)-2);
        *pcbBuf = sizeof(result)-2;
        return S_OK;
    }

    if (LOWORD(dwOption) == HTTP_QUERY_VERSION)
    {
        wchar_t result[] = L"HTTP/1.1";
        std::memcpy(pBuffer, result, sizeof(result)-2);
        *pcbBuf = sizeof(result)-2;
        return S_OK;
    }

    if (LOWORD(dwOption) == HTTP_QUERY_RAW_HEADERS_CRLF)
    {
        if (dwOption & HTTP_QUERY_FLAG_REQUEST_HEADERS)
            return E_NOTIMPL;

        std::wstring wheaders(m_headers.cbegin(), m_headers.cend());
        auto size = wheaders.size() * 2;
        if (*pcbBuf < size)
            return E_INVALIDARG;

        std::memcpy(pBuffer, &wheaders.front(), size);
        *pcbBuf = size;
        return S_OK;
    }

    if (LOWORD(dwOption) == HTTP_QUERY_STATUS_CODE)
    {
        if (dwOption & HTTP_QUERY_FLAG_NUMBER)
        {
            UINT code = 204;
            std::memcpy(pBuffer, &code, 4);
            *pcbBuf = 4;
            return S_OK;
        }
        else
        {
            wchar_t code[] = L"204";
            std::memcpy(pBuffer, code, sizeof(code)-2);
            *pcbBuf = sizeof(code)-2;
            return S_OK;
        }
    }

    return E_FAIL;
}

STDMETHODIMP SchemeHandlerImpl::QueryOption(
        DWORD dwOption,
        LPVOID pBuffer,
        DWORD  *pcbBuf)
{
    return INET_E_DEFAULT_ACTION;
}
Alexander Dyagilev
  • 1,139
  • 1
  • 15
  • 43
  • Does it work if you return a 205 (Reset Content), which is supposed to reload the page that generated the request? Also, are you sure that the response being sent back has no message body? See: [HTTP 204](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5) and [Message Body](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3) – theB May 24 '16 at 12:40
  • No, 205 does not work too. Yes, the response has no body. – Alexander Dyagilev May 24 '16 at 14:54
  • Hmm... HTTP 404 behaves the same way. – Alexander Dyagilev May 25 '16 at 01:51

1 Answers1

0

IInternetProtocolSink::ReportResult(INET_E_DATA_NOT_AVAILABLE, 204, nullptr) does the job!

Alexander Dyagilev
  • 1,139
  • 1
  • 15
  • 43