Issues (5)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/AppserverIo/Stomp/ConnectionHandler.php (5 issues)

Upgrade to new PHP Analysis Engine

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
$this->stompFrame of type object<AppserverIo\Stomp...erfaces\FrameInterface> is not a sub-type of object<AppserverIo\Stomp\Frame>. It seems like you assume a concrete implementation of the interface AppserverIo\Stomp\Interfaces\FrameInterface to be always present.

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.

Loading history...
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.

Loading history...
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.

Loading history...
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.

Loading history...
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.

Loading history...
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