/**
  * Send an http(s) request via cURL.
  *
  * @param string       $url     The URL to request.
  * @param array|string $data    Data to be posted with the request.
  * @param array        $headers Headers to assign to the request.
  * @return object An object containing details about this request.
  */
 private function _http_request($url, $data = array(), $headers = array())
 {
     // Prefix the full pod URL if necessary.
     if (0 === strpos($url, '/')) {
         $url = $this->get_pod_url($url);
     }
     // Call address via cURL.
     $ch = curl_init($url);
     // Set up cURL options.
     curl_setopt($ch, CURLOPT_HEADER, true);
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     if (file_exists(WP2D_DIR . '/cacert.pem')) {
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
         curl_setopt($ch, CURLOPT_CAINFO, WP2D_DIR . '/cacert.pem');
     }
     if (!empty($this->_cookie)) {
         curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie);
     }
     // Add the passed headers.
     if (!empty($headers)) {
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
     }
     // Add the passed post data.
     if (!empty($data)) {
         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
     }
     // Get the response from the cURL call.
     $response = curl_exec($ch);
     // Get the headers and the html response.
     $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
     $headers = substr($response, 0, $header_size);
     $response = substr($response, $header_size);
     // Remember this request.
     $this->_last_request = new stdClass();
     $this->_last_request->headers = $headers;
     $this->_last_request->response = $response;
     $this->_last_request->error = curl_error($ch);
     $this->_last_request->errno = curl_errno($ch);
     $this->_last_request->info = curl_getinfo($ch);
     curl_close($ch);
     // Save the new token.
     if ($token = $this->_parse_regex('token', $response)) {
         $this->_token = $token;
     }
     // Save the latest cookie.
     if ($cookie = $this->_parse_regex('cookie', $headers)) {
         $this->_cookie = $cookie;
     }
     // Once we're logged in, can we load new aspects and services while we're at it?
     if ($this->is_logged_in()) {
         // Load the aspects.
         if (empty($this->_aspects) && ($aspects_raw = json_decode($this->_parse_regex('aspects', $response)))) {
             // Add the 'public' aspect, as it's global and not user specific.
             $aspects = array('public' => __('Public'));
             // Create an array of all the aspects and save them to the settings.
             foreach ($aspects_raw as $aspect) {
                 $aspects[$aspect->id] = $aspect->name;
             }
             $this->_aspects = $aspects;
         }
         // Load the services.
         if (empty($this->_services) && ($services_raw = json_decode($this->_parse_regex('services', $response)))) {
             $services = array();
             foreach ($services_raw as $service) {
                 $services[$service] = ucfirst($service);
             }
             $this->_services = $services;
         }
     }
     // Add debug info.
     WP2D_Helpers::add_debugging(sprintf("code %s on %s\n", $this->_last_request->info['http_code'], $this->_last_request->info['url']));
     // Return the last request details.
     return $this->_last_request;
 }