Как получить доступ к сайту HTTPS через прокси с помощью Hyper?

Ниже приведена попытка доступа к HTTPS-сайту через прокси:

extern crate hyper;
extern crate hyper_native_tls;

use hyper::net::HttpsConnector;
use hyper::client::{Client, ProxyConfig};
use hyper_native_tls::NativeTlsClient;

fn main() {
    let ssl = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);

    let client = Client::with_proxy_config(
        ProxyConfig::new(
            "http", "localhost", 3128, connector, ssl
        )
    );

    let response = client.get("https://httpbin.org").send().unwrap();
    println!("{}", response.headers);
}

Я получаю эту ошибку:

error[E0277]: the trait bound `hyper_native_tls::TlsStream<hyper::net::HttpStream>: std::fmt::Debug` is not satisfied
  --> src/main.rs:13:9
   |
13 |         ProxyConfig::new(
   |         ^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `hyper_native_tls::TlsStream<hyper::net::HttpStream>`
   |
   = note: `hyper_native_tls::TlsStream<hyper::net::HttpStream>` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>`
   = note: required because of the requirements on the impl of `hyper::net::SslClient<hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>>` for `hyper_native_tls::NativeTlsClient`
   = note: required by `<hyper::client::ProxyConfig<C, S>>::new`

error[E0277]: the trait bound `hyper_native_tls::TlsStream<hyper::net::HttpStream>: std::fmt::Debug` is not satisfied
  --> src/main.rs:13:9
   |
13 |           ProxyConfig::new(
   |  _________^ starting here...
14 | |             "http", "localhost", 3128, connector, ssl
15 | |         )
   | |_________^ ...ending here: the trait `std::fmt::Debug` is not implemented for `hyper_native_tls::TlsStream<hyper::net::HttpStream>`
   |
   = note: `hyper_native_tls::TlsStream<hyper::net::HttpStream>` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>`
   = note: required because of the requirements on the impl of `hyper::net::SslClient<hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>>` for `hyper_native_tls::NativeTlsClient`
   = note: required by `hyper::client::ProxyConfig`

error[E0277]: the trait bound `hyper_native_tls::TlsStream<hyper::net::HttpStream>: std::fmt::Debug` is not satisfied
  --> src/main.rs:12:18
   |
12 |     let client = Client::with_proxy_config(
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `hyper_native_tls::TlsStream<hyper::net::HttpStream>`
   |
   = note: `hyper_native_tls::TlsStream<hyper::net::HttpStream>` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>`
   = note: required because of the requirements on the impl of `hyper::net::SslClient<hyper::net::HttpsStream<hyper_native_tls::TlsStream<hyper::net::HttpStream>>>` for `hyper_native_tls::NativeTlsClient`
   = note: required by `hyper::Client::with_proxy_config`

Вот зависимости Cargo:

[dependencies]
hyper = "0.10"
hyper-native-tls = "0.2"

Лучше использовать эти зависимости:

[dependencies]
hyper = "0.10"
hyper-openssl = "0.2"

И этот код:

extern crate hyper;
extern crate hyper_openssl;

use hyper::net::HttpsConnector;
use hyper::client::{Client, ProxyConfig};
use hyper_openssl::OpensslClient as TlsClient;

fn main() {
    let ssl = TlsClient::new().unwrap();
    let connector = HttpsConnector::new(ssl.clone());

    let client = Client::with_proxy_config(
        ProxyConfig::new(
            "http", "localhost", 3128, connector, ssl
        )
    );

    let response = client.get("https://httpbin.org").send().unwrap();
    println!("{:#?}", response);
}

Выход:

Response {
    status: Ok,
    headers: Headers { Server: nginx, Date: Thu, 12 Jan 2017 15:05:13 GMT, Content-Type: text/html; charset=utf-8, Content-Length: 12150, Connection: keep-alive, Access-Control-Allow-Origin: *, Access-Control-Allow-Credentials: true, },
    version: Http11,
    url: "https://httpbin.org/",
    status_raw: RawStatus(
        200,
        "OK"
    ),
    message: Http11Message {
        is_proxied: false,
        method: None,
        stream: Wrapper {
            obj: Some(
                Reading(
                    SizedReader(remaining=12150)
                )
            )
        }
    }
}

Сбоев при сборке нет, но через прокси не проходит.


person tshepang    schedule 12.01.2017    source источник
comment
Разве все эти ошибки не вызваны тем фактом, что вы пытаетесь напечатать response в режиме отладки, когда он не реализует Debug?   -  person ljedrz    schedule 12.01.2017
comment
Я получаю ту же ошибку, даже если я ничего не печатаю   -  person tshepang    schedule 12.01.2017
comment
Ни одна из структур на hyper_native_tls не подразумевает Debug, поэтому поведение, наблюдаемое в этом коде, будет правильным. Пожалуйста, убедитесь, что вы не выполняете никаких fmt(), и обновите вопрос с учетом ваших выводов.   -  person E_net4 the curator    schedule 12.01.2017
comment
@E_net4: Вероятно, должен быть ответ. Я проверил ProxyConfig и Client и не требует Debug, поэтому кажется, что OP выстрелил себе в ногу... и что сообщение об ошибке не очень хорошее. Или, может быть, он не использует последнюю версию Hyper (0.10.0), и поэтому документы, с которыми я консультируюсь, не очень хороши.   -  person Matthieu M.    schedule 12.01.2017
comment
@MatthieuM. В некотором смысле это правда. С другой стороны, вопрос низкого качества и вообще не относится к использованию вывода в формате Debug в своей формулировке. Я бы предпочел, чтобы его либо улучшили, либо удалили. Мне также интересно, есть ли подходящий дубликат.   -  person E_net4 the curator    schedule 12.01.2017
comment
Я обновил Вопрос @E_net4   -  person tshepang    schedule 12.01.2017
comment
И ошибка по-прежнему не может быть отформатирована с помощью :??   -  person ljedrz    schedule 12.01.2017
comment
@ljedrz да, та же ошибка   -  person tshepang    schedule 12.01.2017


Ответы (1)


Были некоторые непроверенные конфликты вокруг ящиков hyper_native_tls и native_tls.

В настоящее время существует ограничение на реализацию SslClient для NativeTlsClient, для которой требуется T: Debug (код). Код в вопросе не компилируется, потому что TlsStream не реализует Debug, независимо от типа его параметра.

Сначала можно было рассмотреть возможность снятия вышеупомянутого ограничения. Но это вызывает несколько других ошибок в hyper_native_tls:

error[E0277]: the trait bound `T: std::fmt::Debug` is not satisfied
   --> src/lib.rs:129:45
    |
129 |             Err(e) => Err(hyper::Error::Ssl(Box::new(e))),
    |                                             ^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `T`
    |
    = help: consider adding a `where T: std::fmt::Debug` bound
    = note: required because of the requirements on the impl of `std::error::Error` for `native_tls::HandshakeError<T>`
    = note: required for the cast to the object type `std::error::Error + std::marker::Sync + std::marker::Send + 'static`

Спускаясь в кроличью нору, мы обнаруживаем, что native_tls::HandshakeError содержит тип параметра S потока, который был прерван (в случае этой конкретной ошибки). Это стало еще одной проблемой, потому что тип реализует только Debug, где S: Debug, и в соответствии с Error, типы ошибок всегда должны реализовывать Debug.

Исправление этой конкретной проблемы заключается в предоставлении Debug для TlsStream:

#[derive(Debug, Clone)]
pub struct TlsStream<S>(Arc<Mutex<native_tls::TlsStream<S>>>);

Первый фрагмент кода по-прежнему не скомпилируется, потому что ssl используется после перемещения, а копирование здесь недопустимо. Второй фрагмент работает путем клонирования объекта, что, к сожалению, не реализовано для NativeTlsClient. Мы также не можем получить реализацию, потому что native_tls::TlsConnector также не реализует Clone. Что касается этой кроличьей норы, она, вероятно, должна закончиться здесь, прежде чем это станет отчетом об отладке.

Я не совсем уверен, что здесь можно сделать (кроме того, чтобы вообще не использовать собственный TLS), но мой текущий совет — зарегистрировать проблему в hyper_native_tls_client, объяснив, что он не работает с клиентским прокси-сервером Hyper (редактировать: сделано и исправлено!).

person E_net4 the curator    schedule 12.01.2017
comment
github.com/sfackler/hyper-native-tls/commit/ - person tshepang; 12.01.2017
comment
@Tshepang Хорошая работа. ;) - person E_net4 the curator; 13.01.2017