Rede

Este guia mostra como trabalhar com a funcionalidade relacionada com a rede, como proxy, eventos de rede, autenticação, TLS, autenticação de certificado de cliente, etc.

A funcionalidade relacionada com a rede pode ser acessada através da instância Network que pode ser obtida da seguinte forma:

Network network = profile.network();
val network = profile.network()

Cabeçalho Accept-Language

O JxBrowser permite configurar o valor do cabeçalho HTTP Accept-Language através do método Network.acceptLanguage(String).

Por exemplo, o valor “fr, en-gb;q=0.8, en;q=0.7” significaria: “Prefiro francês, mas aceito inglês britânico e outros tipos de inglês”:

network.acceptLanguage("fr, en-gb;q=0.8, en;q=0.7");
network.acceptLanguage("fr, en-gb;q=0.8, en;q=0.7")

Servidores Whitelist

Whitelist de Autorização do Servidor HTTP

Você pode configurar a lista branca de autorização do servidor HTTP que representa uma string com uma lista de URLs separados por vírgula/semicoluna. Por exemplo:

network.httpAuthPreferences().serverWhitelist("*google.com,*example.com,*baz");
network.httpAuthPreferences().serverWhitelist("*google.com,*example.com,*baz")

Whitelist de Delegados de Rede HTTP

Para configurar a lista branca de delegados de rede HTTP, você pode utilizar a abordagem descrita abaixo:

network.httpAuthPreferences().delegateWhitelist("*google.com,*example.com,*baz");
network.httpAuthPreferences().delegateWhitelist("*google.com,*example.com,*baz")

TLS

Verificação do Certificado

Por padrão, o Chromium verifica todos os certificados SSL obtidos de um servidor Web durante o carregamento da página Web. O JxBrowser permite modificar este comportamento padrão e assumir o controle do processo de verificação.

Para lidar com a verificação de certificados, utilize a chamada de retorno VerifyCertificateCallback. Antes de esta chamada de retorno ser invocada, o Chromium verifica o certificado SSL e fornece os resultados da verificação à chamada de retorno. Com os resultados da verificação, a chamada de retorno recebe o próprio certificado SSL. É possível verificar o certificado SSL fornecido e notificar o motor com os resultados da verificação.

Por exemplo:

network.set(VerifyCertificateCallback.class, (params) -> {
    // Certificado SSL a verificar.
    Certificate certificate = params.certificate();
    // Os resultados da verificação efetuada pelo verificador padrão.
    List<CertVerificationError> verificationErrors =
        params.verificationErrors();
    // Devem ser utilizados os resultados da verificação padrão.
    return Response.defaultAction();
});
network.set(VerifyCertificateCallback::class.java, VerifyCertificateCallback { params ->
    // SSL Certificate to verify.
    val certificate = params.certificate()
    // The results of the verification performed by default verifier.
    val verificationErrors = params.verificationErrors()
    // Devem ser utilizados os resultados da verificação padrão.
    Response.defaultAction()
})

Autenticação do Certificado do Cliente

O JxBrowser suporta a autenticação utilizando certificados de cliente HTTPS. Para mais informações, consulte o guia Autenticação.

Esquemas

A biblioteca fornece uma API que permite registrar os esquemas personalizados e interceptar requests URL com os esquemas padrão, como HTTP ou HTTPS.

Em ambos os casos, os requests de URL com o esquema correspondente serão interceptados e os dados de resposta serão fornecidos como se fossem enviados por um servidor Web. Utilizando esta funcionalidade, é possível emular a resposta de um servidor remoto e utilizar uma espécie de servidor Web local.

Registrar um Esquema Personalizado

Para registrar um esquema personalizado utilize o método EngineOptions.Builder.addScheme() durante a configuração do Engine. Isso é necessário porque o Chromium registra todos os esquemas durante o inicialização e não permite a modificação de esquemas depois de ter sido inicializado.

O código a seguir demonstra como registrar um esquema personalizado e associar a chamada de retorno InterceptUrlRequestCallback que será invocada sempre que o navegador carregar um recurso por um URL com o esquema fornecido:

EngineOptions options = EngineOptions
        .newBuilder(renderingMode)
        .addScheme(Scheme.of("jxb"), params -> {
            UrlRequestJob job = params.newUrlRequestJob(
                    UrlRequestJob.Options
                            .newBuilder(HttpStatus.OK)
                            .addHttpHeader(HttpHeader.of("Content-Type", "text/plain"))
                            .build());
            job.write("Hello!".getBytes());
            job.complete();
            return Response.intercept(job);
        })
        .build();
