WordPress.org

Make WordPress Core

Changeset 25224


Ignore:
Timestamp:
09/04/13 04:48:21 (2 years ago)
Author:
dd32
Message:

WP_HTTP: Replacing the Fsockopen & Streams Transports with a new Streams transport which fully supports HTTPS communication.
This changeset also bundles ca-bundle.crt from the Mozilla project to allow for us to verify SSL certificates on hosts which have an incomplete, outdated, or invalid local SSL configuration.
Props rmccue for major assistance getting this this far. See #25007 for discussion, also Fixes #16606

Location:
trunk
Files:
2 added
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-http.php

    r25222 r25224  
    8282            'decompress' => true, 
    8383            'sslverify' => true, 
     84            'sslcertificates' => ABSPATH . WPINC . '/certificates/ca-bundle.crt', 
    8485            'stream' => false, 
    8586            'filename' => null, 
     
    215216     */ 
    216217    public function _get_first_available_transport( $args, $url = null ) { 
    217         $request_order = apply_filters( 'http_api_transports', array( 'curl', 'streams', 'fsockopen' ), $args, $url ); 
     218        $request_order = apply_filters( 'http_api_transports', array(  'streams' ), $args, $url ); 
    218219 
    219220        // Loop over each transport on each HTTP request looking for one which will serve this request's needs 
     
    237238     * Also caches the transport instance to be used later. 
    238239     * 
    239      * The order for blocking requests is cURL, Streams, and finally Fsockopen. 
    240      * The order for non-blocking requests is cURL, Streams and Fsockopen(). 
     240     * The order for requests is cURL, and then PHP Streams. 
    241241     * 
    242242     * @since 3.2.0 
     
    633633        return wp_remote_request( $redirect_location, $args );   
    634634    } 
     635 
     636    /** 
     637     * Determines if a specified string represents an IP address or not. 
     638     * 
     639     * This function also detects the type of the IP address, returning either 
     640     * '4' or '6' to represent a IPv4 and IPv6 address respectively. 
     641     * This does not verify if the IP is a valid IP, only that it appears to be 
     642     * an IP address. 
     643     * 
     644     * @see http://home.deds.nl/~aeron/regex/ for IPv6 regex 
     645     * 
     646     * @since 3.7.0 
     647     * @static 
     648     * 
     649     * @param string $maybe_ip A suspected IP address 
     650     * @return integer|bool Upon success, '4' or '6' to represent a IPv4 or IPv6 address, false upon failure 
     651     */ 
     652    static function is_ip_address( $maybe_ip ) { 
     653        if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $maybe_ip ) ) 
     654            return 4; 
     655 
     656        if ( false !== strpos( $maybe_ip, ':' ) && preg_match( '/^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i', trim( $maybe_ip, ' []' ) ) ) 
     657            return 6; 
     658 
     659        return false; 
     660    } 
     661 
    635662} 
    636663 
    637664/** 
    638  * HTTP request method uses fsockopen function to retrieve the url. 
    639  * 
    640  * This would be the preferred method, but the fsockopen implementation has the most overhead of all 
    641  * the HTTP transport implementations. 
     665 * HTTP request method uses PHP Streams to retrieve the url. 
    642666 * 
    643667 * @package WordPress 
    644668 * @subpackage HTTP 
    645  * @since 2.7.0 
     669 * @since 3.7.0 
    646670 */ 
    647 class WP_Http_Fsockopen { 
    648     /** 
    649      * Send a HTTP request to a URI using fsockopen(). 
    650      * 
    651      * Does not support non-blocking mode. 
     671class WP_Http_Streams { 
     672    /** 
     673     * Send a HTTP request to a URI using PHP Streams. 
    652674     * 
    653675     * @see WP_Http::request For default options descriptions. 
    654676     * 
    655      * @since 2.7 
     677     * @since 3.7.0 
    656678     * @access public 
    657679     * @param string $url URI resource. 
    658      * @param str|array $args Optional. Override the defaults. 
     680     * @param string|array $args Optional. Override the defaults. 
    659681     * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys. 
    660682     */ 
     
    680702        WP_Http::buildCookieHeader( $r ); 
    681703 
    682         $iError = null; // Store error number 
    683         $strError = null; // Store error string 
    684  
    685704        $arrURL = parse_url($url); 
    686705 
    687         $fsockopen_host = $arrURL['host']; 
    688  
    689         $secure_transport = false; 
    690  
     706        $connect_host = $arrURL['host']; 
     707 
     708        $secure_transport = ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ); 
    691709        if ( ! isset( $arrURL['port'] ) ) { 
    692             if ( ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ) && extension_loaded('openssl') ) { 
    693                 $fsockopen_host = "ssl://$fsockopen_host"; 
     710            if ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ) { 
    694711                $arrURL['port'] = 443; 
    695712                $secure_transport = true; 
     
    707724        } 
    708725 
    709         //fsockopen has issues with 'localhost' with IPv6 with certain versions of PHP, It attempts to connect to ::1, 
     726        // Certain versions of PHP have issues with 'localhost' and IPv6, It attempts to connect to ::1, 
    710727        // which fails when the server is not set up for it. For compatibility, always connect to the IPv4 address. 
    711         if ( 'localhost' == strtolower($fsockopen_host) ) 
    712             $fsockopen_host = '127.0.0.1'; 
    713  
    714         // There are issues with the HTTPS and SSL protocols that cause errors that can be safely 
    715         // ignored and should be ignored. 
    716         if ( true === $secure_transport ) 
    717             $error_reporting = error_reporting(0); 
    718  
    719         $startDelay = time(); 
     728        if ( 'localhost' == strtolower( $connect_host ) ) 
     729            $connect_host = '127.0.0.1'; 
     730 
     731        $connect_host = $secure_transport ? 'ssl://' . $connect_host : 'tcp://' . $connect_host; 
     732 
     733        $is_local = isset( $r['local'] ) && $r['local']; 
     734        $ssl_verify = isset( $r['sslverify'] ) && $r['sslverify']; 
     735        if ( $is_local ) 
     736            $ssl_verify = apply_filters( 'https_local_ssl_verify', $ssl_verify ); 
     737        elseif ( ! $is_local ) 
     738            $ssl_verify = apply_filters( 'https_ssl_verify', $ssl_verify ); 
    720739 
    721740        $proxy = new WP_HTTP_Proxy(); 
    722741 
     742        $context = stream_context_create( array( 
     743            'ssl' => array( 
     744                'verify_peer' => $ssl_verify, 
     745                //'CN_match' => $arrURL['host'], // This is handled by self::verify_ssl_certficate() 
     746                'capture_peer_cert' => $ssl_verify, 
     747                'SNI_enabled' => true, 
     748                'cafile' => $r['sslcertificates'], 
     749                'allow_self_signed' => ! $ssl_verify, 
     750            ) 
     751        ) ); 
     752 
     753        $timeout = (int) floor( $r['timeout'] ); 
     754        $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000; 
     755        $connect_timeout = max( $timeout, 1 ); 
     756 
     757        $connection_error = null; // Store error number 
     758        $connection_error_str = null; // Store error string 
     759 
    723760        if ( !WP_DEBUG ) { 
     761            // In the event that the SSL connection fails, silence the many PHP Warnings 
     762            if ( $secure_transport ) 
     763                $error_reporting = error_reporting(0); 
     764 
    724765            if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) 
    725                 $handle = @fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] ); 
     766                $handle = @stream_socket_client( 'tcp://' . $proxy->host() . ':' . $proxy->port(), $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context ); 
    726767            else 
    727                 $handle = @fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] ); 
     768                $handle = @stream_socket_client( $connect_host . ':' . $arrURL['port'], $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context ); 
     769 
     770            if ( $secure_transport ) 
     771                error_reporting( $error_reporting ); 
     772 
    728773        } else { 
    729774            if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) 
    730                 $handle = fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] ); 
     775                $handle = stream_socket_client( 'tcp://' . $proxy->host() . ':' . $proxy->port(), $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context ); 
    731776            else 
    732                 $handle = fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] ); 
    733         } 
    734  
    735         $endDelay = time(); 
    736  
    737         // If the delay is greater than the timeout then fsockopen shouldn't be used, because it will 
    738         // cause a long delay. 
    739         $elapseDelay = ($endDelay-$startDelay) > $r['timeout']; 
    740         if ( true === $elapseDelay ) 
    741             add_option( 'disable_fsockopen', $endDelay, null, true ); 
    742  
    743         if ( false === $handle ) 
    744             return new WP_Error('http_request_failed', $iError . ': ' . $strError); 
    745  
    746         $timeout = (int) floor( $r['timeout'] ); 
    747         $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000; 
     777                $handle = stream_socket_client( $connect_host . ':' . $arrURL['port'], $connection_error, $connection_error_str, $connect_timeout, STREAM_CLIENT_CONNECT, $context ); 
     778        } 
     779 
     780        if ( false === $handle ) { 
     781            // SSL connection failed due to expired/invalid cert, or, OpenSSL configuration is broken 
     782            if ( $secure_transport && 0 === $connection_error && '' === $connection_error_str ) 
     783                return new WP_Error( 'http_request_failed', __( 'The SSL Certificate for the host could not be verified.' ) ); 
     784 
     785            return new WP_Error('http_request_failed', $connection_error . ': ' . $connection_error_str ); 
     786        } 
     787 
     788        // Verify that the SSL certificate is valid for this request 
     789        if ( $secure_transport && $ssl_verify && ! $proxy->is_enabled() ) { 
     790            if ( ! self::verify_ssl_certficate( $handle, $arrURL['host'] ) ) 
     791                return new WP_Error( 'http_request_failed', __( 'The SSL Certificate for the host could not be verified.' ) ); 
     792        } 
     793 
    748794        stream_set_timeout( $handle, $timeout, $utimeout ); 
    749795 
     
    784830 
    785831        if ( ! $r['blocking'] ) { 
    786             fclose($handle); 
     832            stream_set_blocking( $handle, 0 ); 
     833            fclose( $handle ); 
    787834            return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    788835        } 
     
    847894        fclose( $handle ); 
    848895 
    849         if ( true === $secure_transport ) 
    850             error_reporting($error_reporting); 
    851  
    852896        $arrHeaders = WP_Http::processHeaders( $process['headers'], $url ); 
    853897 
     
    880924 
    881925    /** 
     926     * Verifies the received SSL certificate against it's Common Names and subjectAltName fields 
     927     *  
     928     * PHP's SSL verifications only verify that it's a valid Certificate, it doesn't verify if 
     929     * the certificate is valid for the hostname which was requested. 
     930     * This function verifies the requested hostname against certificate's subjectAltName field, 
     931     * if that is empty, or contains no DNS entries, a fallback to the Common Name field is used. 
     932     * 
     933     * IP Address support is included if the request is being made to an IP address. 
     934     * 
     935     * @since 3.7.0 
     936     * @static 
     937     * 
     938     * @param stream $stream The PHP Stream which the SSL request is being made over 
     939     * @param string $host The hostname being requested 
     940     * @return bool If the cerficiate presented in $stream is valid for $host 
     941     */ 
     942    static function verify_ssl_certficate( $stream, $host ) { 
     943        $context_options = stream_context_get_options( $stream ); 
     944 
     945        if ( empty( $context_options['ssl']['peer_certificate'] ) ) 
     946            return false; 
     947 
     948        $cert = openssl_x509_parse( $context_options['ssl']['peer_certificate'] ); 
     949        if ( ! $cert ) 
     950            return false; 
     951 
     952        // If the request is being made to an IP address, we'll validate against IP fields in the cert (if they exist) 
     953        $host_type = ( WP_HTTP::is_ip_address( $host ) ? 'ip' : 'dns' ); 
     954 
     955        $certificate_hostnames = array(); 
     956        if ( ! empty( $cert['extensions']['subjectAltName'] ) ) { 
     957            $match_against = preg_split( '/,\s*/', $cert['extensions']['subjectAltName'] ); 
     958            foreach ( $match_against as $match ) { 
     959                list( $match_type, $match_host ) = explode( ':', $match ); 
     960                if ( $host_type == strtolower( trim( $match_type ) ) ) // IP: or DNS: 
     961                    $certificate_hostnames[] = strtolower( trim( $match_host ) ); 
     962            } 
     963        } elseif ( !empty( $cert['subject']['CN'] ) ) { 
     964            // Only use the CN when the certificate includes no subjectAltName extension 
     965            $certificate_hostnames[] = strtolower( $cert['subject']['CN'] ); 
     966        } 
     967 
     968        // Exact hostname/IP matches 
     969        if ( in_array( strtolower( $host ), $certificate_hostnames ) ) 
     970            return true; 
     971 
     972        // IP's can't be wildcards, Stop processing 
     973        if ( 'ip' == $host_type ) 
     974            return false; 
     975 
     976        // Test to see if the domain is at least 2 deep for wildcard support 
     977        if ( substr_count( $host, '.' ) < 2 ) 
     978            return false; 
     979 
     980        // Wildcard subdomains certs (*.example.com) are valid for a.example.com but not a.b.example.com 
     981        $wildcard_host = preg_replace( '/^[^.]+\./', '*.', $host ); 
     982 
     983        return in_array( strtolower( $wildcard_host ), $certificate_hostnames ); 
     984    } 
     985 
     986    /** 
    882987     * Whether this class can be used for retrieving an URL. 
    883988     * 
    884      * @since 2.7.0 
    885989     * @static 
     990     * @access public 
     991     * @since 3.7.0 
     992     * 
    886993     * @return boolean False means this class can not be used, true means it can. 
    887994     */ 
    888995    public static function test( $args = array() ) { 
    889         if ( ! function_exists( 'fsockopen' ) ) 
     996        if ( ! function_exists( 'stream_socket_client' ) ) 
    890997            return false; 
    891998 
    892         if ( false !== ( $option = get_option( 'disable_fsockopen' ) ) && time() - $option < 12 * HOUR_IN_SECONDS ) 
    893             return false; 
    894  
    895999        $is_ssl = isset( $args['ssl'] ) && $args['ssl']; 
    8961000 
    897         if ( $is_ssl && ! extension_loaded( 'openssl' ) ) 
    898             return false; 
    899  
    900         return apply_filters( 'use_fsockopen_transport', true, $args ); 
     1001        if ( $is_ssl ) { 
     1002            if ( ! extension_loaded( 'openssl' ) ) 
     1003                return false; 
     1004            if ( ! function_exists( 'openssl_x509_parse' ) ) 
     1005                return false; 
     1006        } 
     1007 
     1008        return apply_filters( 'use_streams_transport', true, $args ); 
    9011009    } 
    9021010} 
    9031011 
    9041012/** 
    905  * HTTP request method uses Streams to retrieve the url. 
    906  * 
    907  * Requires PHP 5.0+ and uses fopen with stream context. Requires that 'allow_url_fopen' PHP setting 
    908  * to be enabled. 
    909  * 
    910  * Second preferred method for getting the URL, for PHP 5. 
     1013 * Deprecated HTTP Transport method which used fsockopen. 
     1014 * This class is not used, and is included for backwards compatibility only. 
     1015 * All code should make use of WP_HTTP directly through it's API. 
     1016 * 
     1017 * @see WP_HTTP::request 
     1018 * 
     1019 * @package WordPress 
     1020 * @subpackage HTTP 
     1021 * @since 3.7.0 
     1022 */ 
     1023class WP_HTTP_Fsockopen extends WP_HTTP_Streams { 
     1024    // For backwards compatibility for users who are using the class directly 
     1025} 
     1026 
     1027/** 
     1028 * HTTP request method uses Curl extension to retrieve the url. 
     1029 * 
     1030 * Requires the Curl extension to be installed. 
    9111031 * 
    9121032 * @package WordPress 
     
    9141034 * @since 2.7.0 
    9151035 */ 
    916 class WP_Http_Streams { 
    917     /** 
    918      * Send a HTTP request to a URI using streams with fopen(). 
     1036class WP_Http_Curl { 
     1037 
     1038    /** 
     1039     * Temporary header storage for during requests. 
     1040     * 
     1041     * @since 3.2.0 
     1042     * @access private 
     1043     * @var string 
     1044     */ 
     1045    private $headers = ''; 
     1046 
     1047    /** 
     1048     * Temporary body storage for during requests. 
     1049     * 
     1050     * @since 3.6.0 
     1051     * @access private 
     1052     * @var string 
     1053     */ 
     1054    private $body = ''; 
     1055 
     1056    /** 
     1057     * The maximum amount of data to recieve from the remote server 
     1058     * 
     1059     * @since 3.6.0 
     1060     * @access private 
     1061     * @var int 
     1062     */ 
     1063    private $max_body_length = false; 
     1064 
     1065    /** 
     1066     * The file resource used for streaming to file. 
     1067     * 
     1068     * @since 3.6.0 
     1069     * @access private 
     1070     * @var resource 
     1071     */ 
     1072    private $stream_handle = false; 
     1073 
     1074    /** 
     1075     * Send a HTTP request to a URI using cURL extension. 
    9191076     * 
    9201077     * @access public 
     
    9431100        } 
    9441101 
    945         // Construct Cookie: header if any cookies are set 
    946         WP_Http::buildCookieHeader( $r ); 
    947  
    948         $arrURL = parse_url($url); 
    949  
    950         if ( false === $arrURL ) 
    951             return new WP_Error('http_request_failed', sprintf(__('Malformed URL: %s'), $url)); 
    952  
    953         if ( 'http' != $arrURL['scheme'] && 'https' != $arrURL['scheme'] ) 
    954             $url = preg_replace('|^' . preg_quote($arrURL['scheme'], '|') . '|', 'http', $url); 
    955  
    956         // Convert Header array to string. 
    957         $strHeaders = ''; 
    958         if ( is_array( $r['headers'] ) ) 
    959             foreach ( $r['headers'] as $name => $value ) 
    960                 $strHeaders .= "{$name}: $value\r\n"; 
    961         else if ( is_string( $r['headers'] ) ) 
    962             $strHeaders = $r['headers']; 
    963  
    964         $is_local = isset($args['local']) && $args['local']; 
    965         $ssl_verify = isset($args['sslverify']) && $args['sslverify']; 
    966         if ( $is_local ) 
    967             $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify); 
    968         elseif ( ! $is_local ) 
    969             $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify); 
    970  
    971         $arrContext = array('http' => 
    972             array( 
    973                 'method' => strtoupper($r['method']), 
    974                 'user_agent' => $r['user-agent'], 
    975                 'max_redirects' => 0, // Follow no redirects 
    976                 'follow_redirects' => false, 
    977                 'protocol_version' => (float) $r['httpversion'], 
    978                 'header' => $strHeaders, 
    979                 'ignore_errors' => true, // Return non-200 requests. 
    980                 'timeout' => $r['timeout'], 
    981                 'ssl' => array( 
    982                         'verify_peer' => $ssl_verify, 
    983                         'verify_host' => $ssl_verify 
    984                 ) 
    985             ) 
    986         ); 
    987  
    988         $proxy = new WP_HTTP_Proxy(); 
    989  
    990         if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { 
    991             $arrContext['http']['proxy'] = 'tcp://' . $proxy->host() . ':' . $proxy->port(); 
    992             $arrContext['http']['request_fulluri'] = true; 
    993  
    994             // We only support Basic authentication so this will only work if that is what your proxy supports. 
    995             if ( $proxy->use_authentication() ) 
    996                 $arrContext['http']['header'] .= $proxy->authentication_header() . "\r\n"; 
    997         } 
    998  
    999         if ( ! is_null( $r['body'] ) ) 
    1000             $arrContext['http']['content'] = $r['body']; 
    1001  
    1002         $context = stream_context_create($arrContext); 
    1003  
    1004         if ( !WP_DEBUG ) 
    1005             $handle = @fopen($url, 'r', false, $context); 
    1006         else 
    1007             $handle = fopen($url, 'r', false, $context); 
    1008  
    1009         if ( ! $handle ) 
    1010             return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url)); 
    1011  
    1012         $timeout = (int) floor( $r['timeout'] ); 
    1013         $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000; 
    1014         stream_set_timeout( $handle, $timeout, $utimeout ); 
    1015  
    1016         if ( ! $r['blocking'] ) { 
    1017             stream_set_blocking($handle, 0); 
    1018             fclose($handle); 
    1019             return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    1020         } 
    1021  
    1022         $max_bytes = isset( $r['limit_response_size'] ) ? intval( $r['limit_response_size'] ) : -1; 
    1023         if ( $r['stream'] ) { 
    1024             if ( ! WP_DEBUG ) 
    1025                 $stream_handle = @fopen( $r['filename'], 'w+' ); 
    1026             else 
    1027                 $stream_handle = fopen( $r['filename'], 'w+' ); 
    1028  
    1029             if ( ! $stream_handle ) 
    1030                 return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) ); 
    1031  
    1032             stream_copy_to_stream( $handle, $stream_handle, $max_bytes ); 
    1033  
    1034             fclose( $stream_handle ); 
    1035             $strResponse = ''; 
    1036         } else { 
    1037             $strResponse = stream_get_contents( $handle, $max_bytes ); 
    1038         } 
    1039  
    1040         $meta = stream_get_meta_data( $handle ); 
    1041  
    1042         fclose( $handle ); 
    1043  
    1044         $processedHeaders = array(); 
    1045         if ( isset( $meta['wrapper_data']['headers'] ) ) 
    1046             $processedHeaders = WP_Http::processHeaders( $meta['wrapper_data']['headers'], $url ); 
    1047         else 
    1048             $processedHeaders = WP_Http::processHeaders( $meta['wrapper_data'], $url ); 
    1049  
    1050         $response = array( 
    1051             'headers' => $processedHeaders['headers'], 
    1052             'body' => null, 
    1053             'response' => $processedHeaders['response'], 
    1054             'cookies' => $processedHeaders['cookies'], 
    1055             'filename' => $r['filename'] 
    1056         ); 
    1057  
    1058         // Handle redirects 
    1059         if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) ) 
    1060             return $redirect_response; 
    1061  
    1062         if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] ) 
    1063             $strResponse = WP_Http::chunkTransferDecode($strResponse); 
    1064  
    1065         if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) ) 
    1066             $strResponse = WP_Http_Encoding::decompress( $strResponse ); 
    1067  
    1068         $response['body'] = $strResponse; 
    1069  
    1070         return $response; 
    1071     } 
    1072  
    1073     /** 
    1074      * Whether this class can be used for retrieving an URL. 
    1075      * 
    1076      * @static 
    1077      * @access public 
    1078      * @since 2.7.0 
    1079      * 
    1080      * @return boolean False means this class can not be used, true means it can. 
    1081      */ 
    1082     public static function test( $args = array() ) { 
    1083         if ( ! function_exists( 'fopen' ) ) 
    1084             return false; 
    1085  
    1086         if ( ! function_exists( 'ini_get' ) || true != ini_get( 'allow_url_fopen' ) ) 
    1087             return false; 
    1088  
    1089         $is_ssl = isset( $args['ssl'] ) && $args['ssl']; 
    1090  
    1091         if ( $is_ssl && ! extension_loaded( 'openssl' ) ) 
    1092             return false; 
    1093  
    1094         return apply_filters( 'use_streams_transport', true, $args ); 
    1095     } 
    1096 } 
    1097  
    1098 /** 
    1099  * HTTP request method uses Curl extension to retrieve the url. 
    1100  * 
    1101  * Requires the Curl extension to be installed. 
    1102  * 
    1103  * @package WordPress 
    1104  * @subpackage HTTP 
    1105  * @since 2.7 
    1106  */ 
    1107 class WP_Http_Curl { 
    1108  
    1109     /** 
    1110      * Temporary header storage for during requests. 
    1111      * 
    1112      * @since 3.2.0 
    1113      * @access private 
    1114      * @var string 
    1115      */ 
    1116     private $headers = ''; 
    1117  
    1118     /** 
    1119      * Temporary body storage for during requests. 
    1120      * 
    1121      * @since 3.6.0 
    1122      * @access private 
    1123      * @var string 
    1124      */ 
    1125     private $body = ''; 
    1126  
    1127     /** 
    1128      * The maximum amount of data to recieve from the remote server 
    1129      * 
    1130      * @since 3.6.0 
    1131      * @access private 
    1132      * @var int 
    1133      */ 
    1134     private $max_body_length = false; 
    1135  
    1136     /** 
    1137      * The file resource used for streaming to file. 
    1138      * 
    1139      * @since 3.6.0 
    1140      * @access private 
    1141      * @var resource 
    1142      */ 
    1143     private $stream_handle = false; 
    1144  
    1145     /** 
    1146      * Send a HTTP request to a URI using cURL extension. 
    1147      * 
    1148      * @access public 
    1149      * @since 2.7.0 
    1150      * 
    1151      * @param string $url 
    1152      * @param str|array $args Optional. Override the defaults. 
    1153      * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys. 
    1154      */ 
    1155     function request($url, $args = array()) { 
    1156         $defaults = array( 
    1157             'method' => 'GET', 'timeout' => 5, 
    1158             'redirection' => 5, 'httpversion' => '1.0', 
    1159             'blocking' => true, 
    1160             'headers' => array(), 'body' => null, 'cookies' => array() 
    1161         ); 
    1162  
    1163         $r = wp_parse_args( $args, $defaults ); 
    1164  
    1165         if ( isset($r['headers']['User-Agent']) ) { 
    1166             $r['user-agent'] = $r['headers']['User-Agent']; 
    1167             unset($r['headers']['User-Agent']); 
    1168         } else if ( isset($r['headers']['user-agent']) ) { 
    1169             $r['user-agent'] = $r['headers']['user-agent']; 
    1170             unset($r['headers']['user-agent']); 
    1171         } 
    1172  
    11731102        // Construct Cookie: header if any cookies are set. 
    11741103        WP_Http::buildCookieHeader( $r ); 
     
    12081137        curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, ( $ssl_verify === true ) ? 2 : false ); 
    12091138        curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify ); 
     1139        curl_setopt( $handle, CURLOPT_CAINFO, $r['sslcertificates'] ); 
    12101140        curl_setopt( $handle, CURLOPT_USERAGENT, $r['user-agent'] ); 
    12111141        // The option doesn't work with safe mode or when open_basedir is set, and there's a 
  • trunk/tests/phpunit/tests/http/base.php

    r25046 r25224  
    271271        $this->assertEquals( 'PASS', wp_remote_retrieve_body( $res ) ); 
    272272    } 
     273 
     274    /** 
     275     * Test if HTTPS support works 
     276     * 
     277     * @group ssl 
     278     * @ticket 25007 
     279     */ 
     280    function test_ssl() { 
     281        if ( ! wp_http_supports( array( 'ssl' ) ) ) 
     282            $this->markTestSkipped( 'This install of PHP does not support SSL' ); 
     283 
     284        $res = wp_remote_get( 'https://wordpress.org/' ); 
     285        $this->assertTrue( ! is_wp_error( $res ), print_r( $res, true ) ); 
     286    } 
     287     
     288     
    273289} 
Note: See TracChangeset for help on using the changeset viewer.