Skip to content

Commit 9426874

Browse files
committed
Extract helper class to create Responses from legacy data
1 parent 50109a1 commit 9426874

File tree

2 files changed

+148
-134
lines changed

2 files changed

+148
-134
lines changed

Integration/LegacyCaptureResponseFactory.php

Lines changed: 1 addition & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,8 @@
88

99
namespace Webfactory\Bundle\LegacyIntegrationBundle\Integration;
1010

11-
use Symfony\Component\HttpFoundation\Cookie;
12-
use Symfony\Component\HttpFoundation\RedirectResponse;
13-
14-
use Symfony\Component\HttpFoundation\Response;
15-
1611
class LegacyCaptureResponseFactory
1712
{
18-
private static $dateFormats = array(
19-
'D, d M Y H:i:s T',
20-
'D, d-M-y H:i:s T',
21-
'D, d-M-Y H:i:s T',
22-
'D, d-m-y H:i:s T',
23-
'D, d-m-Y H:i:s T',
24-
'D M j G:i:s Y',
25-
'D M d H:i:s Y T',
26-
);
27-
2813
public static function create($legacyExecutionCallback)
2914
{
3015
// Preserve all headers that have previously been set (pre-Legacy startup)
@@ -66,124 +51,6 @@ private static function runLegacyAndCaptureResponse($legacyExecutionCallback)
6651
$headers = headers_list();
6752
header_remove();
6853

69-
$responseHeaders = array();
70-
$cookies = array();
71-
72-
foreach ($headers as $header) {
73-
preg_match('(^([^:]+):(.*)$)', $header, $matches);
74-
$headerName = strtolower(trim($matches[1]));
75-
$headerValue = trim($matches[2]);
76-
77-
if ($headerName == 'set-cookie') {
78-
$cookies[] = self::createCookieFromString($headerValue);
79-
} else {
80-
$responseHeaders[$headerName][] = $headerValue;
81-
}
82-
}
83-
84-
if (isset($responseHeaders['location'])) {
85-
unset($responseHeaders['expires']);
86-
$response = new RedirectResponse($responseHeaders['location'][0], 302, $responseHeaders);
87-
} else {
88-
$response = new Response($content, $statusCode, $responseHeaders);
89-
}
90-
91-
foreach ($cookies as $cookie) {
92-
$response->headers->setCookie($cookie);
93-
}
94-
95-
return $response;
96-
}
97-
98-
private static function createCookieFromString($cookie, $url = null)
99-
{
100-
$parts = explode(';', $cookie);
101-
102-
if (false === strpos($parts[0], '=')) {
103-
throw new \InvalidArgumentException(sprintf('The cookie string "%s" is not valid.', $parts[0]));
104-
}
105-
106-
list($name, $value) = explode('=', array_shift($parts), 2);
107-
108-
$values = array(
109-
'name' => trim($name),
110-
// Cookie value must be decoded, otherwise it is encoded again when we forward it to the Symfony response.
111-
// That would lead to problems, for example with session cookies whose id can contain a comma.
112-
'value' => trim(urldecode($value)),
113-
'expires' => 0,
114-
'path' => '/',
115-
'domain' => '',
116-
'secure' => false,
117-
'httponly' => false
118-
);
119-
120-
if (null !== $url) {
121-
if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host'])) {
122-
throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url));
123-
}
124-
125-
$values['domain'] = $urlParts['host'];
126-
$values['path'] = isset($urlParts['path']) ? substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')) : '';
127-
}
128-
129-
foreach ($parts as $part) {
130-
$part = trim($part);
131-
132-
if ('secure' === strtolower($part)) {
133-
// Ignore the secure flag if the original URI is not given or is not HTTPS
134-
if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) {
135-
continue;
136-
}
137-
138-
$values['secure'] = true;
139-
140-
continue;
141-
}
142-
143-
if ('httponly' === strtolower($part)) {
144-
$values['httponly'] = true;
145-
146-
continue;
147-
}
148-
149-
if (2 === count($elements = explode('=', $part, 2))) {
150-
if ('expires' === strtolower($elements[0])) {
151-
$elements[1] = self::parseDate($elements[1]);
152-
}
153-
154-
$values[strtolower($elements[0])] = $elements[1];
155-
}
156-
}
157-
158-
return new Cookie(
159-
$values['name'],
160-
$values['value'],
161-
$values['expires'],
162-
$values['path'],
163-
$values['domain'],
164-
$values['secure'],
165-
$values['httponly']
166-
);
167-
}
168-
169-
private static function parseDate($dateValue)
170-
{
171-
// trim single quotes around date if present
172-
if (($length = strlen($dateValue)) > 1 && "'" === $dateValue[0] && "'" === $dateValue[$length - 1]) {
173-
$dateValue = substr($dateValue, 1, -1);
174-
}
175-
176-
foreach (self::$dateFormats as $dateFormat) {
177-
if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) {
178-
return $date->getTimestamp();
179-
}
180-
}
181-
182-
// attempt a fallback for unusual formatting
183-
if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) {
184-
return $date->getTimestamp();
185-
}
186-
187-
throw new \InvalidArgumentException(sprintf('Could not parse date "%s".', $dateValue));
54+
return ResponseCaptureHelper::createResponse($content, $statusCode, $headers);
18855
}
18956
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
namespace Webfactory\Bundle\LegacyIntegrationBundle\Integration;
4+
5+
use Symfony\Component\HttpFoundation\Cookie;
6+
use Symfony\Component\HttpFoundation\RedirectResponse;
7+
use Symfony\Component\HttpFoundation\Response;
8+
9+
/**
10+
* Helper class to create a Symfony Response object from raw (legacy) header
11+
* and content data
12+
*/
13+
class ResponseCaptureHelper
14+
{
15+
private static $dateFormats = [
16+
'D, d M Y H:i:s T',
17+
'D, d-M-y H:i:s T',
18+
'D, d-M-Y H:i:s T',
19+
'D, d-m-y H:i:s T',
20+
'D, d-m-Y H:i:s T',
21+
'D M j G:i:s Y',
22+
'D M d H:i:s Y T',
23+
];
24+
25+
public static function createResponse(string $content, int $status, array $headers): Response
26+
{
27+
$responseHeaders = [];
28+
$cookies = [];
29+
30+
foreach ($headers as $header) {
31+
preg_match('(^([^:]+):(.*)$)', $header, $matches);
32+
$headerName = strtolower(trim($matches[1]));
33+
$headerValue = trim($matches[2]);
34+
35+
if ($headerName == 'set-cookie') {
36+
$cookies[] = self::createCookieFromString($headerValue);
37+
} else {
38+
$responseHeaders[$headerName][] = $headerValue;
39+
}
40+
}
41+
42+
if (isset($responseHeaders['location'])) {
43+
unset($responseHeaders['expires']);
44+
$response = new RedirectResponse($responseHeaders['location'][0], 302, $responseHeaders);
45+
} else {
46+
$response = new Response($content, $status, $responseHeaders);
47+
}
48+
49+
foreach ($cookies as $cookie) {
50+
$response->headers->setCookie($cookie);
51+
}
52+
53+
return $response;
54+
}
55+
56+
private static function createCookieFromString($cookie, $url = null)
57+
{
58+
$parts = explode(';', $cookie);
59+
60+
if (false === strpos($parts[0], '=')) {
61+
throw new \InvalidArgumentException(sprintf('The cookie string "%s" is not valid.', $parts[0]));
62+
}
63+
64+
[$name, $value] = explode('=', array_shift($parts), 2);
65+
66+
$values = [
67+
'name' => trim($name),
68+
// Cookie value must be decoded, otherwise it is encoded again when we forward it to the Symfony response.
69+
// That would lead to problems, for example with session cookies whose id can contain a comma.
70+
'value' => trim(urldecode($value)),
71+
'expires' => 0,
72+
'path' => '/',
73+
'domain' => '',
74+
'secure' => false,
75+
'httponly' => false,
76+
];
77+
78+
if (null !== $url) {
79+
if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host'])) {
80+
throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url));
81+
}
82+
83+
$values['domain'] = $urlParts['host'];
84+
$values['path'] = isset($urlParts['path']) ? substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')) : '';
85+
}
86+
87+
foreach ($parts as $part) {
88+
$part = trim($part);
89+
90+
if ('secure' === strtolower($part)) {
91+
// Ignore the secure flag if the original URI is not given or is not HTTPS
92+
if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) {
93+
continue;
94+
}
95+
96+
$values['secure'] = true;
97+
98+
continue;
99+
}
100+
101+
if ('httponly' === strtolower($part)) {
102+
$values['httponly'] = true;
103+
104+
continue;
105+
}
106+
107+
if (2 === count($elements = explode('=', $part, 2))) {
108+
if ('expires' === strtolower($elements[0])) {
109+
$elements[1] = self::parseDate($elements[1]);
110+
}
111+
112+
$values[strtolower($elements[0])] = $elements[1];
113+
}
114+
}
115+
116+
return new Cookie(
117+
$values['name'],
118+
$values['value'],
119+
$values['expires'],
120+
$values['path'],
121+
$values['domain'],
122+
$values['secure'],
123+
$values['httponly']
124+
);
125+
}
126+
127+
private static function parseDate($dateValue)
128+
{
129+
// trim single quotes around date if present
130+
if (($length = strlen($dateValue)) > 1 && "'" === $dateValue[0] && "'" === $dateValue[$length - 1]) {
131+
$dateValue = substr($dateValue, 1, -1);
132+
}
133+
134+
foreach (self::$dateFormats as $dateFormat) {
135+
if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) {
136+
return $date->getTimestamp();
137+
}
138+
}
139+
140+
// attempt a fallback for unusual formatting
141+
if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) {
142+
return $date->getTimestamp();
143+
}
144+
145+
throw new \InvalidArgumentException(sprintf('Could not parse date "%s".', $dateValue));
146+
}
147+
}

0 commit comments

Comments
 (0)