Filtrar qualquer URI de solicitação HTTP?

9

Eu quero filtrar qualquer URI de solicitação HTTP feito por meio da API HTTP.

Casos de uso:

  1. A verificação de atualização do WordPress vai para enlace , mas enlace também funciona, e eu quero usar isso sempre.
  2. O novo arquivo do WordPress foi retirado de enlace , mas enlace também funciona.
  3. Às vezes, quero depurar solicitações e redirecionar essas temporárias para um domínio personalizado no meu servidor local.
  4. Alguns plug-ins fazem solicitações a outros servidores e desejo substituir essas solicitações quando o servidor externo ficar inativo.

As solicitações de atualização são as mais importantes por enquanto, porque ainda há o unfixed bug 16778 ( Mais informações ), e solicitações HTTPS reduzem o risco de um ataque Man-in-the-middle.

Eu tenho pesquisado completamente , eu estudei o código principal… mas terminei como o Nacin dois anos atrás:

  

Eu pensei que você poderia filtrar a URL de uma solicitação HTTP, mas agora não consigo encontrar uma.

O que eu perdi? Eu fiz? :)

    
por fuxia 14.11.2012 / 08:08

3 respostas

8

Menos que uma resposta, mas apenas uma lista de coisas diretamente da minha experiência com ela - talvez você tenha esquecido algo.

Depurando o pedido & seus resultados

Sem aprofundar muito no processo de atualização, mas a API HTTP do WP usa a classe WP_HTTP . Também oferece uma coisa legal: um gancho de depuração.

do_action( 'http_api_debug', $response, 'response', $class, $args, $url );

Onde $response também pode ser um objeto WP_Error que talvez lhe diga mais.

Nota: A partir de um teste breve, este filtro parece funcionar (por algum motivo) apenas se você colocá-lo como perto de onde você está realmente fazendo a solicitação. Então, talvez você precise chamá-lo de dentro de um retorno de chamada em um dos filtros abaixo.

WP_HTTP Argumentos da classe

Os argumentos de Classes em si são filtráveis, mas alguns são redefinidos pelo método internals de volta para o que o WP assume que é necessário.

apply_filters( 'http_request_args', $r, $url );

Um dos argumentos é ssl_verify , que é verdadeiro por padrão (mas para mim causa problemas enormes ao atualizar de - por exemplo - GitHub). Editar: Após a depuração de uma solicitação de teste, encontrei outro argumento que está definido para verificar se o SSL está definido como true . É chamado sslverify (sem separar o sublinhado). Não faço ideia de onde isso entrou no jogo, se está realmente em uso ou abandonado e se você tem uma chance de influenciar seu valor. Eu achei usando o filtro 'http_api_debug' .

Completamente personalizado

Você também pode "simplesmente" substituir todos os componentes internos e usar uma configuração personalizada. Há um filtro para isso.

apply_filters( 'pre_http_request', false, $r, $url );

O primeiro argumento precisa ser definido como verdadeiro. Do que você pode interagir com os argumentos dentro de $r e o resultado de parse_url( $url ); .

Proxy

Outra coisa que pode funcionar é a execução de tudo por meio de um proxy personalizado. Isso precisa de algumas configurações no seu wp-config.php . Eu nunca tentei isso antes, mas eu repassei as constantes há algum tempo e resumi alguns exemplos que o deveria funcionar e incluí alguns comentários no caso de eu precisar dele algum dia. Você precisa definir WP_PROXY_HOST e WP_PROXY_PORT como min. configuração. Caso contrário, nada funcionará e simplesmente ignorará seu proxy.

# HTTP Proxies
# Used for e.g. in Intranets
# Fixes Feeds as well
# Defines the proxy adresse.
define( 'WP_PROXY_HOST',          '127.0.84.1' );
# Defines the proxy port.
define( 'WP_PROXY_PORT',          '8080' );
# Defines the proxy username.
define( 'WP_PROXY_USERNAME',      'my_user_name' );
# Defines the proxy password.
define( 'WP_PROXY_PASSWORD',      'my_password' );
# Allows you to define some adresses which
# shouldn't be passed through a proxy.
define( 'WP_PROXY_BYPASS_HOSTS',  'localhost, www.example.com' );

EDITAR

A classe WP_HTTP normalmente atua como classe base (será estendida para diferentes cenários). As classes WP_HTTP_* de extensão são Fsockopen , Streams , Curl , Proxy , Cookie , Encoding . Se você ligar um retorno de chamada ao 'http_api_debug' -action, o terceiro argumento informará qual classe foi usada para sua solicitação.

Dentro da classe WP_HTTP_curl , você encontrará o método request() . Esse método oferece dois filtros para interceptar o comportamento do SSL: um para solicitações locais 'https_local_ssl_verify' e um para solicitações remotas 'https_ssl_verify' . O WP provavelmente definirá local como localhost e o que você recebe em relação a get_option( 'siteurl' ); .

