Make WordPress Core

Changeset 25224


Ignore:
Timestamp:
09/04/2013 04:48:21 AM (13 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.