Engine engine = Engine.newInstance(options);
val options = EngineOptions
        .newBuilder(renderingMode)
        .addScheme(Scheme.of("jxb"), InterceptUrlRequestCallback { params ->
            val job = params.newUrlRequestJob(
                    UrlRequestJob.Options
                            .newBuilder(HttpStatus.OK)
                            .addHttpHeader(HttpHeader.of("Content-Type", "text/plain"))
                            .build())
            job.write("Hello!".toByteArray())
            job.complete()
            Response.intercept(job)
        })
        .build()
val engine = Engine.newInstance(options)

Agora, se você carregar jxb://anyhost/anypage.html, os requests de URL serão interceptados e a chamada de retorno associada será invocada. Você obterá o seguinte resultado:

Esquema personalizado

Interceptação de Requests HTTP/HTTPS

A mesma abordagem com o registro de um esquema personalizado pode ser utilizada para interceptar os esquemas padrão, como HTTP ou HTTPS. Neste caso, é necessário adicionar o esquema correspondente, como indicado abaixo:

EngineOptions options = EngineOptions
        .newBuilder(renderingMode)
        .addScheme(Scheme.HTTPS, params -> {
            UrlRequestJob job = params.newUrlRequestJob(...);
            ...
            return Response.intercept(job);
        })
        ...
EngineOptions options = EngineOptions
        .newBuilder(renderingMode)
        .addScheme(Scheme.HTTPS, InterceptUrlRequestCallback { params ->
            val job = params.newUrlRequestJob(...);
            ...
            Response.intercept(job)
        })
        ...

Eventos de Rede e Chamadas de Retorno

A API Network define um conjunto de eventos e chamadas de retorno que seguem o ciclo de vida de um request Web. Você pode utilizar estes eventos para observar e analisar o tráfego. As chamadas de retorno lhe permitirão interceptar, bloquear ou modificar requests.

O ciclo de vida dos eventos de requests bem sucedidos é o seguinte: Fluxo de eventos de rede

Antes do Request de URL

A chamada de retorno BeforeUrlRequestCallback é invocada quando uma solicitação HTTP está prestes a ocorrer. Você pode utilizar esta chamada de retorno para redirecionar o request para outra localização. Por exemplo:

network.set(BeforeUrlRequestCallback.class, (params) ->
        Response.redirect("<new-url>"));
network.set(BeforeUrlRequestCallback::class.java,
    BeforeUrlRequestCallback {  Response.redirect("<new-url>") }
)

Antes do Upload de Dados

A chamada de retorno BeforeSendUploadDataCallback é invocada antes dos dados de upload serem enviados para um servidor Web. Aqui você pode sobrescrever os dados de upload. Por exemplo:

network.set(BeforeSendUploadDataCallback.class, (params) ->
        Response.override(TextData.of("<text-data>")));
network.set(BeforeSendUploadDataCallback::class.java,
    BeforeSendUploadDataCallback {  Response.override(TextData.of("<text-data>")) }
)

Esta chamada de retorno não será chamada se o request não tiver os dados de upload.

São suportados os seguintes tipos de UploadData:

  • BytesData representa uma sequência de bytes, o tipo de conteúdo é configurável.
  • TextData os dados do tipo de conteúdo text/plain.
  • FormData os dados do tipo de conteúdo application/x-www-form-urlencoded.
  • MultipartFormData os dados do tipo de conteúdo multipart/form-data.

Antes de Iniciar a Transação

A chamada de retorno BeforeStartTransactionCallback é invocada antes do início da transação de rede. Nesta chamada de retorno, você pode adicionar ou substituir os cabeçalhos HTTP antes de serem enviados. Por exemplo:

network.set(BeforeStartTransactionCallback.class, (params) -> {
    List<HttpHeader> httpHeaders = new ArrayList<>(params.httpHeaders());
    httpHeaders.add(HttpHeader.of("<header-name>", "<header-value>"));
    return Response.override(httpHeaders);
});
network.set(BeforeStartTransactionCallback::class.java,
    BeforeStartTransactionCallback { params ->
        val httpHeaders = buildList<HttpHeader> {
            addAll(params.httpHeaders())
            add(HttpHeader.of("<header-name>", "<header-value>"))
        }
        Response.override(httpHeaders)
    }
)

Esta chamada de retorno não capta os seguintes cabeçalhos. Esta lista está sujeita a alterações e pode não estar completa:

- Authorization
- Cache-Control
- Connection
- Content-Length
- Host
- If-Modified-Since
- If-None-Match
- If-Range
- Partial-Data
- Pragma
- Proxy-Authorization
- Proxy-Connection
- Transfer-Encoding

Receber Cabeçalhos

