Irgendeinen HTTP-Anfrage-URI filtern?

Ich möchte jeden HTTP-Request-URI filtern, der über die HTTP-API erfolgt.

Anwendungsfälle:

  1. Der WordPress-Update-Check geht zu http://api.wordpress.org/core/version-check/1.6/ , aber https://api.wordpress.org/core/version-check/1.6/ funktioniert auch, und ich will um das immer zu benutzen.
  2. Die neue WordPress-Datei stammt von http://wordpress.org/wordpress-3.4.2.zip , aber https://wordpress.org/wordpress-3.4.2.zip funktioniert auch.
  3. Manchmal möchte ich Anfragen debuggen und diese temporär auf eine benutzerdefinierte Domäne auf meinem lokalen Server redirect.
  4. Einige Plugins stellen Anfragen an andere Server, und ich möchte diese Anfragen ersetzen, wenn der externe Server ausfällt.

Die Update-Anfragen sind vorerst die wichtigsten, da immer noch der unfixierte Bug 16778 ( mehr Informationen ) vorhanden ist und HTTPS-Anfragen das Risiko eines Man-in-the-Middle-Angriffs verringern .

Ich habe gründlich gesucht , ich habe den corecode studiert … aber endete vor zwei Jahren wie Nacin:

Ich dachte sicher, Sie könnten die URL einer HTTP-Anfrage filtern, aber jetzt kann ich keine finden.

Was habe ich verpasst? Habe ich? 🙂

Solutions Collecting From Web of "Irgendeinen HTTP-Anfrage-URI filtern?"

Weniger als eine Antwort, aber nur eine Liste von Dingen, die direkt aus meiner Erfahrung stammen – vielleicht haben Sie etwas übersehen.

Debuggen der Anfrage und ihrer Ergebnisse

Ohne zu tief in den Aktualisierungsprozess einzugreifen, aber die WP HTTP-API verwendet die WP_HTTP class. Es bietet auch eine schöne Sache: Ein Debug-Hook.

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

Wobei $response auch ein WP_Error Objekt sein kann, das Ihnen vielleicht mehr sagt.

Hinweis: Nach einem kurzen Test scheint dieser Filter (aus irgendeinem Grund) nur dann zu funktionieren, wenn Sie ihn so nah an der Stelle platzieren, an der Sie die Anfrage tatsächlich ausführen. Vielleicht müssen Sie es innerhalb eines callbacks auf einem der folgenden Filter aufrufen.

WP_HTTP classnargumente

Die classnargumente selbst sind filterbar, aber afaik werden einige von den Interna der Methoden zurück zu dem, was WP annimmt, dass benötigt wird, zurückgesetzt.

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

Eines der Argumente ist ssl_verify , das ist standardmäßig true (aber für mich verursacht massive Probleme beim Aktualisieren von – zum Beispiel – GitHub). Bearbeiten: Nach dem Debuggen einer Testanforderung, fand ich ein anderes Argument, das festgelegt wurde, um zu überprüfen, ob SSL auf true . Es heißt sslverify (ohne Unterstrich zu trennen). Keine Ahnung, wo das ins Spiel kam, ob es tatsächlich benutzt wird oder aufgegeben wird und ob du eine Chance hast, seinen Wert zu beeinflussen. Ich habe es mit dem Filter 'http_api_debug' .

Völlig benutzerdefiniert

Sie können auch einfach die gesamten Interna überschreiben und mit einem benutzerdefinierten Setup gehen. Dafür gibt es einen Filter.

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

Das erste Argument muss auf “Wahr” gesetzt sein. parse_url( $url ); können Sie mit den Argumenten innerhalb von $r und dem Ergebnis von parse_url( $url ); .

Proxy

Eine andere Sache, die funktionieren könnte, könnte alles über einen benutzerdefinierten Proxy ausführen. Dies benötigt einige Einstellungen in deiner wp-config.php . Ich habe das noch nie zuvor versucht, aber ich habe die Konstanten vor einer Weile durchgelesen und einige Beispiele zusammengefasst, die funktionieren sollten und einige Kommentare enthalten, falls ich es eines Tages brauchen sollte. Sie müssen WP_PROXY_HOST und WP_PROXY_PORT als Min definieren. Rahmen. Sonst funktioniert nichts und es wird einfach Ihren Proxy umgehen.

 # HTTP Proxies # Used for eg 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' ); 

BEARBEITEN

Die WP_HTTP class fungiert normalerweise als Basisklasse (wird für verschiedene Szenarien erweitert). Die erweiterten WP_HTTP_* -classn sind Fsockopen , Streams , Curl , Proxy , Cookie , Encoding . Wenn Sie einen callback an die 'http_api_debug' anhängen, 'http_api_debug' Ihnen das dritte Argument mit, welche class für Ihre Anfrage verwendet wurde.

