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,
+