Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
27pchrisl committed Apr 6, 2021
1 parent dc16406 commit 6b4d640
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 22 deletions.
49 changes: 29 additions & 20 deletions src/Controller/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Flat3\Lodata\Exception\Protocol\NotAcceptableException;
use Flat3\Lodata\Exception\Protocol\NotFoundException;
use Flat3\Lodata\Exception\Protocol\NotImplementedException;
use Flat3\Lodata\Exception\Protocol\NotModifiedException;
use Flat3\Lodata\Exception\Protocol\PreconditionFailedException;
use Flat3\Lodata\Exception\Protocol\ProtocolException;
use Flat3\Lodata\Expression\Lexer;
Expand Down Expand Up @@ -1440,38 +1441,46 @@ public function setETagHeader(string $etag): self
return $this;
}

/**
* Get the current value of the If-Match header
* @return array If-Match header
*/
public function getIfMatchHeaders(): array
{
return $this->getRequestHeaders(Constants::IF_MATCH);
}

/**
* Validate that the provided ETag matches the current If-Match header
* @param string|null $etag ETag
*/
public function assertIfMatchHeader(?string $etag): void
{
$ifMatches = $this->getIfMatchHeaders();
$ifMatches = $this->getRequestHeaders(Constants::IF_MATCH);
$ifNoneMatches = $this->getRequestHeaders(Constants::IF_NONE_MATCH);

$this->request->headers->remove(Constants::IF_MATCH);
$this->request->headers->remove(Constants::IF_NONE_MATCH);

if (!$ifMatches) {
return;
if ($ifMatches) {
foreach ($ifMatches as $ifMatch) {
if ($ifMatch === '*' || $ifMatch === $etag) {
return;
}
}

throw new PreconditionFailedException(
'etag_mismatch',
'The provided If-Match header did not match the current ETag value'
);
}

foreach ($ifMatches as $ifMatch) {
if ($ifMatch === '*' || $ifMatch === $etag) {
return;
if ($ifNoneMatches) {
foreach ($ifNoneMatches as $ifNoneMatch) {
if ($ifNoneMatch === '*' || $ifNoneMatch !== $etag) {
return;
}
}
}

throw new PreconditionFailedException(
'etag_mismatch',
'The provided If-Match header did not match the current ETag value'
);
if ($this->getMethod() === Request::METHOD_GET) {
throw new NotModifiedException();
}

throw new PreconditionFailedException(
'etag_mismatch',
'The provided If-None-Match header matched the current ETag value',
);
}
}
}
17 changes: 17 additions & 0 deletions src/Exception/Protocol/NotModifiedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Flat3\Lodata\Exception\Protocol;

use Illuminate\Http\Response;

/**
* Not Modified Exception
* @package Flat3\Lodata\Exception\Protocol
*/
class NotModifiedException extends ProtocolException
{
protected $httpCode = Response::HTTP_NOT_MODIFIED;
protected $odataCode = 'not_modified';
protected $message = 'Not modified';
protected $suppressContent = true;
}
1 change: 1 addition & 0 deletions src/Helper/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ class Constants
const ODATA_ENTITY_ID = 'odata-entityid';
const ETAG = 'etag';
const IF_MATCH = 'if-match';
const IF_NONE_MATCH = 'if-none-match';
}
7 changes: 6 additions & 1 deletion tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ protected function assertPreconditionFailed(Request $request): TestResponse
return $this->assertODataError($request, Response::HTTP_PRECONDITION_FAILED);
}

protected function assertNotModified(Request $request): TestResponse
{
return $this->assertODataError($request, Response::HTTP_NOT_MODIFIED);
}

