Saring setiap permintaan HTTP URI?


10

Saya ingin memfilter setiap permintaan HTTP yang dilakukan URI melalui API HTTP.

Gunakan kasing:

  1. Pemeriksaan pembaruan WordPress masuk ke http://api.wordpress.org/core/version-check/1.6/ , tetapi https://api.wordpress.org/core/version-check/1.6/ juga berfungsi, dan saya ingin untuk menggunakan ini selalu.
  2. File WordPress baru diambil dari http://wordpress.org/wordpress-3.4.2.zip , tetapi https://wordpress.org/wordpress-3.4.2.zip juga berfungsi.
  3. Terkadang saya ingin men-debug permintaan dan mengarahkan mereka yang sementara ke domain khusus di server lokal saya.
  4. Beberapa plugin membuat permintaan ke server lain, dan saya ingin mengganti permintaan ini ketika server eksternal turun.

Permintaan pembaruan adalah yang paling penting untuk saat ini, karena masih ada bug yang belum diperbaiki 16778 ( informasi lebih lanjut ), dan permintaan HTTPS menurunkan risiko serangan Man-in-the-middle.

Saya telah mencari dengan seksama , saya telah mempelajari kode inti ... tetapi akhirnya seperti Nacin dua tahun lalu:

Saya yakin Anda dapat memfilter URL permintaan HTTP, tetapi sekarang saya tidak dapat menemukannya.

Apa yang saya lewatkan? Benarkah? :)


Menautkan jawaban ini di sini untuk siapa saja yang mencari debug cURL di WP.
kaiser

Jawaban:


9

Kurang dari jawaban, tetapi hanya daftar hal-hal langsung dari pengalaman saya dengannya - mungkin Anda telah mengabaikan sesuatu.

Men-debug permintaan & hasilnya

Tanpa diggin terlalu jauh ke dalam proses pembaruan, tetapi WP HTTP API menggunakan WP_HTTPkelas. Ini juga menawarkan hal yang menyenangkan: Sebuah kait debug.

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

Di mana $responsejuga bisa menjadi WP_Errorobjek yang mungkin memberi tahu Anda lebih banyak.

Catatan: Dari tes singkat, filter ini tampaknya hanya (karena alasan tertentu) berfungsi jika Anda menempatkannya sedekat mungkin dengan tempat Anda benar-benar melakukan permintaan. Jadi mungkin Anda perlu meneleponnya dari dalam panggilan balik di salah satu filter di bawah ini.

WP_HTTP Argumen kelas

Argumen Classes itu sendiri dapat difilter, tetapi beberapa afaik mendapatkan reset dengan metode internal kembali ke apa WP menganggap bahwa diperlukan.

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

Salah satu argumennya adalah ssl_verify, yang benar secara default (tetapi bagi saya menyebabkan masalah besar ketika memperbarui dari - misalnya - GitHub). Sunting: Setelah men-debug permintaan pengujian, saya menemukan argumen lain yang ditetapkan untuk memverifikasi jika SSL diatur ke true. Ini disebut sslverify(tanpa memisahkan garis bawah). Tidak tahu di mana ini datang ke dalam permainan, apakah itu benar-benar digunakan atau ditinggalkan dan jika Anda memiliki kesempatan untuk mempengaruhi nilainya. Saya menemukannya menggunakan 'http_api_debug'filter.

Sepenuhnya kustom

Anda juga dapat "cukup" menimpa seluruh internal dan pergi dengan pengaturan khusus. Ada filter untuk itu.

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

Arg pertama harus di set true. Daripada Anda dapat berinteraksi dengan argumen di dalam $rdan hasil dari parse_url( $url );.

Proksi

