Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Refactor fetching iana http status codes to use caching
Browse files Browse the repository at this point in the history
  • Loading branch information
Xerkus authored and weierophinney committed Oct 8, 2019
1 parent 9070462 commit 6131aea
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
doc/html/
vendor/
zf-mkdoc-theme/
/test/TestAsset/.cache/
phpunit.xml
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ language: php
cache:
directories:
- $HOME/.composer/cache
- test/TestAsset/.cache # Cache archives are currently set to expire after 28 days by default

env:
global:
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"psr/http-message": "^1.0"
},
"require-dev": {
"ext-curl": "*",
"ext-dom": "*",
"ext-libxml": "*",
"http-interop/http-factory-tests": "^0.5.0",
Expand Down
19 changes: 10 additions & 9 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
</filter>

<php>
<env name="ALWAYS_REFRESH_IANA_HTTP_STATUS_CODES" value="false"/>
<const name="REQUEST_FACTORY" value="Zend\Diactoros\RequestFactory"/>
<const name="RESPONSE_FACTORY" value="Zend\Diactoros\ResponseFactory"/>
<const name="SERVER_REQUEST_FACTORY" value="Zend\Diactoros\ServerRequestFactory"/>
Expand Down
99 changes: 77 additions & 22 deletions test/ResponseTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
* @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2015-2019 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
*/

Expand All @@ -16,10 +16,25 @@
use Zend\Diactoros\Response;
use Zend\Diactoros\Stream;

use function curl_close;
use function curl_exec;
use function curl_getinfo;
use function curl_init;
use function curl_setopt;
use function defined;
use function file_exists;
use function file_put_contents;
use function gmdate;
use function in_array;
use function libxml_set_streams_context;
use function preg_match;
use function stream_context_create;
use function sprintf;
use function strtotime;

use const CURLINFO_HTTP_CODE;
use const CURLOPT_HTTPHEADER;
use const CURLOPT_RETURNTRANSFER;
use const CURLOPT_TIMEOUT;
use const LOCK_EX;

class ResponseTest extends TestCase
{
Expand Down Expand Up @@ -51,28 +66,68 @@ public function testReasonPhraseDefaultsToStandards()
$this->assertSame('Unprocessable Entity', $response->getReasonPhrase());
}

public function ianaCodesReasonPhrasesProvider()
private function fetchIanaStatusCodes() : DOMDocument
{
$ianaHttpStatusCodes = new DOMDocument();

libxml_set_streams_context(
stream_context_create(
[
'http' => [
'method' => 'GET',
'timeout' => 30,
'user_agent' => 'PHP',
],
]
)
);

$ianaHttpStatusCodes->load('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml');

if (! $ianaHttpStatusCodes->relaxNGValidate(__DIR__ . '/TestAsset/http-status-codes.rng')) {
self::fail('Unable to retrieve IANA response status codes due to timeout or invalid XML');
$updated = null;
$ianaHttpStatusCodesFile = __DIR__ . '/TestAsset/.cache/http-status-codes.xml';
$ianaHttpStatusCodes = null;
if (file_exists($ianaHttpStatusCodesFile)) {
$ianaHttpStatusCodes = new DOMDocument();
$ianaHttpStatusCodes->load($ianaHttpStatusCodesFile);
if (! $ianaHttpStatusCodes->relaxNGValidate(__DIR__ . '/TestAsset/http-status-codes.rng')) {
$ianaHttpStatusCodes = null;
}
}
if ($ianaHttpStatusCodes) {
if (! getenv('ALWAYS_REFRESH_IANA_HTTP_STATUS_CODES')) {
// use cached codes
return $ianaHttpStatusCodes;
}
$xpath = new DOMXPath($ianaHttpStatusCodes);
$xpath->registerNamespace('ns', 'http://www.iana.org/assignments');
$updated = $xpath->query('//ns:updated')->item(0)->nodeValue;
$updated = strtotime($updated);
}

$ch = curl_init('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP Curl');
if ($updated) {
$ifModifiedSince = sprintf(
'If-Modified-Since: %s',
gmdate('D, d M Y H:i:s \G\M\T', $updated)
);
curl_setopt($ch, CURLOPT_HTTPHEADER, [$ifModifiedSince]);
}
$response = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($responseCode === 304 && $ianaHttpStatusCodes) {
// status codes did not change
return $ianaHttpStatusCodes;
}

if ($responseCode === 200) {
$downloadedIanaHttpStatusCodes = new DOMDocument();
$downloadedIanaHttpStatusCodes->loadXML($response);
if ($downloadedIanaHttpStatusCodes->relaxNGValidate(__DIR__ . '/TestAsset/http-status-codes.rng')) {
file_put_contents($ianaHttpStatusCodesFile, $response, LOCK_EX);
return $downloadedIanaHttpStatusCodes;
}
}
if ($ianaHttpStatusCodes) {
// return cached codes if available
return $ianaHttpStatusCodes;
}
self::fail('Unable to retrieve IANA response status codes due to timeout or invalid XML');
}

public function ianaCodesReasonPhrasesProvider()
{
$ianaHttpStatusCodes = $this->fetchIanaStatusCodes();

$ianaCodesReasonPhrases = [];

$xpath = new DOMXPath($ianaHttpStatusCodes);
Expand Down
Empty file added test/TestAsset/.cache/.gitkeep
Empty file.

0 comments on commit 6131aea

Please sign in to comment.