protected function request($method, $url, $parameters = array())
    {
        Logger::get()->debug('HTTP: starting request...');
        $headers = $this->headers;

        // Add accepted content type header.
        $headers[] = 'Content-Type: ' . $this->contentType;
        $headers[] = 'Accept: ' . $this->acceptedContentType;

        $handler = curl_init();

        if (!is_null($this->user)) {
            curl_setopt($handler, CURLOPT_USERPWD, $this->user . ':' . $this->password);
        }

        Logger::get()->debug('HTTP: method is ' . $method);
        switch ($method) {
            case self::METHOD_DELETE:
                curl_setopt($handler, CURLOPT_URL, $url . '?' . http_build_query($parameters));
                curl_setopt($handler, CURLOPT_CUSTOMREQUEST, self::DELETE);
                break;
            case self::METHOD_POST:
                curl_setopt($handler, CURLOPT_URL, $url);
                curl_setopt($handler, CURLOPT_POST, true);
                curl_setopt($handler, CURLOPT_POSTFIELDS, $parameters);
                break;
            case self::METHOD_GET:
                curl_setopt($handler, CURLOPT_URL, $url . '?' . http_build_query($parameters));
                break;
        }

        curl_setopt($handler, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($handler, CURLOPT_HTTPHEADER, $headers);
        Logger::get()->debug('HTTP: headers set.');

        // Send the request to the server.
        Logger::get()->debug("HTTP: requesting $url...");
        $output = curl_exec($handler);
        $errNo = curl_errno($handler);
        $error = curl_error($handler);
        // Obtain the status.
        Logger::get()->debug('HTTP: Done. Getting status...');
        $status = curl_getinfo($handler, CURLINFO_HTTP_CODE);
        // The handler is no longer needed.
        curl_close($handler);
        Logger::get()->debug('HTTP: request finished.');

        if ($errNo) {
            throw new Exception('HTTP: cURL failed: ' . $error, $errNo);
        }

        // If cURL had no errors itself, then there is an HTTP response.
        switch ($status) {
            case self::STATUS_OK:
            case self::STATUS_CREATED:
            case self::STATUS_ACCEPTED:
            case self::STATUS_NO_CONTENT:
                return $output;
            default:
                throw new Http\Exception("HTTP {$status}", $status);
        }
    }