Skip to content

Commit 3c49506

Browse files
authored
Merge pull request #3497 from fmata/post-location
Prevent header Location on POST when status code is not 201 or 30x
2 parents d235fe5 + b028367 commit 3c49506

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

src/EventListener/RespondListener.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,6 @@ public function onKernelView(ViewEvent $event): void
6363
'X-Frame-Options' => 'deny',
6464
];
6565

66-
if ($request->attributes->has('_api_write_item_iri')) {
67-
$headers['Content-Location'] = $request->attributes->get('_api_write_item_iri');
68-
69-
if ($request->isMethod('POST')) {
70-
$headers['Location'] = $request->attributes->get('_api_write_item_iri');
71-
}
72-
}
73-
7466
$status = null;
7567
if ($this->resourceMetadataFactory && $attributes) {
7668
$resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']);
@@ -83,9 +75,19 @@ public function onKernelView(ViewEvent $event): void
8375
$status = $resourceMetadata->getOperationAttribute($attributes, 'status');
8476
}
8577

78+
$status = $status ?? self::METHOD_TO_CODE[$request->getMethod()] ?? Response::HTTP_OK;
79+
80+
if ($request->attributes->has('_api_write_item_iri')) {
81+
$headers['Content-Location'] = $request->attributes->get('_api_write_item_iri');
82+
83+
if ((Response::HTTP_CREATED === $status || (300 <= $status && $status < 400)) && $request->isMethod('POST')) {
84+
$headers['Location'] = $request->attributes->get('_api_write_item_iri');
85+
}
86+
}
87+
8688
$event->setResponse(new Response(
8789
$controllerResult,
88-
$status ?? self::METHOD_TO_CODE[$request->getMethod()] ?? Response::HTTP_OK,
90+
$status,
8991
$headers
9092
));
9193
}

tests/EventListener/RespondListenerTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,55 @@ public function testCreate200Response()
8080
$this->assertEquals('deny', $response->headers->get('X-Frame-Options'));
8181
}
8282

83+
public function testPost200WithoutLocation()
84+
{
85+
$kernelProphecy = $this->prophesize(HttpKernelInterface::class);
86+
87+
$request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1']);
88+
$request->setMethod('POST');
89+
90+
$event = new ViewEvent(
91+
$kernelProphecy->reveal(),
92+
$request,
93+
HttpKernelInterface::MASTER_REQUEST,
94+
'bar'
95+
);
96+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
97+
$resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata(null, null, null, ['get' => ['status' => Response::HTTP_OK]]));
98+
99+
$listener = new RespondListener($resourceMetadataFactoryProphecy->reveal());
100+
$listener->onKernelView($event);
101+
102+
$response = $event->getResponse();
103+
$this->assertFalse($response->headers->has('Location'));
104+
$this->assertSame(Response::HTTP_OK, $event->getResponse()->getStatusCode());
105+
}
106+
107+
public function testPost301WithLocation()
108+
{
109+
$kernelProphecy = $this->prophesize(HttpKernelInterface::class);
110+
111+
$request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1']);
112+
$request->setMethod('POST');
113+
114+
$event = new ViewEvent(
115+
$kernelProphecy->reveal(),
116+
$request,
117+
HttpKernelInterface::MASTER_REQUEST,
118+
'bar'
119+
);
120+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
121+
$resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata(null, null, null, ['get' => ['status' => Response::HTTP_MOVED_PERMANENTLY]]));
122+
123+
$listener = new RespondListener($resourceMetadataFactoryProphecy->reveal());
124+
$listener->onKernelView($event);
125+
126+
$response = $event->getResponse();
127+
$this->assertTrue($response->headers->has('Location'));
128+
$this->assertEquals('/dummy_entities/1', $response->headers->get('Location'));
129+
$this->assertSame(Response::HTTP_MOVED_PERMANENTLY, $event->getResponse()->getStatusCode());
130+
}
131+
83132
public function testCreate201Response()
84133
{
85134
$kernelProphecy = $this->prophesize(HttpKernelInterface::class);
@@ -107,6 +156,7 @@ public function testCreate201Response()
107156
$this->assertEquals('deny', $response->headers->get('X-Frame-Options'));
108157
$this->assertEquals('/dummy_entities/1', $response->headers->get('Location'));
109158
$this->assertEquals('/dummy_entities/1', $response->headers->get('Content-Location'));
159+
$this->assertTrue($response->headers->has('Location'));
110160
}
111161

112162
public function testCreate204Response()

0 commit comments

Comments
 (0)