New Sec-* headers in WebView2

Viewed 201

Working with MS WebView2 in C++ I can see a number of "Sec-*"-headers if visiting https://manytools.org/http-html-text/http-request-headers/

Example of a few:

Sec-Fetch-Dest document
Sec-Fetch-User ?1
Sec-Fetch-Mode navigate
Sec-Fetch-Site none
Sec-Ch-Ua-Mobile ?0
Sec-Ch-Ua "Not A;Brand";v="99", "Chromium";v="100", "Microsoft Edge";v="100", "Microsoft Edge WebView2";v="100"

These new headers are mentioned in https://wicg.github.io/ua-client-hints/

Is there any way to access/edit those headers, preferably in C++?

It's possible to disable the Sec-Ch headers with a command line option:

--disable-features=UserAgentClientHint

and to do that from C++:

Microsoft::WRL::ComPtr<CoreWebView2EnvironmentOptions> options = Microsoft::WRL::Make<CoreWebView2EnvironmentOptions>();
options->put_AdditionalBrowserArguments(L"--disable-features=UserAgentClientHint");

However, I want to be able to edit those values.

Further googling revealed this page which I guess answers this post: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name

1 Answers

You are correct that the sec-* headers are part of the "forbidden header" lists. But they are forbidden for client code like the JS that runs on the user-agent. But user-agents like the browser can set those fields.

You can change some of the sec-* headers inside a callback added to add_WebResourceRequested. Some fields like Sec-Fetch-Site get overwritten afterwards, others like Sec-Fetch-Mode can be set, but can't be deleted because they will get a default value, if not set after the WebResourceRequestedEvent. But you can change most of the sec-ch ones like this:

NOTE: this code is only to demonstrate the approach, it's missing a bunch of error handling

EventRegistrationToken webResourceRequestedToken;
webviewWindow->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
webviewWindow->add_WebResourceRequested(
  Callback<ICoreWebView2WebResourceRequestedEventHandler>([](ICoreWebView2* sender,
                                                             ICoreWebView2WebResourceRequestedEventArgs* args) {
    COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext;
    args->get_ResourceContext(&resourceContext);
    ICoreWebView2WebResourceRequest* req = nullptr;
    ICoreWebView2HttpRequestHeaders* headers = nullptr;
    ICoreWebView2HttpHeadersCollectionIterator* iter = nullptr;
    args->get_Request(&req);
    req->get_Headers(&headers);
    headers->GetIterator(&iter);
    BOOL hasCurrent = FALSE;
    iter->get_HasCurrentHeader(&hasCurrent);
    std::vector<std::wstring> headersToDelete;
    std::wstring secChPrefix = L"sec-ch";
    while (hasCurrent) {
      LPWSTR name = nullptr, value = nullptr;
      iter->GetCurrentHeader(&name, &value);
      if (secChPrefix.compare(0, secChPrefix.size(), name, secChPrefix.size()) == 0) {
        headersToDelete.push_back(name);
      }
      iter->MoveNext(&hasCurrent);
    }
    for (auto header : headersToDelete) {
      headers->RemoveHeader(header.c_str());
    }
    // Setting "Sec-Fetch-Site" will have no effect, will get overwritten afterwards
    headers->SetHeader(L"Sec-Fetch-Site", L"same-origin");
    // This will work, but removing this key will just make it take the default value
    headers->SetHeader(L"Sec-Fetch-Mode", L"same-origin");

    return S_OK;
  }).Get(),
  &webResourceRequestedToken);
Related