This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * \AppserverIo\Stomp\StompConnectionHandler |
||
5 | * |
||
6 | * NOTICE OF LICENSE |
||
7 | * |
||
8 | * This source file is subject to the Open Software License (OSL 3.0) |
||
9 | * that is available through the world-wide-web at this URL: |
||
10 | * http://opensource.org/licenses/osl-3.0.php |
||
11 | * |
||
12 | * PHP version 5 |
||
13 | * |
||
14 | * @author Lars Roettig <[email protected]> |
||
15 | * @copyright 2016 TechDivision GmbH - <[email protected]> |
||
16 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
||
17 | * @link http://www.appserver.io/ |
||
18 | */ |
||
19 | |||
20 | namespace AppserverIo\Stomp; |
||
21 | |||
22 | use AppserverIo\Psr\Socket\SocketInterface; |
||
23 | use AppserverIo\Server\Interfaces\ConnectionHandlerInterface; |
||
24 | use AppserverIo\Server\Interfaces\ServerContextInterface; |
||
25 | use AppserverIo\Server\Interfaces\WorkerInterface; |
||
26 | use AppserverIo\Stomp\Exception\ProtocolException; |
||
27 | use AppserverIo\Stomp\Interfaces\ProtocolHandlerInterface; |
||
28 | use AppserverIo\Stomp\Utils\ErrorMessages; |
||
29 | use Psr\Log\LogLevel; |
||
30 | |||
31 | /** |
||
32 | * The connection handler to handle stomp requests. |
||
33 | * |
||
34 | * @author Lars Roettig <[email protected]> |
||
35 | * @copyright 2016 TechDivision GmbH - <[email protected]> |
||
36 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
||
37 | * @link http://www.appserver.io/ |
||
38 | * @link https://github.com/stomp/stomp-spec/blob/master/src/stomp-specification-1.1.md |
||
39 | */ |
||
40 | class ConnectionHandler implements ConnectionHandlerInterface |
||
41 | { |
||
42 | |||
43 | /** |
||
44 | * Hold's the server context instance |
||
45 | * |
||
46 | * @var \AppserverIo\Server\Interfaces\ServerContextInterface |
||
47 | */ |
||
48 | protected $serverContext; |
||
49 | |||
50 | /** |
||
51 | * Hold's the request's context instance |
||
52 | * |
||
53 | * @var \AppserverIo\Server\Interfaces\RequestContextInterface |
||
54 | */ |
||
55 | protected $requestContext; |
||
56 | |||
57 | /** |
||
58 | * Hold's an array of modules to use for connection handler |
||
59 | * |
||
60 | * @var array |
||
61 | */ |
||
62 | protected $modules; |
||
63 | |||
64 | /** |
||
65 | * Hold's the connection instance |
||
66 | * |
||
67 | * @var \AppserverIo\Psr\Socket\SocketInterface |
||
68 | */ |
||
69 | protected $connection; |
||
70 | |||
71 | /** |
||
72 | * Hold's the worker instance |
||
73 | * |
||
74 | * @var \AppserverIo\Server\Interfaces\WorkerInterface |
||
75 | */ |
||
76 | protected $worker; |
||
77 | |||
78 | /** |
||
79 | * Flag if a shutdown function was registered or not |
||
80 | * |
||
81 | * @var boolean |
||
82 | */ |
||
83 | protected $hasRegisteredShutdown = false; |
||
84 | |||
85 | /** |
||
86 | * Holds the stomp protocol handler. |
||
87 | * |
||
88 | * @var \AppserverIo\Stomp\Interfaces\ProtocolHandlerInterface |
||
89 | */ |
||
90 | protected $protocolHandler; |
||
91 | |||
92 | /** |
||
93 | * Holds the stomp frame. |
||
94 | * |
||
95 | * @var \AppserverIo\Stomp\Interfaces\FrameInterface |
||
96 | */ |
||
97 | protected $stompFrame; |
||
98 | |||
99 | /** |
||
100 | * Holds the stomp parser. |
||
101 | * |
||
102 | * @var \AppserverIo\Stomp\Interfaces\RequestParserInterface |
||
103 | */ |
||
104 | protected $stompParser; |
||
105 | |||
106 | /** |
||
107 | * The logger for the connection handler |
||
108 | * |
||
109 | * @var \Psr\Log\LoggerInterface |
||
110 | */ |
||
111 | protected $logger; |
||
112 | |||
113 | /** |
||
114 | * Holds the maximum command length in bytes. |
||
115 | * |
||
116 | * @var int |
||
117 | */ |
||
118 | protected $maxCommandLength = 20; |
||
119 | |||
120 | /** |
||
121 | * Holds the maximum count of header lines. |
||
122 | * |
||
123 | * @var int |
||
124 | */ |
||
125 | protected $maxHeaders = 1000; |
||
126 | |||
127 | /**. |
||
128 | * Holds the max string length of the header in bytes. |
||
129 | * |
||
130 | * @var int |
||
131 | */ |
||
132 | protected $maxHeaderLength = 102410; |
||
133 | |||
134 | /** |
||
135 | * Holds the max string length of the data in bytes. |
||
136 | * |
||
137 | * @var int |
||
138 | */ |
||
139 | protected $maxDataLength = 10241024100; |
||
140 | |||
141 | /** |
||
142 | * Holds must the connection closed. |
||
143 | * |
||
144 | * @var bool |
||
145 | */ |
||
146 | protected $closeConnection = false; |
||
147 | |||
148 | /** |
||
149 | * Holds the flag for developer mode. |
||
150 | * |
||
151 | * @var bool |
||
152 | */ |
||
153 | protected $developerMode = false; |
||
154 | |||
155 | /** |
||
156 | * Holds the configuration key for maxCommandLength. |
||
157 | * |
||
158 | * @var string |
||
159 | */ |
||
160 | const KEY_MAX_COMMAND_LENGTH = 'maxCommandLength'; |
||
161 | |||
162 | /** |
||
163 | * Holds the configuration key for maxHeaders. |
||
164 | * |
||
165 | * @var string |
||
166 | */ |
||
167 | const KEY_MAX_HEADERS = 'maxHeaders'; |
||
168 | |||
169 | /** |
||
170 | * Holds the configuration key for maxHeaderLength. |
||
171 | * |
||
172 | * @var string |
||
173 | */ |
||
174 | const KEY_MAX_HEADER_LENGTH = 'maxHeaderLength'; |
||
175 | |||
176 | /** |
||
177 | * Holds the configuration key for maxDataLength. |
||
178 | * |
||
179 | * @var string |
||
180 | */ |
||
181 | const KEY_MAX_DATA_LENGTH = 'maxDataLength'; |
||
182 | |||
183 | /** |
||
184 | * Holds the configuration key for developerMode. |
||
185 | * |
||
186 | * @var string |
||
187 | */ |
||
188 | const KEY_DEVELOPER_MODE = 'developerMode'; |
||
189 | |||
190 | /** |
||
191 | * Inits the connection handler by given context and params |
||
192 | * |
||
193 | * @param \AppserverIo\Server\Interfaces\ServerContextInterface $serverContext The server's context |
||
194 | * @param array $params The params for connection handler |
||
195 | * |
||
196 | * @return void |
||
197 | */ |
||
198 | public function init(ServerContextInterface $serverContext, array $params = null) |
||
199 | { |
||
200 | // set server context |
||
201 | $this->serverContext = $serverContext; |
||
202 | |||
203 | // register shutdown handler |
||
204 | register_shutdown_function(array(&$this, "shutdown")); |
||
205 | |||
206 | // get the logger for the connection handler |
||
207 | $this->logger = $serverContext->getLogger(); |
||
208 | |||
209 | if (isset($params) && is_array($params)) { |
||
210 | // set the configuration for the connection handler. |
||
211 | $this->setConfigValues($params); |
||
212 | } |
||
213 | |||
214 | // injects new stomp handler |
||
215 | $this->injectProtocolHandler(new ProtocolHandler()); |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Init instances for the stompConnection handler |
||
220 | * |
||
221 | * @return void |
||
222 | */ |
||
223 | public function initInstances() |
||
224 | { |
||
225 | // init new stomp frame with received command |
||
226 | $this->stompFrame = new Frame(); |
||
227 | |||
228 | // init new stomp frame parser |
||
229 | $this->stompParser = new Parser(); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Injects all needed modules for connection handler to process |
||
234 | * |
||
235 | * @param array $modules An array of Modules |
||
236 | * |
||
237 | * @return void |
||
238 | */ |
||
239 | public function injectModules($modules) |
||
240 | { |
||
241 | $this->modules = $modules; |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Return's all needed modules as array for connection handler to process |
||
246 | * |
||
247 | * @return array An array of Modules |
||
248 | */ |
||
249 | public function getModules() |
||
250 | { |
||
251 | return $this->modules; |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * Return's a specific module instance by given name |
||
256 | * |
||
257 | * @param string $name The modules name to return an instance for |
||
258 | * |
||
259 | * @return \AppserverIo\WebServer\Interfaces\HttpModuleInterface | null |
||
260 | */ |
||
261 | public function getModule($name) |
||
262 | { |
||
263 | if (isset($this->modules[$name])) { |
||
264 | return $this->modules[$name]; |
||
265 | } |
||
266 | |||
267 | return null; |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Return's the request's context instance |
||
272 | * |
||
273 | * @return \AppserverIo\Server\Interfaces\RequestContextInterface |
||
274 | * |
||
275 | * @codeCoverageIgnore |
||
276 | */ |
||
277 | public function getRequestContext() |
||
278 | { |
||
279 | return $this->requestContext; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Return's the server's configuration |
||
284 | * |
||
285 | * @return \AppserverIo\Server\Interfaces\ServerConfigurationInterface |
||
286 | * |
||
287 | * @codeCoverageIgnore |
||
288 | */ |
||
289 | public function getServerConfig() |
||
290 | { |
||
291 | return $this->getServerContext()->getServerConfig(); |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Return's the server context instance |
||
296 | * |
||
297 | * @return \AppserverIo\Server\Interfaces\ServerContextInterface |
||
298 | * |
||
299 | * @codeCoverageIgnore |
||
300 | */ |
||
301 | public function getServerContext() |
||
302 | { |
||
303 | return $this->serverContext; |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Handles the connection with the connected client in a proper way the given |
||
308 | * protocol type and version expects for example. |
||
309 | * |
||
310 | * @param \AppserverIo\Psr\Socket\SocketInterface $connection The connection to handle |
||
311 | * @param \AppserverIo\Server\Interfaces\WorkerInterface $worker The worker how started this handle |
||
312 | * |
||
313 | * @return boolean|null Weather it was responsible to handle the firstLine or not. |
||
314 | */ |
||
315 | public function handle(SocketInterface $connection, WorkerInterface $worker) |
||
316 | { |
||
317 | // add connection ref to self |
||
318 | $this->connection = $connection; |
||
319 | $this->worker = $worker; |
||
320 | $this->protocolHandler->init(); |
||
321 | |||
322 | do { |
||
323 | try { |
||
324 | // set the command initial to empty string |
||
325 | $command = ""; |
||
326 | |||
327 | try { |
||
328 | // read the first line from the connection. |
||
329 | $command = $connection->readLine(); |
||
330 | } catch (\Exception $e) { |
||
331 | // do nothing connection must open |
||
332 | } |
||
333 | |||
334 | // if no command receive retry receive command |
||
335 | if (strlen($command) == 0) { |
||
336 | continue; |
||
337 | } |
||
338 | |||
339 | // some clients send additional newlines for heart beat |
||
340 | if ($command === Frame::NEWLINE) { |
||
341 | continue; |
||
342 | } |
||
343 | |||
344 | // init´s instances for the stompConnection handler |
||
345 | $this->initInstances(); |
||
346 | |||
347 | // remove the newline from the command |
||
348 | $command = rtrim($command, Frame::NEWLINE); |
||
349 | $this->stompFrame->setCommand($command); |
||
350 | |||
351 | if (strlen($command) > $this->maxCommandLength) { |
||
352 | throw new ProtocolException(ErrorMessages::HEADER_COMMAND_LENGTH); |
||
353 | } |
||
354 | |||
355 | // handle the stomp frame header |
||
356 | $this->handleHeader(); |
||
357 | |||
358 | // set the headers for the stomp frame |
||
359 | $this->stompFrame->setHeaders($this->stompParser->getParsedHeaders()); |
||
360 | |||
361 | // handle the stomp frame body |
||
362 | $this->handleBody(); |
||
363 | |||
364 | //log for frame receive |
||
365 | $this->log("FrameReceive", $this->stompFrame, LogLevel::INFO); |
||
366 | |||
367 | // delegate the frame to a handler and write the response in the stream |
||
368 | $this->getProtocolHandler()->handle($this->stompFrame); |
||
0 ignored issues
–
show
|
|||
369 | $response = $this->getProtocolHandler()->getResponseStompFrame(); |
||
370 | if (isset($response)) { |
||
371 | $this->writeFrame($response, $connection); |
||
372 | } |
||
373 | |||
374 | // get the state if will the handler close the connection with the client. |
||
375 | $this->closeConnection = $this->getProtocolHandler()->getMustConnectionClose(); |
||
376 | } catch (\Exception $e) { |
||
377 | // set the current exception as error to get the error frame for the stream |
||
378 | $this->getProtocolHandler()->setErrorState($e->getMessage(), array()); |
||
379 | $response = $this->getProtocolHandler()->getResponseStompFrame(); |
||
380 | $this->writeFrame($response, $connection); |
||
381 | |||
382 | // close the connection |
||
383 | $this->closeConnection = true; |
||
384 | } |
||
385 | } while ($this->closeConnection === false); |
||
386 | |||
387 | // finally close connection |
||
388 | $this->connection->close(); |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Inject the handler stomp handler to handle stomp request. |
||
393 | * |
||
394 | * @param ProtocolHandlerInterface $protocolHandler the protocol handler to inject. |
||
395 | * |
||
396 | * @return void |
||
397 | */ |
||
398 | public function injectProtocolHandler(ProtocolHandlerInterface $protocolHandler) |
||
399 | { |
||
400 | $this->protocolHandler = $protocolHandler; |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * Logs with an arbitrary level. |
||
405 | * |
||
406 | * @param string $message The message to log |
||
407 | * @param Interfaces\FrameInterface $params The params to export |
||
408 | * @param string $level The level to log |
||
409 | * |
||
410 | * @return void |
||
411 | */ |
||
412 | protected function log($message, $params, $level = LogLevel::INFO) |
||
413 | { |
||
414 | |||
415 | // logging is not use if is developer mode deactivate. |
||
416 | if ($this->developerMode === false) { |
||
417 | return; |
||
418 | } |
||
419 | |||
420 | if (isset($params)) { |
||
421 | $message .= var_export($params, true); |
||
422 | } |
||
423 | |||
424 | $this->logger->log($level, $message); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Returns the protocol handler. |
||
429 | * |
||
430 | * @return \AppserverIo\Stomp\Interfaces\ProtocolHandlerInterface |
||
431 | * |
||
432 | * @codeCoverageIgnore |
||
433 | */ |
||
434 | public function getProtocolHandler() |
||
435 | { |
||
436 | return $this->protocolHandler; |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * Write a stomp frame |
||
441 | * |
||
442 | * @param \AppserverIo\Stomp\Frame $stompFrame The stomp frame to write |
||
443 | * @param \AppserverIo\Psr\Socket\SocketInterface $connection The connection to handle |
||
444 | * |
||
445 | * @return void |
||
446 | */ |
||
447 | public function writeFrame(Frame $stompFrame, SocketInterface $connection) |
||
448 | { |
||
449 | $stompFrameStr = (string)$stompFrame; |
||
450 | $this->log("FrameSend", $stompFrame, LogLevel::INFO); |
||
451 | $connection->write($stompFrameStr); |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * Registers the shutdown function in this context |
||
456 | * |
||
457 | * @return void |
||
458 | * |
||
459 | * @codeCoverageIgnore |
||
460 | */ |
||
461 | public function registerShutdown() |
||
462 | { |
||
463 | // register shutdown handler once to avoid strange memory consumption problems |
||
464 | if ($this->hasRegisteredShutdown === false) { |
||
465 | register_shutdown_function(array(&$this, "shutdown")); |
||
466 | $this->hasRegisteredShutdown = true; |
||
467 | } |
||
468 | } |
||
469 | |||
470 | /** |
||
471 | * Does shutdown logic for worker if something breaks in process |
||
472 | * |
||
473 | * @return void |
||
474 | * |
||
475 | * @codeCoverageIgnore |
||
476 | */ |
||
477 | public function shutdown() |
||
478 | { |
||
479 | // get refs to local vars |
||
480 | $connection = $this->getConnection(); |
||
481 | $worker = $this->getWorker(); |
||
482 | |||
483 | // check if connections is still alive |
||
484 | if ($connection) { |
||
485 | // close client connection |
||
486 | $this->getConnection()->close(); |
||
487 | } |
||
488 | |||
489 | // check if worker is given |
||
490 | if ($worker) { |
||
491 | // call shutdown process on worker to re spawn |
||
492 | $this->getWorker()->shutdown(); |
||
493 | } |
||
494 | } |
||
495 | |||
496 | /** |
||
497 | * Return's the connection used to handle with |
||
498 | * |
||
499 | * @return \AppserverIo\Psr\Socket\SocketInterface |
||
500 | * |
||
501 | * @codeCoverageIgnore |
||
502 | */ |
||
503 | protected function getConnection() |
||
504 | { |
||
505 | return $this->connection; |
||
506 | } |
||
507 | |||
508 | /** |
||
509 | * Return's the worker instance which starte this worker thread |
||
510 | * |
||
511 | * @return \AppserverIo\Server\Interfaces\WorkerInterface |
||
512 | * |
||
513 | * @codeCoverageIgnore |
||
514 | */ |
||
515 | protected function getWorker() |
||
516 | { |
||
517 | return $this->worker; |
||
518 | } |
||
519 | |||
520 | /** |
||
521 | * Sets the config values for the connection handler. |
||
522 | * |
||
523 | * @param array $params config values to set. |
||
524 | * |
||
525 | * @return void |
||
526 | */ |
||
527 | public function setConfigValues($params = array()) |
||
528 | { |
||
529 | if (!isset($params) || !is_array($params)) { |
||
530 | return; |
||
531 | } |
||
532 | |||
533 | //set config values |
||
534 | View Code Duplication | if (isset($params[self::KEY_MAX_COMMAND_LENGTH]) && is_numeric($params[self::KEY_MAX_COMMAND_LENGTH])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
535 | $this->maxCommandLength = intval($params[self::KEY_MAX_COMMAND_LENGTH]); |
||
536 | } |
||
537 | |||
538 | View Code Duplication | if (isset($params[self::KEY_MAX_HEADERS]) && is_numeric($params[self::KEY_MAX_HEADERS])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
539 | $this->maxHeaders = intval($params[self::KEY_MAX_HEADERS]); |
||
540 | } |
||
541 | |||
542 | View Code Duplication | if (isset($params[self::KEY_MAX_HEADER_LENGTH]) && is_numeric($params[self::KEY_MAX_HEADER_LENGTH])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
543 | $this->maxHeaders = intval($params[self::KEY_MAX_HEADER_LENGTH]); |
||
544 | } |
||
545 | |||
546 | View Code Duplication | if (isset($params[self::KEY_MAX_DATA_LENGTH]) && is_numeric($params[self::KEY_MAX_DATA_LENGTH])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
547 | $this->maxHeaders = intval($params[self::KEY_MAX_DATA_LENGTH]); |
||
548 | } |
||
549 | |||
550 | if (isset($params[self::KEY_DEVELOPER_MODE]) && is_bool($params[self::KEY_DEVELOPER_MODE])) { |
||
551 | $this->developerMode = $params[self::KEY_DEVELOPER_MODE]; |
||
552 | } |
||
553 | } |
||
554 | |||
555 | /** |
||
556 | * Read the headers from the connection |
||
557 | * |
||
558 | * @throws \AppserverIo\Stomp\Exception\ProtocolException |
||
559 | * |
||
560 | * @return void |
||
561 | */ |
||
562 | protected function handleHeader() |
||
563 | { |
||
564 | // read the headers from the connection |
||
565 | do { |
||
566 | // read next line |
||
567 | $line = $this->getConnection()->readLine(); |
||
568 | |||
569 | // stomp header are complete |
||
570 | if ($line === Frame::NEWLINE) { |
||
571 | break; |
||
572 | } |
||
573 | |||
574 | // remove the last line break |
||
575 | $line = rtrim($line, Frame::NEWLINE); |
||
576 | |||
577 | // check for the max header length |
||
578 | if (strlen($line) > $this->maxHeaderLength) { |
||
579 | throw new ProtocolException(ErrorMessages::HEADER_LENGTH); |
||
580 | } |
||
581 | |||
582 | // check for the max header size |
||
583 | if ($this->stompParser->getHeaderSize() > $this->maxHeaders) { |
||
584 | throw new ProtocolException(ErrorMessages::HEADERS_WAS_EXCEEDED); |
||
585 | } |
||
586 | |||
587 | // parse a single stomp header line |
||
588 | $this->stompParser->parseHeaderLine($line); |
||
589 | |||
590 | } while (true); |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * Read the stomp body from the connection |
||
595 | * |
||
596 | * @throws \AppserverIo\Stomp\Exception\ProtocolException |
||
597 | * |
||
598 | * @return void |
||
599 | */ |
||
600 | protected function handleBody() |
||
601 | { |
||
602 | // read the stomp body |
||
603 | $stompBody = ""; |
||
604 | do { |
||
605 | $stompBody .= $this->getConnection()->read(1); |
||
606 | |||
607 | // check for the max data length |
||
608 | if (strlen($stompBody) > $this->maxDataLength) { |
||
609 | throw new ProtocolException(ErrorMessages::MAX_DATA_LENGTH); |
||
610 | } |
||
611 | |||
612 | } while (false === strpos($stompBody, Frame::NULL)); |
||
613 | |||
614 | // removes the null frame from the body string |
||
615 | $stompBody = str_replace(Frame::NULL, "", $stompBody); |
||
616 | |||
617 | // set the body for the stomp frame |
||
618 | $this->stompFrame->setBody($stompBody); |
||
619 | } |
||
620 | } |
||
621 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.