Skip to content

Commit 08de71c

Browse files
committed
Prevent header Location on POST when status code is not 201 or 30x
1 parent d235fe5 commit 08de71c

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,38 @@ public function testCreate200Response()
8080
$this->assertEquals('deny', $response->headers->get('X-Frame-Options'));
8181
}
8282

83+
public function testPostCreate200Response()
84+
{
85+
$kernelProphecy = $this->prophesize(HttpKernelInterface::class);
86+
87+
$request = new Request([], [], ['_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1', '_api_item_operation_name' => 'post']);
88+
$request->setMethod('POST');
89+
$request->setRequestFormat('xml');
90+
91+
$event = new ViewEvent(
92+
$kernelProphecy->reveal(),
93+
$request,
94+
HttpKernelInterface::MASTER_REQUEST,
95+
'foo'
96+
);
97+
98+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
99+
$resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata(null, null, null, ['post' => ['status' => Response::HTTP_OK]]));
100+
101+
$listener = new RespondListener($resourceMetadataFactoryProphecy->reveal());
102+
$listener->onKernelView($event);
103+
104+
$response = $event->getResponse();
105+
$this->assertEquals('foo', $response->getContent());
106+
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
107+
$this->assertEquals('text/xml; charset=utf-8', $response->headers->get('Content-Type'));
108+
$this->assertEquals('Accept', $response->headers->get('Vary'));
109+
$this->assertEquals('nosniff', $response->headers->get('X-Content-Type-Options'));
110+
$this->assertEquals('deny', $response->headers->get('X-Frame-Options'));
111+
$this->assertFalse($response->headers->has('Location'));
112+
$this->assertEquals('/dummy_entities/1', $response->headers->get('Content-Location'));
113+
}
114+
83115
public function testCreate201Response()
84116
{
85117
$kernelProphecy = $this->prophesize(HttpKernelInterface::class);

0 commit comments

Comments
 (0)