Hal lain yang mungkin berhasil adalah menjalankan semuanya melalui Proxy khusus. Ini membutuhkan beberapa pengaturan di wp-config.php. Saya belum pernah mencoba ini sebelumnya, tetapi saya berlari melalui konstanta beberapa waktu lalu dan menyimpulkan beberapa contoh yang harus bekerja dan menyertakan beberapa komentar jika saya membutuhkannya suatu hari. Anda harus mendefinisikan WP_PROXY_HOSTdan WP_PROXY_PORTsebagai min. pengaturan. Jika tidak, tidak ada yang akan bekerja dan itu hanya akan memotong proxy Anda.

# 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' );

EDIT

The WP_HTTPKelas biasanya bertindak sebagai basis kelas (akan diperpanjang untuk skenario yang berbeda). The memperpanjang WP_HTTP_*kelas yang Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. Jika Anda mengaitkan panggilan balik ke 'http_api_debug'-aksi, maka argumen ketiga akan memberi tahu Anda kelas mana yang digunakan untuk permintaan Anda.

Di dalam WP_HTTP_curlKelas, Anda akan menemukan request()metodenya. Metode ini menawarkan dua filter untuk mencegat perilaku SSL: Satu untuk permintaan lokal 'https_local_ssl_verify'dan satu untuk permintaan jarak jauh 'https_ssl_verify'. WP kemungkinan akan mendefinisikan localsebagai localhostdan apa yang Anda dapatkan sebagai imbalannya get_option( 'siteurl' );.