In der class WP_HTTP_curl finden Sie die Methode request() . Diese Methode bietet zwei Filter zum Abfangen des SSL-Verhaltens: Eines für lokale Anfragen 'https_local_ssl_verify' und eines für entfernte Anfragen 'https_ssl_verify' . WP wird wahrscheinlich local als localhost definieren und was man von get_option( 'siteurl' ); .

Also, was ich tun würde, ist Folgendes zu versuchen, bevor Sie diese Anfrage (oder von einem callback, der mit der nächsten Anfrage verknüpft ist:

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

Hinweis: In den meisten Fällen wird WP_HTTP_curl verwendet, um mit Proxys umzugehen.

Basierend auf @ kaisers nützlicher Antwort habe ich einen Code geschrieben, der gut zu funktionieren scheint. Das ist der Grund, warum ich es als die Antwort markiert habe.

Lass mich meine Lösung erklären …

Die Logik

Wenn eine Anforderung über die API gesendet wird, wird sie über WP_Http::request() . Das ist die Methode mit …

@todo Refactor diesen Code.

… in seiner Kopfzeile. Ich könnte mehr nicht zustimmen.

Jetzt gibt es einige Filter. Ich entschied mich pre_http_request für meine Bedürfnisse zu missbrauchen:

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

Wir erhalten hier drei Argumente: false, $r, $url .

  • false ist der erwartete Rückgabewert für apply_filters() . Wenn wir etwas anderes zurücksenden, stoppt WordPress sofort und die ursprüngliche Anfrage wird nicht gesendet.

  • $r ist ein Array von Argumenten für diese Anfrage. Wir müssen diese auch in einer Minute ändern.

  • $url ist – Überraschung! – die URL

In unserem Callback t5_update_wp_per_https() schauen wir uns die URL an, und wenn es eine URL ist, die wir filtern wollen, sagen wir NEIN zu WordPress, indem wir nicht “nein” sagen ( false ).

Bildbeschreibung hier eingeben

Randnotiz: Es folgt, dass Sie alle HTTP-Anfragen mit folgenden verhindern können:
add_filter( 'pre_http_request', '__return_true' );

Wir zünden stattdessen unsere eigene Anfrage mit einer besseren URL und leicht angepassten Argumenten ( $r , zur besseren Lesbarkeit in $args umbenannt).

Der Code

Bitte lesen Sie die Inline-Kommentare, sie sind wichtig.

 < ?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 '
' . htmlspecialchars( print_r( $result, TRUE ), ENT_QUOTES, 'utf-8', FALSE ) . '

'; die(); /**/ return $result; }

Die Tests

Ohne dieses Plugin verwendete WordPress:

  • http://api.wordpress.org/core/version-check/1.6/ für Update-Prüfungen und
  • http://wordpress.org/wordpress-3.4.2.zip , um die neuen Dateien herunterzuladen.

Ich habe es mit zwei lokalen Installationen, einer einzelnen Site und einem Multi-Site Setup auf Win 7 getestet. Um ein Update zu erzwingen, setze ich $wp_version in wp-includes/version.php auf 1 und die Version von TwentyEleven auf 1.3 .

Um den Netzwerkverkehr zu überwachen, habe ich Wireshark verwendet : Er ist kostenlos, läuft unter Windows und Linux und bietet einige beeindruckende Filter-Tools.

Es ist ein bisschen schwierig, HTTPS zu beobachten: Sie sehen nur verschlüsselte Daten … das ist doch die Idee. Um zu sehen, ob mein Plugin das getan hat, was es tun sollte, habe ich zuerst den unverschlüsselten Verkehr beobachtet und die IP-Adresse zur Verbindung mit wordpress.org notiert. Das war 72.233.56.138 , manchmal 72.233.56.139 .
Nicht überraschend, es gibt einen Load Balancer und wahrscheinlich viele andere Tools, so dass wir uns nicht auf eine IP-Adresse verlassen können.

Dann tippte ich ip.addr == 72.233.56.138 in die Filtermaske, aktivierte das Plugin, ging zu wp-admin/update-core.php und beobachtete den Verkehr in Wireshark. Grüne Linien sind Anfragen im Klartext – genau das, was wir nicht wollen. Die roten und schwarzen Linien sind ein Zeichen des Erfolgs.

Wireshark

Der Update-Check lief gut: Es wurden die “neueren” Versionen gefunden. Die eigentlichen Updates für das Thema und den core sind auch gut gelaufen. Genau das, was ich brauchte.

Und trotzdem … das könnte einfacher sein, wenn es einen einfachen Filter für die URL gäbe.

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