@@ -175,6 +175,85 @@ public function testClosedConnection()
175175 $ this ->assertTrue ($ context ['connection ' ]->isClosed ());
176176 }
177177
178+ /**
179+ * Test that the daemon doesn't accept new requests once it has been
180+ * shutdown but still handles old ones
181+ */
182+ public function testShutdown ()
183+ {
184+ $ response = new Response ($ this ->toStream ('Hello World ' ), 200 );
185+
186+ $ kernelCalled = false ;
187+
188+ // Create test environment
189+ $ context = $ this ->createTestingContext (function (ServerRequestInterface $ request ) use ($ response , &$ kernelCalled ) {
190+ $ this ->assertEquals (['FOO ' => 'bar ' ], $ request ->getServerParams ());
191+
192+ $ kernelCalled = true ;
193+
194+ return $ response ;
195+ });
196+
197+ // Write half of the first request (id 0)
198+ $ context ['clientWrapper ' ]->writeBeginRequestRecord (0 , DaemonInterface::FCGI_RESPONDER , DaemonInterface::FCGI_KEEP_CONNECTION );
199+ $ context ['clientWrapper ' ]->writeParamsRecord (0 , 'foo ' , 'bar ' );
200+ $ context ['clientWrapper ' ]->writeParamsRecord (0 );
201+
202+ // Process first half of the first request
203+ $ context ['handler ' ]->ready ();
204+
205+ // Trigger the shutdown method
206+ $ context ['handler ' ]->shutdown ();
207+
208+ // Try creating a new request (id 1)
209+ $ context ['clientWrapper ' ]->writeBeginRequestRecord (1 , DaemonInterface::FCGI_RESPONDER , DaemonInterface::FCGI_KEEP_CONNECTION );
210+
211+ // Process the attempt at a second request after the shutdown
212+ $ context ['handler ' ]->ready ();
213+
214+ // The application should end the second request immediately
215+ $ record = $ context ['clientWrapper ' ]->readRecord ($ this );
216+ $ this ->assertEquals (DaemonInterface::FCGI_END_REQUEST , $ record ['type ' ]);
217+ $ this ->assertEquals (1 , $ record ['requestId ' ]);
218+
219+ // The application should declare an overloaded protocol status
220+ $ content = unpack ('NappStatus/CprotocolStatus/x3 ' , $ record ['contentData ' ]);
221+ $ this ->assertEquals (DaemonInterface::FCGI_OVERLOADED , $ content ['protocolStatus ' ]);
222+
223+ // Check daemon hasn't closed server side connection
224+ $ this ->assertFalse ($ context ['connection ' ]->isClosed ());
225+
226+ // Write the second half of the first request
227+ $ context ['clientWrapper ' ]->writeStdinRecord (0 );
228+
229+ // Process the second half of the first request
230+ $ context ['handler ' ]->ready ();
231+
232+ // Assert that kernel was called
233+ $ this ->assertTrue ($ kernelCalled );
234+
235+ // Receive response
236+ $ rawResponse = '' ;
237+
238+ do {
239+ $ record = $ context ['clientWrapper ' ]->readRecord ($ this );
240+
241+ $ this ->assertEquals (0 , $ record ['requestId ' ]);
242+
243+ if (DaemonInterface::FCGI_STDOUT === $ record ['type ' ]) {
244+ $ rawResponse .= $ record ['contentData ' ];
245+ }
246+ } while (DaemonInterface::FCGI_END_REQUEST !== $ record ['type ' ]);
247+
248+ $ expectedResponse = "Status: 200 OK \r\n\r\nHello World " ;
249+
250+ // Check response
251+ $ this ->assertEquals ($ expectedResponse , $ rawResponse );
252+
253+ // Close the client side socket
254+ fclose ($ context ['sockets ' ][0 ]);
255+ }
256+
178257 /**
179258 * Test that the daemon correctly handles a kernel exception.
180259 */
@@ -403,7 +482,7 @@ public function testUnknownRole()
403482
404483 // The application should respond with an end request record
405484 $ record = $ context ['clientWrapper ' ]->readRecord ($ this );
406- $ this ->assertEquals (DaemonInterface::FCGI_END_REQUEST , $ record ['type ' ]);
485+ $ this ->assertEquals (DaemonInterface::FCGI_END_REQUEST , $ record ['type ' ]);
407486
408487 // The application should declare an unknown role protocol status
409488 $ content = unpack ('NappStatus/CprotocolStatus/x3 ' , $ record ['contentData ' ]);
0 commit comments