Реализация IHttpFilter вызывает нарушение прав доступа для вызова HttpClient :: GetStringAsync - PullRequest
0 голосов
/ 23 мая 2018

Я нахожусь в процессе выделения OAuth-аутентификации в IHttpFilter для использования с HttpClient .Я использую следующий код для тестирования, ожидая, что он просто перенаправит все запросы в HttpBaseProtocolFilter :

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Filters.h>

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Http;
using namespace Windows::Web::Http::Filters;

struct TestHttpFilter : implements<TestHttpFilter, IHttpFilter>
{
    TestHttpFilter(IHttpFilter inner_filter) : inner_filter_{ inner_filter } {}
    IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage const& request) const
    {
        auto const result{ co_await inner_filter_.SendRequestAsync(request) };
        co_return result;
    }
private:
    IHttpFilter inner_filter_{ nullptr };
};

int main()
{
    init_apartment();

    IHttpFilter const base_filter{ HttpBaseProtocolFilter{} };
    IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
    HttpClient const http_client{ test_filter };

    auto const result{ http_client.GetStringAsync({ L"http://aka.ms/cppwinrt" }).get() };

    printf("Response: %ls!\n", result.c_str());
}

Цепочка фильтров правильно создана и передана в HttpClient не могу.При выполнении вызова GetStringAsync код падает внутри TestHttpFilter::SendRequestAsync со следующей ошибкой:

Exception thrown at <address> in <app>.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

Это выглядит как указатель NULL, разыменованный в вызове put_abiвнутри заголовочного файла SDK (пространства имен опущены для краткости):

template <typename D> IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> consume_Windows_Web_Http_Filters_IHttpFilter<D>::SendRequestAsync(HttpRequestMessage const& request) const
{
    IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> operation{ nullptr };
    check_hresult(WINRT_SHIM(IHttpFilter)->SendRequestAsync(get_abi(request), put_abi(operation)));
    return operation;
}

Я не понимаю, где я ошибся с этим.Я надеюсь разобраться в этом с ответами на следующие вопросы:

  • Что-то не так с реализацией TestHttpFilter?
  • Можно ли использовать фильтры HTTP с удобными реализациямиHttpClient (например, GetStringAsync), или мы должны пройти через интерфейс SendRequestAsync при использовании фильтров?
  • Весьма маловероятно, но может ли это быть проблемой сгенерированных заголовков SDK, выбравнеподходящий c'tor для локального operation объекта?

Я могу воспроизвести проблему, используя официальную версию Windows SDK 10.0.17134.0.

1 Ответ

0 голосов
/ 25 мая 2018

Проекция C ++ / WinRT имеет некоторую двойственность типов 1 : есть типы реализации , которые также обеспечивают реализацию класса времени выполнениякак спроецированные типы , которые содержат леса, требуемые средой выполнения Windows, и действуют как прокси-сервер для типа реализации.

Это различие становится важным, когда вы создаете класс среды выполнения, который должен использоватьсяс помощью Windows Runtime API.Код, о котором идет речь, реализует тип, но не может создать соответствующий проектируемый тип.Ошибка в следующих строках кода:

IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
HttpClient const http_client{ test_filter };

Первая строка создает экземпляр типа реализации .Вторая строка передает его в HttpClient c'tor, который ожидает проецируемого типа 2 .Исправление состоит в том, чтобы вместо этого построить прогнозируемый тип для TestHttpFilter, что удобно сделать с помощью шаблона функции make :

IHttpFilter const test_filter{ make<TestHttpFilter>(base_filter) };
HttpClient const http_client{ test_filter };

Общие рекомендации:

  • Всегда убедитесь, что вы понимаете, с каким типом вы работаете.Установите соглашения об именах, чтобы различать типы реализации и прогнозируемые типы.
  • При пересечении ABI (обычно) требуется передать проецируемый тип.Обычно вы пересекаете ABI при вызове API среды выполнения Windows или когда возвращаете значение из типа реализации.
  • Что бы вы ни делали, не допускайте, чтобы это не сработало во время выполнения.Скорее всего, в этой вселенной есть не более одного человека, который может помочь вам, когда вы туда доберетесь.

1 См. Чтоозначают спроецированный тип и тип реализации?

2 В идеале это не должно компилироваться, хотя я не знаю, как это реализоватьбез (излишне) ограничения универсальности библиотеки общего назначения.

...