[MediaWiki-commits] [Gerrit] wikimedia...SmashPig[master]: Add cURL wrapper

2017-02-15 Thread jenkins-bot (Code Review)
jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/334453 )

Change subject: Add cURL wrapper
..


Add cURL wrapper

Moves the GatewayAdapter::curl_transaction logic down into SmashPig,
giving us a place to centralize adapter request logic like timeouts,
user-agents, and retries.

Retry logic is in its own class, so different processor configs can
override the default decisions which are based on HTTP status.

Change-Id: I6710c327c39866367b169922df4a25df3e4127c4
---
A Core/Http/CurlWrapper.php
A Core/Http/HttpStatusValidator.php
A Core/Http/OutboundRequest.php
A Core/Http/ResponseValidator.php
M SmashPig.yaml
5 files changed, 291 insertions(+), 0 deletions(-)

Approvals:
  Cdentinger: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Core/Http/CurlWrapper.php b/Core/Http/CurlWrapper.php
new file mode 100644
index 000..8f4f862
--- /dev/null
+++ b/Core/Http/CurlWrapper.php
@@ -0,0 +1,149 @@
+configuration = Context::get()->getConfiguration();
+   }
+
+   public function execute( $url, $method, $responseHeaders, $data ) {
+   if ( is_array( $data ) ) {
+   $data = http_build_query( $data );
+   }
+
+   Logger::info( "Initiating cURL" );
+   $ch = curl_init();
+
+   // Always capture the cURL output
+   $curlDebugLog = fopen( 'php://temp', 'r+' );
+
+   $curlOptions = $this->getCurlOptions( $url, $method, 
$responseHeaders, $data, $curlDebugLog );
+   curl_setopt_array( $ch, $curlOptions );
+
+   // TODO: log timing
+   $loopCount = $this->configuration->val( 'curl/retries' );
+   $tries = 0;
+   $parsed = null;
+   do {
+   Logger::info(
+   "Preparing to send {$method} request to {$url}"
+   );
+
+   // Execute the cURL operation
+   $response = curl_exec( $ch );
+
+   // Always read the verbose output
+   rewind( $curlDebugLog );
+   $logged = fread( $curlDebugLog, 8192 );
+
+   if ( $response !== false ) {
+   // The cURL operation was at least successful, 
what happened in it?
+   Logger::debug( "cURL verbose logging: $logged" 
);
+
+   $curlInfo = curl_getinfo( $ch );
+   $parsed = $this->parseResponse( $response, 
$curlInfo );
+
+   /**
+* @var ResponseValidator
+*/
+   $validator = $this->configuration->object( 
'curl/validator' );
+   $continue = $validator->shouldRetry( $parsed );
+
+   } else {
+   // Well the cURL transaction failed for some 
reason or another. Try again!
+   $continue = true;
+
+   $errno = curl_errno( $ch );
+   $err = curl_error( $ch );
+
+   Logger::alert(
+   "cURL transaction to {$url} failed: 
($errno) $err.  " .
+   "cURL verbose logging: $logged"
+   );
+   }
+   $tries++;
+   if ( $tries >= $loopCount ) {
+   $continue = false;
+   }
+   } while ( $continue ); // End while cURL transaction hasn't 
returned something useful
+
+   // Clean up and return
+   curl_close( $ch );
+   fclose( $curlDebugLog );
+
+   if ( $response === false ) {
+   // no valid response after multiple tries
+   throw new HttpRuntimeException(
+   "{$method} request to {$url} failed $loopCount 
times."
+   );
+   }
+
+   return $parsed;
+   }
+
+   protected function getCurlOptions( $url, $method, $headers, $data, 
$logStream ) {
+   $options = array(
+   CURLOPT_URL => $url,
+   CURLOPT_USERAGENT => $this->configuration->val( 
'curl/user-agent' ),
+   CURLOPT_HEADER => 1,
+   CURLOPT_RETURNTRANSFER => 1,
+   CURLOPT_TIMEOUT => $this->configuration->val( 
'curl/timeout' ),
+   CURLOPT_FOLLOWLOCATION => 0,
+   CURLOPT_SSL_VERIFYPEER => 1,
+   CURLOPT_SSL_VERIFYHOST => 2,
+   CURLOPT_FORBID_REUSE => true,
+  

[MediaWiki-commits] [Gerrit] wikimedia...SmashPig[master]: Add cURL wrapper

2017-01-26 Thread Ejegg (Code Review)
Ejegg has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/334453 )

Change subject: Add cURL wrapper
..

Add cURL wrapper

Moves the curl_transaction logic down into SmashPig, in preparation
for making API calls without using processor SDKs

Change-Id: I6710c327c39866367b169922df4a25df3e4127c4
---
A Core/Http/OutboundRequest.php
1 file changed, 177 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/SmashPig 
refs/changes/53/334453/1

diff --git a/Core/Http/OutboundRequest.php b/Core/Http/OutboundRequest.php
new file mode 100644
index 000..f76f32c
--- /dev/null
+++ b/Core/Http/OutboundRequest.php
@@ -0,0 +1,177 @@
+config = Context::get()->getConfiguration();
+   $this->url = $url;
+   $this->method = $method;
+   }
+
+   public function setHeader( $name, $value ) {
+   $this->headers[$name] = $value;
+   }
+
+   public function getHeaders() {
+   return $this->headers;
+   }
+
+   public function execute( $data = null ) {
+   $loopCount = $this->config->val( 'api_repeat' );
+
+   Logger::info( "Initiating cURL" );
+   $ch = curl_init();
+   // Always capture the cURL output
+   $curlDebugLog = fopen( 'php://temp', 'r+' );
+
+   $curlOptions = $this->getCurlOptions( $data );
+   curl_setopt_array( $ch, $curlOptions );
+   // TODO: log timing
+
+   $tries = 0;
+   do {
+   Logger::info(
+   "Preparing to send {$this->method} request to 
{$this->url}"
+   );
+
+   // Execute the cURL operation
+   $response = curl_exec( $ch );
+
+   // Always read the verbose output
+   rewind( $curlDebugLog );
+   $logged = fread( $curlDebugLog, 4096 );
+
+   if ( $response !== false ) {
+   // The cURL operation was at least successful, 
what happened in it?
+   Logger::debug( "cURL verbose logging: $logged" 
);
+
+   $headers = curl_getinfo( $ch );
+   $httpCode = $headers['http_code'];
+
+   switch ( $httpCode ) {
+   case 200:   // Everything is AWESOME
+   $continue = false;
+
+   Logger::debug( "Successful 
transaction to $this->url" );
+   break;
+
+   case 400:   // Oh noes! Bad request.. 
BAD CODE, BAD BAD CODE!
+   $continue = false;
+   Logger::error( "{$this->url} 
returned (400) BAD REQUEST: $response" );
+   break;
+
+   case 403:   // Hmm, forbidden? Maybe if 
we ask it nicely again...
+   $continue = true;
+   Logger::alert( "{$this->url} 
returned (403) FORBIDDEN: $response" );
+   break;
+
+   default:// No clue what happened... 
break out and log it
+   $continue = false;
+   Logger::error( "{$this->url} 
failed remotely and returned ($httpCode): $response" );
+   break;
+   }
+   } else {
+   // Well the cURL transaction failed for some 
reason or another. Try again!
+   $continue = true;
+
+   $errno = curl_errno( $ch );
+   $err = curl_error( $ch );
+
+   Logger::alert(
+   "cURL transaction to {$this->url} 
failed: ($errno) $err.  " .
+   "cURL verbose logging: $logged"
+   );
+   }
+   $tries++;
+   if ( $tries >= $loopCount ) {
+   $continue = false;
+   }
+   if ( $continue ) {
+   // If we're going to try again, reset the debug 
log.
+   // TODO: log timing for this particular curl 
attempt
+   rewind( $curlDebugLog );
+   }
+   } while ( $continue ); // End while cUR