protected function assertNotAcceptable(Request $request): TestResponse
{
return $this->assertODataError($request, Response::HTTP_NOT_ACCEPTABLE);
Expand Down Expand Up @@ -179,7 +184,7 @@ protected function assertConflict(Request $request): TestResponse

protected function assertODataError(Request $request, int $code): TestResponse
{
$emptyCodes = [Response::HTTP_NO_CONTENT, Response::HTTP_FOUND];
$emptyCodes = [Response::HTTP_NO_CONTENT, Response::HTTP_FOUND, Response::HTTP_NOT_MODIFIED];
$response = $this->req($request);
$this->assertEquals($code, $response->getStatusCode());
$content = $this->responseContent($response);
Expand Down
46 changes: 46 additions & 0 deletions tests/Unit/Modify/UpdateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,52 @@ public function test_any_etag()
);
}

public function test_any_if_none_match_any()
{
$this->assertJsonResponse(
Request::factory()
->path('/flights(1)')
->header('if-none-match', '*')
->put()
->body([
'origin' => 'ooo',
])
);
}

public function test_any_if_none_match()
{
$response = $this->req(
Request::factory()
->path('/flights(1)')
);

$etag = $response->headers->get('etag');

$this->assertPreconditionFailed(
Request::factory()
->path('/flights(1)')
->header('if-none-match', $etag)
->put()
->body([
'origin' => 'ooo',
])
);
}

public function test_any_if_none_match_failed()
{
$this->assertMetadataResponse(
Request::factory()
->path('/flights(1)')
->header('if-none-match', 'xxx')
->put()
->body([
'origin' => 'ooo',
])
);
}

public function test_update_ref()
{
$this->assertJsonResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"code": "etag_mismatch",
"message": "The provided If-None-Match header matched the current ETag value"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"@context": "http://localhost/odata/$metadata#flights/$entity",
"id": 1,
"origin": "ooo",
"destination": "lax",
"gate": null,
"duration": "PT11H25M0S"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
headers:
cache-control: ['no-cache, private']
content-type: [application/json]
odata-version: ['4.01']
etag: ['W/"46c7c8eb6fca7d5ca6b46b02c0f3455ce8e97ad6246ce46fe92d010cd64e557d"']
status: 200
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ airports:
- { id: '4', name: 'O''Hare', code: ohr, construction_date: '1930-01-01 00:00:00', sam_datetime: '1999-11-10 14:00:01', open_time: '15:00:00', review_score: null, is_big: '1', country_id: null }
countries: { }
flights:
- { id: '1', origin: lhr, destination: lax, gate: null, duration: '41100.0' }
- { id: '1', origin: ooo, destination: lax, gate: null, duration: '41100.0' }
- { id: '2', origin: sam, destination: rgr, gate: null, duration: '2384.0' }
- { id: '3', origin: sfo, destination: lax, gate: null, duration: '2133.0' }
passengers:
Expand Down
27 changes: 27 additions & 0 deletions tests/Unit/Queries/Entity/EntityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,33 @@ public function test_read_an_entity_if_match_any()
);
}

public function test_read_an_entity_if_none_match_any()
{
$this->assertMetadataResponse(
Request::factory()
->header('if-none-match', '*')
->path('/flights(1)')
);
}

public function test_read_an_entity_if_none_match()
{
$this->assertNotModified(
Request::factory()
->header('if-none-match', 'W/"9002879996637791044635c0a75ae412322098677c04322be3da15089239bc76"')
->path('/flights(1)')
);
}

public function test_read_an_entity_if_none_match_failed()
{
$this->assertMetadataResponse(
Request::factory()
->header('if-none-match', 'xxx')
->path('/flights(1)')
);
}

public function test_read_an_entity_with_full_metadata()
{
$this->assertJsonResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
headers:
cache-control: ['no-cache, private']
content-type: [application/json]
odata-version: ['4.01']
etag: ['W/"9002879996637791044635c0a75ae412322098677c04322be3da15089239bc76"']
status: 200
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
headers:
cache-control: ['no-cache, private']
content-type: [application/json]
odata-version: ['4.01']
etag: ['W/"9002879996637791044635c0a75ae412322098677c04322be3da15089239bc76"']
status: 200

0 comments on commit 6b4d640

Please sign in to comment.