Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
Sorry for the huge commit: should have merged master into httpStrateg…
Browse files Browse the repository at this point in the history
…y before

merging it into master.

1. Back ported fixes that were in master's procPacket() code into
SagNativeHTTPAdapter's procPacket().

2. Changed how the user selects which HTTP adapter to use - you now specify a
string instead of instantiating your own adapter class (required redundant
passing of host/port info).

3. Wrote the cURL HTTP adapter: SagCURLHTTPAdapter.php. Really needs a
different name.

4. Moved the HTTP adapters into their own sub-directory: ./src/httpAdapters.
  • Loading branch information
sbisbee committed Nov 4, 2011
1 parent d13c561 commit a19223c
Show file tree
Hide file tree
Showing 5 changed files with 398 additions and 191 deletions.
55 changes: 41 additions & 14 deletions src/Sag.php
Expand Up @@ -16,7 +16,8 @@
require_once('SagException.php');
require_once('SagCouchException.php');
require_once('SagConfigurationCheck.php');
require_once('SagNativeHTTPAdapter.php');
require_once('httpAdapters/SagNativeHTTPAdapter.php');
require_once('httpAdapters/SagCURLHTTPAdapter.php');

/**
* The Sag class provides the core functionality for talking to CouchDB.
Expand All @@ -37,6 +38,9 @@ class Sag {
*/
public static $AUTH_COOKIE = "AUTH_COOKIE";

public static $NATIVE_HTTP_ADAPTER = 'NATIVE_HTTP_ADAPTER';
public static $CURL_HTTP_ADAPTER = 'CURL_HTTP_ADAPTER';

private $db; //Database name to hit.
private $host; //IP or address to connect to.
private $port; //Port to connect to.
Expand All @@ -46,8 +50,6 @@ class Sag {
private $authType; //One of the Sag::$AUTH_* variables
private $authSession; //AuthSession cookie value from/for CouchDB

private $decodeResp = true; //Are we decoding CouchDB's JSON?
private $socketOpenTimeout; //The seconds until socket connection timeout
private $socketRWTimeoutSeconds; //The seconds for socket I/O timeout
private $socketRWTimeoutMicroseconds; //The microseconds for socket I/O timeout
Expand All @@ -59,34 +61,59 @@ class Sag {
private $globalCookies = array();

private $httpAdapter;
private $httpAdapterType;

/**
* @param string $host (OPTIONAL) The host's IP or address of the Couch we're
* connecting to. Defaults to '127.0.0.1'.
*
* @param string $port (OPTIONAL) The host's port that Couch is listening on.
* Defaults to '5984'.
*
* @param SagHTTPAdapter $httpAdapter (OPTIONAL) An implementation of the
* SagHTTPAdapter. Defaults to SagNativeHTTPAdapter.
*/
public function __construct($host = "127.0.0.1", $port = "5984", $httpAdapter = null)
public function __construct($host = "127.0.0.1", $port = "5984")
{
SagConfigurationCheck::run();

$this->host = $host;
$this->port = $port;

$this->httpAdapter = ($httpAdapter) ?: new SagNativeHTTPAdapter($host, $port);
//sets to the default by ... default
$this->setHTTPAdapter();
}

/**
* Closes any sockets that are left open in the connection pool.
*/
public function __destruct() {
foreach($this->connPool as $sock) {
@fclose($sock);
public function setHTTPAdapter($type = null) {
if(!$type) {
$type = self::$NATIVE_HTTP_ADAPTER;
}

//nothing to be done
if($type === $this->httpAdapterType) {
return true;
}

//remember what was already set (ie., might have called decode() already)
if($this->httpAdapter) {
$prevDecode = $this->httpAdapter->decodeResp;
}

switch($type) {
case self::$NATIVE_HTTP_ADAPTER:
$this->httpAdapter = new SagNativeHTTPAdapter($this->host, $this->port);
break;

case self::$CURL_HTTP_ADAPTER:
$this->httpAdapter = new SagCURLHTTPAdapter($this->host, $this->port);
break;

default:
throw SagException("Invalid Sag HTTP adapter specified: $type");
}

if($prevDecode) {
$this->httpAdapter->decodeResp = $prevDecode;
}

return $this;
}

/**
Expand Down
173 changes: 0 additions & 173 deletions src/SagNativeHTTPAdapter.php

This file was deleted.

85 changes: 85 additions & 0 deletions src/httpAdapters/SagCURLHTTPAdapter.php
@@ -0,0 +1,85 @@
<?php
class SagCURLHTTPAdapter extends SagHTTPAdapter {
private $ch;

public function __construct($host, $port) {
parent::__construct($host, $port);

$this->ch = curl_init();
}

public function procPacket($method, $url, $data = null, $headers = array()) {
// the base cURL options
$opts = array(
CURLOPT_URL => "{$this->proto}://{$this->host}:{$this->port}{$url}",
CURLOPT_PORT => $this->port,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $method
);

// cURL wants the headers as an array of strings, not an assoc array
/*
if(sizeof($headers) > 0) {
$curlHeaders = array();
foreach($headers as $k => $v) {
$curlHeaders[] = "$k: $v";
}
unset($headers);
$opts[CURLOPT_HTTPHEADER] = $headers;
}
*/
curl_setopt_array($this->ch, $opts);

$chResponse = curl_exec($this->ch);

if($chResponse !== false) {
//prepare the response object
$response = new stdClass();
$response->headers = new stdClass();
$response->headers->_HTTP = new stdClass();
$response->body = '';

//split headers and body
list($headers, $response->body) = explode("\r\n\r\n", $chResponse);

//split up the headers
$headers = explode("\r\n", $headers);

for($i = 0; $i < sizeof($headers); $i++) {
//first element will always be the HTTP status line
if($i === 0) {
$response->headers->_HTTP->raw = $headers[$i];

preg_match('(^HTTP/(?P<version>\d+\.\d+)\s+(?P<status>\d+))S', $headers[$i], $match);

$response->headers->_HTTP->version = $match['version'];
$response->headers->_HTTP->status = $match['status'];
$response->status = $match['status'];
}
else {
$line = explode(':', $headers[$i], 2);
$response->headers->$line[0] = ltrim($line[1]);

if($line[0] == 'Set-Cookie') {
$response->cookies = $this->parseCookieString($line[1]);
}
}
}
}
else if(curl_errno($this->ch)) {
throw new SagException('cURL error #' . curl_errno($this->ch) . ': ' . curl_error($this->ch));
}
else {
throw new SagException('cURL returned false without providing an error.');
}

return self::makeResult($response);
}
}
?>

0 comments on commit a19223c

Please sign in to comment.