Skip to content

Commit 29741b0

Browse files
committed
Minor internal refactoring to apply server params during request ctor
This changeset is in preparation for upcoming refactorings to move unrelated logic out of the parser class to prepare for persistent HTTP connections in follow-up PR. This changeset does not affect the public API and happens to improves performance slightly from around 8800 req/s to 9000 req/s on my machine (best of 5).
1 parent c02fc4b commit 29741b0

3 files changed

Lines changed: 115 additions & 52 deletions

File tree

src/Io/RequestHeaderParser.php

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,6 @@ private function parseRequest($headers)
130130
);
131131
$request = $request->withRequestTarget($target);
132132

133-
// Add query params
134-
$queryString = $request->getUri()->getQuery();
135-
if ($queryString !== '') {
136-
$queryParams = array();
137-
\parse_str($queryString, $queryParams);
138-
$request = $request->withQueryParams($queryParams);
139-
}
140-
141-
$cookies = ServerRequest::parseCookie($request->getHeaderLine('Cookie'));
142-
if ($cookies !== false) {
143-
$request = $request->withCookieParams($cookies);
144-
}
145-
146133
// re-apply actual request target from above
147134
if ($originalTarget !== null) {
148135
$request = $request->withUri(

src/Io/ServerRequest.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ public function __construct(
5151
) {
5252
$this->serverParams = $serverParams;
5353
parent::__construct($method, $uri, $headers, $body, $protocolVersion);
54+
55+
$query = $this->getUri()->getQuery();
56+
if ($query !== '') {
57+
\parse_str($query, $this->queryParams);
58+
}
59+
60+
$this->cookies = $this->parseCookie($this->getHeaderLine('Cookie'));
5461
}
5562

5663
public function getServerParams()
@@ -134,17 +141,16 @@ public function withoutAttribute($name)
134141
}
135142

136143
/**
137-
* @internal
138144
* @param string $cookie
139-
* @return boolean|mixed[]
145+
* @return array
140146
*/
141-
public static function parseCookie($cookie)
147+
private function parseCookie($cookie)
142148
{
143-
// PSR-7 `getHeaderLine('Cookies')` will return multiple
149+
// PSR-7 `getHeaderLine('Cookie')` will return multiple
144150
// cookie header comma-seperated. Multiple cookie headers
145151
// are not allowed according to https://tools.ietf.org/html/rfc6265#section-5.4
146-
if (\strpos($cookie, ',') !== false) {
147-
return false;
152+
if ($cookie === '' || \strpos($cookie, ',') !== false) {
153+
return array();
148154
}
149155

150156
$cookieArray = \explode(';', $cookie);

tests/Io/ServerRequestTest.php

Lines changed: 103 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ public function testWithoutAttribute()
5454
$this->assertEquals(array('test' => 'nice'), $request->getAttributes());
5555
}
5656

57+
public function testGetQueryParamsFromConstructorUri()
58+
{
59+
$this->request = new ServerRequest('GET', 'http://localhost/?test=world');
60+
61+
$this->assertEquals(array('test' => 'world'), $this->request->getQueryParams());
62+
}
63+
5764
public function testWithCookieParams()
5865
{
5966
$request = $this->request->withCookieParams(array('test' => 'world'));
@@ -62,6 +69,13 @@ public function testWithCookieParams()
6269
$this->assertEquals(array('test' => 'world'), $request->getCookieParams());
6370
}
6471

72+
public function testGetQueryParamsFromConstructorUriUrlencoded()
73+
{
74+
$this->request = new ServerRequest('GET', 'http://localhost/?test=hello+world%21');
75+
76+
$this->assertEquals(array('test' => 'hello world!'), $this->request->getQueryParams());
77+
}
78+
6579
public function testWithQueryParams()
6680
{
6781
$request = $this->request->withQueryParams(array('test' => 'world'));
@@ -70,6 +84,14 @@ public function testWithQueryParams()
7084
$this->assertEquals(array('test' => 'world'), $request->getQueryParams());
7185
}
7286

87+
public function testWithQueryParamsWithoutSpecialEncoding()
88+
{
89+
$request = $this->request->withQueryParams(array('test' => 'hello world!'));
90+
91+
$this->assertNotSame($request, $this->request);
92+
$this->assertEquals(array('test' => 'hello world!'), $request->getQueryParams());
93+
}
94+
7395
public function testWithUploadedFiles()
7496
{
7597
$request = $this->request->withUploadedFiles(array('test' => 'world'));
@@ -109,85 +131,133 @@ public function testServerRequestParameter()
109131

110132
public function testParseSingleCookieNameValuePairWillReturnValidArray()
111133
{
112-
$cookieString = 'hello=world';
113-
$cookies = ServerRequest::parseCookie($cookieString);
134+
$this->request = new ServerRequest(
135+
'GET',
136+
'http://localhost',
137+
array('Cookie' => 'hello=world')
138+
);
139+
140+
$cookies = $this->request->getCookieParams();
114141
$this->assertEquals(array('hello' => 'world'), $cookies);
115142
}
116143

117-
public function testParseMultipleCookieNameValuePaiWillReturnValidArray()
144+
public function testParseMultipleCookieNameValuePairWillReturnValidArray()
118145
{
119-
$cookieString = 'hello=world; test=abc';
120-
$cookies = ServerRequest::parseCookie($cookieString);
146+
$this->request = new ServerRequest(
147+
'GET',
148+
'http://localhost',
149+
array('Cookie' => 'hello=world; test=abc')
150+
);
151+
152+
$cookies = $this->request->getCookieParams();
121153
$this->assertEquals(array('hello' => 'world', 'test' => 'abc'), $cookies);
122154
}
123155

124-
public function testParseMultipleCookieNameValuePairWillReturnFalse()
156+
public function testParseMultipleCookieHeadersAreNotAllowedAndWillReturnEmptyArray()
125157
{
126-
// Could be done through multiple 'Cookie' headers
127-
// getHeaderLine('Cookie') will return a value seperated by comma
128-
// e.g.
129-
// GET / HTTP/1.1\r\n
130-
// Host: test.org\r\n
131-
// Cookie: hello=world\r\n
132-
// Cookie: test=abc\r\n\r\n
133-
$cookieString = 'hello=world,test=abc';
134-
$cookies = ServerRequest::parseCookie($cookieString);
135-
$this->assertEquals(false, $cookies);
158+
$this->request = new ServerRequest(
159+
'GET',
160+
'http://localhost',
161+
array('Cookie' => array('hello=world', 'test=abc'))
162+
);
163+
164+
$cookies = $this->request->getCookieParams();
165+
$this->assertEquals(array(), $cookies);
136166
}
137167

138-
public function testOnlyFirstSetWillBeAddedToCookiesArray()
168+
public function testMultipleCookiesWithSameNameWillReturnLastValue()
139169
{
140-
$cookieString = 'hello=world; hello=abc';
141-
$cookies = ServerRequest::parseCookie($cookieString);
170+
$this->request = new ServerRequest(
171+
'GET',
172+
'http://localhost',
173+
array('Cookie' => 'hello=world; hello=abc')
174+
);
175+
176+
$cookies = $this->request->getCookieParams();
142177
$this->assertEquals(array('hello' => 'abc'), $cookies);
143178
}
144179

145180
public function testOtherEqualSignsWillBeAddedToValueAndWillReturnValidArray()
146181
{
147-
$cookieString = 'hello=world=test=php';
148-
$cookies = ServerRequest::parseCookie($cookieString);
182+
$this->request = new ServerRequest(
183+
'GET',
184+
'http://localhost',
185+
array('Cookie' => 'hello=world=test=php')
186+
);
187+
188+
$cookies = $this->request->getCookieParams();
149189
$this->assertEquals(array('hello' => 'world=test=php'), $cookies);
150190
}
151191

152192
public function testSingleCookieValueInCookiesReturnsEmptyArray()
153193
{
154-
$cookieString = 'world';
155-
$cookies = ServerRequest::parseCookie($cookieString);
194+
$this->request = new ServerRequest(
195+
'GET',
196+
'http://localhost',
197+
array('Cookie' => 'world')
198+
);
199+
200+
$cookies = $this->request->getCookieParams();
156201
$this->assertEquals(array(), $cookies);
157202
}
158203

159204
public function testSingleMutlipleCookieValuesReturnsEmptyArray()
160205
{
161-
$cookieString = 'world; test';
162-
$cookies = ServerRequest::parseCookie($cookieString);
206+
$this->request = new ServerRequest(
207+
'GET',
208+
'http://localhost',
209+
array('Cookie' => 'world; test')
210+
);
211+
212+
$cookies = $this->request->getCookieParams();
163213
$this->assertEquals(array(), $cookies);
164214
}
165215

166216
public function testSingleValueIsValidInMultipleValueCookieWillReturnValidArray()
167217
{
168-
$cookieString = 'world; test=php';
169-
$cookies = ServerRequest::parseCookie($cookieString);
218+
$this->request = new ServerRequest(
219+
'GET',
220+
'http://localhost',
221+
array('Cookie' => 'world; test=php')
222+
);
223+
224+
$cookies = $this->request->getCookieParams();
170225
$this->assertEquals(array('test' => 'php'), $cookies);
171226
}
172227

173228
public function testUrlEncodingForValueWillReturnValidArray()
174229
{
175-
$cookieString = 'hello=world%21; test=100%25%20coverage';
176-
$cookies = ServerRequest::parseCookie($cookieString);
230+
$this->request = new ServerRequest(
231+
'GET',
232+
'http://localhost',
233+
array('Cookie' => 'hello=world%21; test=100%25%20coverage')
234+
);
235+
236+
$cookies = $this->request->getCookieParams();
177237
$this->assertEquals(array('hello' => 'world!', 'test' => '100% coverage'), $cookies);
178238
}
179239

180240
public function testUrlEncodingForKeyWillReturnValidArray()
181241
{
182-
$cookieString = 'react%3Bphp=is%20great';
183-
$cookies = ServerRequest::parseCookie($cookieString);
242+
$this->request = new ServerRequest(
243+
'GET',
244+
'http://localhost',
245+
array('Cookie' => 'react%3Bphp=is%20great')
246+
);
247+
248+
$cookies = $this->request->getCookieParams();
184249
$this->assertEquals(array('react;php' => 'is great'), $cookies);
185250
}
186251

187252
public function testCookieWithoutSpaceAfterSeparatorWillBeAccepted()
188253
{
189-
$cookieString = 'hello=world;react=php';
190-
$cookies = ServerRequest::parseCookie($cookieString);
254+
$this->request = new ServerRequest(
255+
'GET',
256+
'http://localhost',
257+
array('Cookie' => 'hello=world;react=php')
258+
);
259+
260+
$cookies = $this->request->getCookieParams();
191261
$this->assertEquals(array('hello' => 'world', 'react' => 'php'), $cookies);
192262
}
193263
}

0 commit comments

Comments
 (0)