protected function createCurlRequest () {
    // merge any custom cURL options into the default set
    $curlOpts = Util::mergeCurlOptions(
        self::$defaultCurlOpts, $this->getCurlOptions());

    // set basic options that we always want to use
    $curlOpts[CURLOPT_RETURNTRANSFER] = true;
    $curlOpts[CURLOPT_HEADER] = true;
    $curlOpts[CURLOPT_FAILONERROR] = false;
    if (defined('CURLINFO_HEADER_OUT')) {
      $curlOpts[CURLINFO_HEADER_OUT] = true;
    }

    // timeouts less than 1 sec fail unless we disable signals
    // see http://www.php.net/manual/en/function.curl-setopt.php#104597
    if (defined('CURLOPT_TIMEOUT_MS') ||
        defined('CURLOPT_CONNECTTIMEOUT_MS')) {
      if ((isset($curlOpts[CURLOPT_TIMEOUT_MS]) &&
          $curlOpts[CURLOPT_TIMEOUT_MS] < 1000) ||
          (isset($curlOpts[CURLOPT_CONNECTTIMEOUT_MS]) &&
          $curlOpts[CURLOPT_CONNECTTIMEOUT_MS] < 1000)) {
        $curlOpts[CURLOPT_NOSIGNAL] = true;
      }
    }

    // prepare the request
    $curlOpts[CURLOPT_URL] = $this->url;
    if (self::METHOD_POST == $this->getMethod()) {
      // using CURLOPT_CUSTOMREQUEST changes the behavior for POST
      // this change forces strict RFC2616:10.3.3 compliance which doesn't
      // work too well with many internet sites.
      $curlOpts[CURLOPT_POST] = true;
    } else {
      $curlOpts[CURLOPT_CUSTOMREQUEST] = $this->getMethod();
    }
    $curlOpts[CURLOPT_USERAGENT] = $this->getUserAgent();

    if ($this->getPostBody()) {
      // add post payload
      $pBody = $this->getPostBody();
      if (!is_array($pBody)) {
        // caller supplied a URI-encoded payload, so make sure we set the
        // content-length header
        $len = mb_strlen($pBody, 'latin1');
        $this->addHeader("Content-Length: {$len}");
      }
      $curlOpts[CURLOPT_POSTFIELDS] = $pBody;
    }

    if ($this->getHeaders()) {
      // add custom headers
      $curlOpts[CURLOPT_HTTPHEADER] = $this->getHeaders();
    }

    // remember the options we used. Might be handy for debugging.
    $this->setCurlOptions($curlOpts);

    // create curl resource
    $ch = curl_init();

    // apply options
    curl_setopt_array($ch, $curlOpts);

    return $ch;
  }