A chamada de retorno ReceiveHeadersCallback é invocada para requests HTTP quando os cabeçalhos são recebidos. Aqui você pode adicionar, modificar ou remover os cabeçalhos HTTP recebidos através da rede. Por exemplo:

network.set(ReceiveHeadersCallback.class, (params) -> {
    List<HttpHeader> httpHeaders = new ArrayList<>(params.httpHeaders());
    httpHeaders.add(HttpHeader.of("<header-name>", "<header-value>"));
    return Response.override(httpHeaders);
});
network.set(ReceiveHeadersCallback::class.java,
    ReceiveHeadersCallback { params ->
        val httpHeaders = buildList<HttpHeader> {
            addAll(params.httpHeaders())
            add(HttpHeader.of("<header-name>", "<header-value>"))
        }
        Response.override(httpHeaders)
    }
)

Código de Resposta de Redirecionamento Recebido

O evento RedirectResponseCodeReceived é disparado quando um código de resposta de redirecionamento 3xx é recebido para o request. Neste evento, você pode obter os detalhes sobre o redirecionamento, como o novo URL e o código de resposta. Por exemplo:

network.on(RedirectResponseCodeReceived.class, (event) -> {
    String newUrl = event.newUrl();
    int responseCode = event.responseCode();
});
network.on(RedirectResponseCodeReceived::class.java) { event -> 
    val newUrl = event.newUrl()
    val responseCode = event.responseCode()
}

Resposta Iniciada

O evento ResponseStarted é disparado quando o primeiro byte do corpo da resposta do URL é recebido. Para os pedidos HTTP, isto significa que a linha de estado e os cabeçalhos de resposta estão disponíveis. Neste evento, é possível acessar o request correspondente e o código de resposta. Por exemplo:

network.on(ResponseStarted.class, (event) -> {
    UrlRequest urlRequest = event.urlRequest();
    int responseCode = event.responseCode();
});
network.on(ResponseStarted::class.java) { event -> 
    val urlRequest = event.urlRequest()
    val responseCode = event.responseCode()
}

Request Concluído

O evento RequestCompleted é disparado quando o request de URL foi concluído com sucesso ou falhou. Neste evento, é possível verificar se o request foi iniciado, obter os detalhes do estado do request e acessar o código de resposta. Por exemplo:

network.on(RequestCompleted.class, (event) -> {
    UrlRequest urlRequest = event.urlRequest();
    // Os detalhes do estado do request de URL.
    UrlRequestStatus urlRequestStatus = event.status();
    // O código de resposta HTTP.
    int responseCode = event.responseCode();
});
network.on(RequestCompleted::class.java) { event -> 
    val urlRequest = event.urlRequest()
    // Os detalhes do estado do request de URL.
    val urlRequestStatus = event.status()
    // O código de resposta HTTP.
    val responseCode = event.responseCode()
}

Request Destruído

O evento RequestDestroyed é disparado quando o request é destruído e não pode mais ser utilizado. Para acessar os detalhes do request destruído, utilize o seguinte código:

network.on(RequestDestroyed.class, (event) -> {
    UrlRequest urlRequest = event.urlRequest();
});
network.on(RequestDestroyed::class.java) { event -> 
    val urlRequest = event.urlRequest()
}

Bytes de Resposta Recebidos

O evento ResponseBytesReceived é disparado quando uma parte do corpo da resposta HTTP é recebida através da rede. Ele permite acessar os bytes do corpo da resposta HTTP:

network.on(ResponseBytesReceived.class, event -> {
    byte[] data = event.data();
});
network.on(ResponseBytesReceived::class.java) { event ->
    val data = event.data()
}

As partes do corpo da resposta podem ser apresentadas numa ordem aleatória. Tenha isso em mente ao restaurar a resposta completa usando este evento.

Estado da Conexão

O Chromium monitora o estado da conexão à Internet. Quando a conexão é interrompida e depois restaurada, o Chromium detecta a alteração e volta a carregar a página Web atualmente carregada. Você pode obter as notificações correspondentes utilizando a seguinte API:

network.on(NetworkChanged.class, e -> {
    // Se o tipo de conexão for TYPE_NONE, não existe qualquer conexão.
    if (e.connectionType() == ConnectionType.TYPE_NONE) {
        // A conexão de rede foi interrompida. Estamos offline.
    } else {
        // A conexão de rede foi restabelecida.
    }
});
network.on(NetworkChanged::class.java) { e ->
    // If the connection type is TYPE_NONE, there is no connection.
    if (e.connectionType() == ConnectionType.TYPE_NONE) {
        // A conexão de rede foi interrompida. Estamos offline.
    } else {
        // A conexão de rede foi restabelecida.
    }
}
Go Top