Jadi yang akan saya lakukan adalah mencoba yang berikut sebelum Anda melakukan permintaan itu (atau dari panggilan balik yang terhubung ke permintaan terdekat:

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: Dalam kebanyakan kasus WP_HTTP_curlakan digunakan untuk menangani Proxy.


1
Ah, saya pikir Anda telah menjawab pertanyaan saya secara tidak langsung: Saya dapat menghubungkan pre_http_request, membatalkan permintaan dan mengirimnya kembali dengan URL yang benar. Akan mencobanya malam ini.
fuxia

8

Berdasarkan jawaban berguna @ kaiser saya telah menulis beberapa kode yang sepertinya berfungsi dengan baik. Itulah alasan mengapa saya menandainya sebagai Jawaban.

Biarkan saya jelaskan solusinya ...

Logika

Ketika permintaan itu dikirim melalui API dijalankan WP_Http::request(). Itulah metode dengan ...

@todo Perbaiki kode ini.

... di tajuknya. Saya sangat setuju.

Sekarang, ada beberapa filter. Saya memutuskan untuk menyalahgunakan pre_http_requestkebutuhan saya:

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

Kami mendapatkan tiga argumen di sini: false, $r, $url.

  • falseadalah nilai pengembalian yang diharapkan untuk apply_filters(). Jika kami mengirim apa pun kembali, WordPress segera berhenti, dan permintaan asli tidak akan dikirim.

  • $radalah array argumen untuk permintaan itu. Kita harus mengubahnya juga dalam semenit.

  • $urladalah - kejutan! - URL.

Jadi dalam panggilan balik t5_update_wp_per_https()kami, kami melihat URL, dan jika itu URL yang ingin kami filter, kami katakan TIDAK ke WordPress dengan tidak mengatakan "tidak" ( false).

masukkan deskripsi gambar di sini

Catatan: Ini mengikuti Anda dapat mencegah semua permintaan HTTP dengan:
add_filter( 'pre_http_request', '__return_true' );

Kami malah memecat permintaan kami sendiri dengan URL yang lebih baik dan argumen yang sedikit disesuaikan ( $r, diganti namanya menjadi $argsagar mudah dibaca).

Kode

Silakan baca komentar sebaris, itu penting.

<?php
/**
 * Plugin Name: T5 Update WP per HTTPS
 * Description: Forces update checks and downloads for WP to use HTTPS.
 * Plugin URI:  http://wordpress.stackexchange.com/questions/72529/filter-any-http-request-uri
 * Version:     2012.11.14
 * Author:      Thomas Scholz
 * Author URI:  http://toscho.de
 * Licence:     MIT
 * License URI: http://opensource.org/licenses/MIT
 */

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

/**
 * Force HTTPS requests for update checks and new WP version downloads.
 *
 * @wp-hook pre_http_request
 * @param   bool   $false
 * @param   array  $args
 * @param   string $url
 * @return  FALSE|array|object FALSE if everything is okay, an array of request
 *                            results or an WP_Error instance.
 */
function t5_update_wp_per_https( $false, $args, $url )
{
    // Split the URL into useful parts.
    $url_data = parse_url( $url );

    // It is already HTTPS.
    if ( 'https' === strtolower( $url_data['scheme'] ) )
        return FALSE;

    // Not our host.
    if ( FALSE === stripos( $url_data['host'], 'wordpress.org' ) )
        return FALSE;

    // Make that an HTTPS request.
    $new_url = substr_replace( $url, 'https', 0, 4 );

    // WP_Http cannot verify the wordpress.org certificate.
    $args['sslverify'] = FALSE;

    // It is slow. We wait at least 30 seconds.
    30 > $args['timeout'] and $args['timeout'] = 30;

    // Get an instance of WP_Http.
    $http    = _wp_http_get_object();

    // Get the result.
    $result = $http->request( $new_url, $args );

    /* prepend this line with a '#' to debug like a boss.
    print '<pre>'
    . htmlspecialchars( print_r( $result, TRUE ), ENT_QUOTES, 'utf-8', FALSE )
    . '</pre>';
    die();
    /**/

    return $result;
}

Tes

Tanpa plugin yang digunakan WordPress:

  • http://api.wordpress.org/core/version-check/1.6/ untuk memeriksa pembaruan, dan
  • http://wordpress.org/wordpress-3.4.2.zip untuk mengunduh file baru.

Saya diuji dengan dua instalasi lokal, satu situs dan multi-situs setup pada Win 7. Untuk memaksa update saya set $wp_versiondi wp-includes/version.phpke 1dan versi TwentyEleven untuk 1.3.

Untuk menonton lalu lintas jaringan saya menggunakan Wireshark : Ini gratis, ini berjalan pada Windows dan Linux, dan ia menawarkan beberapa alat penyaring yang mengesankan.

Menonton HTTPS sedikit sulit: Anda hanya melihat data terenkripsi ... itu idenya. Untuk melihat apakah plugin saya melakukan apa yang harus dilakukan, saya menonton lalu lintas yang tidak terenkripsi terlebih dahulu dan mencatat alamat IP yang digunakan untuk terhubung ke wordpress.org. Itu 72.233.56.138, kadang-kadang 72.233.56.139.
Tidak mengherankan, ada penyeimbang beban dan mungkin banyak alat lainnya, jadi kami tidak bisa mengandalkan satu alamat IP.

Lalu saya mengetik ip.addr == 72.233.56.138ke filter mask, mengaktifkan plugin, pergi ke wp-admin/update-core.phpdan mengawasi lalu lintas di Wireshark. Garis hijau adalah permintaan dalam teks biasa - persis apa yang tidak kita inginkan. Garis merah dan hitam adalah tanda keberhasilan.

Wireshark

Pemeriksaan pembaruan berjalan dengan baik: Ditemukan versi "lebih baru". Pembaruan aktual untuk tema dan intinya berjalan dengan baik juga. Apa yang saya butuhkan.

Dan masih ... itu bisa lebih mudah jika ada filter sederhana untuk URL.


1
+1 untuk /* /**/, hanya karena itu jenius. Dan (jika saya bisa) +1 lain untuk Charles Bronson. Dan kemudian harus ada +1 lain untuk penjelasan terperinci, komentar & tangkapan layar.
kaiser

3
    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);

1
Harus disebutkan, bahwa dalam contoh kode ini, dalam fungsi http_api_curl_custom, variabel global $ replace_url harus disetel ke NULL setelah digunakan. Jika tidak, setelah kemunculan pertama "wordpress.org" di url, semua url lainnya akan diganti.
MihanEntalpo
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.