Então, o que eu faço é tentar o seguinte logo antes de você fazer essa solicitação (ou de um retorno de chamada que esteja ligado à solicitação mais próxima:

add_filter( 'https_ssl_verify', '__return_true' );

# Local requests should be checked with something like
# 'localhost' === $_SERVER['HTTP_HOST'] or similar
# add_filter( 'https_local_ssl_verify', '__return_true' );

Sidenote: na maioria dos casos, WP_HTTP_curl será usado para lidar com proxies.

    
por kaiser 14.11.2012 / 11:42
8

Com base na resposta útil do @kaiser, escrevi um código que parece funcionar bem. Essa é a razão pela qual eu o marquei como a resposta.

Deixe-me explicar minha solução ...

A lógica

Quando uma solicitação enviada por meio da API é executada por WP_Http::request() . Esse é o método com…

  

@todo Refatorie este código.

… no cabeçalho. Eu não pude concordar mais.

Agora, existem alguns filtros. Eu decidi usar pre_http_request para minhas necessidades:

add_filter( 'pre_http_request', 't5_update_wp_per_https', 10, 3 );

Recebemos três argumentos aqui: false, $r, $url .

  • false é o valor de retorno esperado para apply_filters() . Se enviarmos mais alguma coisa de volta, O WordPress para imediatamente e a solicitação original não será enviada.

  • $r é uma matriz de argumentos para essa solicitação. Nós temos que mudar isso também em um minuto.

  • $url is - surpresa! - o URL.

Portanto, no nosso retorno de chamada t5_update_wp_per_https() , olhamos para o URL e, se for um URL que queremos filtrar, dizemos NÃO ao WordPress, não , dizendo “ não ”( false ).

Nota:Segue-seapossibilidadedeevitartodasassolicitaçõesHTTPcom:%add_filter('pre_http_request','__return_true');

Emvezdisso,acionamosnossaprópriasolicitaçãocomumURLmelhoreargumentosligeiramenteajustados($r,renomeadopara$argsparalegibilidade).

Ocódigo

Porfavor,leiaoscomentáriosemlinha,elessãoimportantes.

<?php/***PluginName:T5UpdateWPperHTTPS*Description:ForcesupdatechecksanddownloadsforWPtouseHTTPS.*PluginURI:http://wordpress.stackexchange.com/questions/72529/filter-any-http-request-uri*Version:2012.11.14*Author:ThomasScholz*AuthorURI:http://toscho.de*Licence:MIT*LicenseURI:http://opensource.org/licenses/MIT*/add_filter('pre_http_request','t5_update_wp_per_https',10,3);/***ForceHTTPSrequestsforupdatechecksandnewWPversiondownloads.**@wp-hookpre_http_request*@parambool$false*@paramarray$args*@paramstring$url*@returnFALSE|array|objectFALSEifeverythingisokay,anarrayofrequest*resultsoranWP_Errorinstance.*/functiont5_update_wp_per_https($false,$args,$url){//SplittheURLintousefulparts.$url_data=parse_url($url);//ItisalreadyHTTPS.if('https'===strtolower($url_data['scheme']))returnFALSE;//Notourhost.if(FALSE===stripos($url_data['host'],'wordpress.org'))returnFALSE;//MakethatanHTTPSrequest.$new_url=substr_replace($url,'https',0,4);//WP_Httpcannotverifythewordpress.orgcertificate.$args['sslverify']=FALSE;//Itisslow.Wewaitatleast30seconds.30>$args['timeout']and$args['timeout']=30;//GetaninstanceofWP_Http.$http=_wp_http_get_object();//Gettheresult.$result=$http->request($new_url,$args);/*prependthislinewitha'#'todebuglikeaboss.print'<pre>'.htmlspecialchars(print_r($result,TRUE),ENT_QUOTES,'utf-8',FALSE).'</pre>';die();/**/return$result;}

Ostestes

SemessepluginWordPressusado:

  • http://api.wordpress.org/core/version-check/1.6/paraverificaçõesdeatualizaçãoe
  • http://wordpress.org/wordpress-3.4.2.zipparabaixarosnovosarquivos.

Eutesteicomduasinstalaçõeslocais,umsiteúnicoeumaconfiguraçãomulti-sitenoWin7.Paraforçarumaatualização,defino$wp_versionemwp-includes/version.phppara1eaversãodoTwentyElevenpara1.3.

Paraassistiraotráfegodarede,useio Wireshark : ele é gratuito, é executado no Windows e no Linux e oferece um filtro impressionante ferramentas.

Assistir HTTPS é um pouco difícil: você vê apenas dados criptografados ... afinal, essa é a ideia. Para ver se meu plug-in fez o que deveria, observei o tráfego não criptografado primeiro e anotei o endereço IP usado para se conectar ao wordpress.org. Isso foi 72.233.56.138 , às vezes 72.233.56.139 .
Não é de surpreender que exista um balanceador de carga e provavelmente muitas outras ferramentas, por isso não podemos confiar em um endereço IP.

Em seguida, digitei ip.addr == 72.233.56.138 na máscara do filtro, ativei o plug-in, fui para wp-admin/update-core.php e observei o tráfego no Wireshark. Linhas verdes são solicitações em texto simples - exatamente o que não queremos. As linhas vermelhas e pretas são um sinal de sucesso.

Averificaçãodeatualizaçãocorreubem:elaencontrouasversões"mais recentes". As atualizações reais do tema e do núcleo também correram bem. Exatamente o que eu precisava.

E ainda assim ... isso poderia ser mais fácil se houvesse um filtro simples para o URL.

    
por fuxia 15.11.2012 / 02:03
1
    add_filter('http_request_args', 'http_request_args_custom', 10,2);
    function http_request_args_custom($request,$url){
            if (strpos($url, 'wordpress.org') !== false){
                    global $replaced_url;
                    $replaced_url = 'http://wordpress.local';
            }
            return $request;
    }

    add_action('http_api_curl', 'http_api_curl_custom');
    function http_api_curl_custom(&$handle){
            global $replaced_url;
            if (!is_null($replaced_url))
                    curl_setopt( $handle, CURLOPT_URL, $replaced_url);
    }

    $http = new WP_Http();
    $response = $http->request('http://wordpress.org', array());

    var_dump($response);
    
por Butuzov 14.11.2012 / 08:23