过滤任何HTTP请求URI?


10

我想过滤通过HTTP API完成的所有HTTP请求URI。

用例:

  1. WordPress更新检查转到http://api.wordpress.org/core/version-check/1.6/,但https://api.wordpress.org/core/version-check/1.6/也可以,我想要总是使用它。
  2. 新的WordPress文件来自http://wordpress.org/wordpress-3.4.2.zip,但https://wordpress.org/wordpress-3.4.2.zip也可以。
  3. 有时,我想调试请求并将那些临时请求重定向到本地服务器上的自定义域。
  4. 一些插件向其他服务器发出请求,而当外部服务器出现故障时,我想替换这些请求。

目前,更新请求是最重要的请求,因为仍然存在未修复的错误16778更多信息),并且HTTPS请求降低了中间人攻击的风险。

我进行了彻底的搜索 ,研究了核心代码……但是两年前像Nacin一样结束了:

我以为可以过滤HTTP请求的URL,但现在找不到了。

我错过了什么?是吗 :)


对于在WP中搜索cURL调试的任何人,请在此处链接此答案
kaiser 2014年

Answers:


9

还不算是一个答案,而只是我的经验清单-也许您忽略了一些东西。

调试请求及其结果

无需深入研究更新过程,但是WP HTTP API使用WP_HTTP该类。它还提供了一个好东西:调试钩子。

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

在哪里$response还可以是一个WP_Error可以告诉您更多信息的对象。

注意:从简短的测试来看,如果将过滤器放置在实际执行请求的位置较近的位置,则该过滤器似乎仅出于某种原因而起作用。因此,也许您需要在以下过滤器之一的回调中调用它。

WP_HTTP 类参数

Classes参数本身是可过滤的,但是某些方法可以通过方法内部将其重置为WP所需要的。

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

其中一个参数是ssl_verify,默认情况下为true(但对我来说,从-例如GitHub更新时会引起大量问题)。编辑:调试测试请求后,我发现了另一个参数,该参数设置为验证SSL是否设置为true。它被称为sslverify(不下划线分开)。不知道它在游戏中的位置,是否已真正使用或废弃,以及是否有机会影响其价值。我使用'http_api_debug'过滤器找到了它。

完全定制

您也可以“简单地”覆盖整个内部结构,并进行自定义设置。有一个过滤器。

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

第一个参数需要设置为true。比起您可以与其中的参数$r和的结果进行交互parse_url( $url );

代理

可能可行的另一件事可能是通过自定义代理运行所有内容。这需要您中的一些设置wp-config.php。我以前从来没有尝试过这一点,但我通过常量跑了一段时间后,并总结出了一些例子,应该工作,包括一些意见的情况下,我需要一天。您必须定义WP_PROXY_HOSTWP_PROXY_PORT最小值。设置。否则,将无济于事,它将绕过您的代理。

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

编辑

所述WP_HTTP类通常作为类(将延长不同的场景)。延伸WP_HTTP_*FsockopenStreamsCurlProxyCookieEncoding。如果将回调链接到'http_api_debug'-action,则第三个参数将告诉您哪个类用于您的请求。

WP_HTTP_curl类内部,您将找到request()方法。此方法提供了两个过滤器来拦截SSL行为:一个用于本地请求'https_local_ssl_verify',一个用于远程请求'https_ssl_verify'。WP可能会定义localas localhost和您从中得到的回报get_option( 'siteurl' );

因此,我要做的是在执行该请求之前(或从挂接到最接近的请求的回调中)尝试以下操作:

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

旁注:大多数情况下WP_HTTP_curl将用于处理代理。


1
嗯,我想您已经间接回答了我的问题:我可以加入pre_http_request,取消请求,然后使用正确的URL重新发送。今晚将尝试。
fuxia

8

基于@kaiser的有用答案,我编写了一些似乎运行良好的代码。这就是为什么我将其标记为“答案”的原因。

让我解释一下我的解决方案...

逻辑

通过API发送的请求通过时运行WP_Http::request()。那就是…的方法

@todo重构此代码。

…在标题中。我完全同意。

现在,有一些过滤器。我决定根据pre_http_request自己的需要滥用:

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

我们在这里得到三个参数:false, $r, $url

  • false是的预期返回值apply_filters()。如果我们将其他任何内容发回,WordPress将立即停止,并且原始请求将不会发送。

  • $r是该请求的参数数组。我们也必须在一分钟内更改它们。

  • $url是–惊喜!– URL。

因此,在我们的回调t5_update_wp_per_https(),我们看的URL,如果我们想过滤的网址,我们说NO通过使用WordPress 说“不”( false)。

在此处输入图片说明

旁注:您可以使用以下命令阻止所有HTTP请求:
add_filter( 'pre_http_request', '__return_true' );

我们会使用更好的URL和经过稍微调整的参数($r,为了$args便于阅读而重命名为)来触发自己的请求。

编码

请阅读内联注释,它们很重要。

<?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;
}

测试

如果没有该插件,WordPress将使用:

  • http://api.wordpress.org/core/version-check/1.6/ 用于更新检查,以及
  • http://wordpress.org/wordpress-3.4.2.zip 下载新文件。

我有两个本地安装,单一站点和多站点设置在Win 7.要强制更新我一套测试它$wp_versionwp-includes/version.php1和版本TwentyEleven来1.3

为了观察网络流量,我使用了Wireshark:它是免费的,可以在Windows和Linux上运行,并且提供了一些令人印象深刻的筛选器工具。

观看HTTPS有点困难:您只会看到加密的数据…毕竟就是这个主意。要查看我的插件是否执行了应做的工作,我首先观察了未加密的流量,并记下了用于连接到wordpress.org的IP地址。那是72.233.56.138有时候72.233.56.139
毫不奇怪,这里有一个负载均衡器,也许还有许多其他工具,因此我们不能依赖一个 IP地址。

然后,我键入ip.addr == 72.233.56.138了过滤器掩码,激活了插件,然后前往wp-admin/update-core.phpWireshark并观察流量。绿线是纯文本格式的请求-正是我们不想要的。红线和黑线是成功的标志。

Wireshark

更新检查进行得很顺利:它找到了“较新的”版本。主题和核心的实际更新也很好。正是我所需要的。

而且……如果URL有一个简单的过滤器,那可能会更容易。


1
为+1 /* /**/,只因为它是天才。(如果可以的话)再给查尔斯·布朗森+1。然后应该还有+1的详细说明,评论和屏幕截图。
kaiser 2012年

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
应该提到的是,在此代码示例中,在函数http_api_curl_custom中,使用全局变量$ replaced_url后应将其设置为NULL。否则,在URL中首次出现“ wordpress.org”之后,所有其他URL将被替换。
MihanEntalpo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.