Completed
Push — master ( 2ed294...dbc2b7 )
by Nils
02:31
created

Scanner::scan()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 24
rs 8.5125
cc 5
eloc 12
nc 4
nop 0
1
<?php
2
3
namespace whm\Smoke\Scanner;
4
5
use Ivory\HttpAdapter\HttpAdapterInterface;
6
use phmLabs\Components\Annovent\Dispatcher;
7
use phmLabs\Components\Annovent\Event\Event;
8
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
9
use whm\Smoke\Http\ClientAware;
10
use whm\Smoke\Http\Response;
11
use whm\Smoke\Rules\CheckResult;
12
use whm\Smoke\Rules\Rule;
13
use whm\Smoke\Rules\ValidationFailedException;
14
15
class Scanner
16
{
17
    const ERROR = 'error';
18
    const PASSED = 'passed';
19
20
    /**
21
     * @var Rule[]
22
     */
23
    private $rules;
24
    private $eventDispatcher;
25
26
    private $responseRetriever;
27
28
    private $status = 0;
29
30
    public function __construct(array $rules, HttpAdapterInterface $client, Dispatcher $eventDispatcher, Retriever $responseRetriever)
31
    {
32
        $eventDispatcher->simpleNotify('Scanner.Init', array('rules' => $rules, 'httpClient' => $client, 'dispatcher' => $eventDispatcher));
33
34
        $this->initRules($rules, $client);
35
36
        $this->eventDispatcher = $eventDispatcher;
37
38
        $this->responseRetriever = $responseRetriever;
39
40
        $this->eventDispatcher->simpleNotify('Scanner.Init.ResponseRetriever', array('responseRetriever' => $this->responseRetriever));
41
    }
42
43
    private function initRules($rules, HttpAdapterInterface $client)
44
    {
45
        $this->rules = $rules;
46
        foreach ($this->rules as $rule) {
47
            if ($rule instanceof ClientAware) {
48
                $rule->setClient($client);
49
            }
50
        }
51
    }
52
53
    public function scan()
54
    {
55
        $this->eventDispatcher->simpleNotify('Scanner.Scan.Begin');
56
57
        while (($response = $this->responseRetriever->next()) && !$this->eventDispatcher->notifyUntil(new Event('Scanner.Scan.isStopped'))) {
58
59
            // this is the url filter
60
            if ($this->eventDispatcher->notifyUntil(new Event('Scanner.ProcessHtml.isFiltered', array('uri' => $response->getUri())))) {
61
                continue;
62
            }
63
64
            $results = $this->checkResponse($response);
65
66
            if(count($results) == 0) {
67
                $checkResult = new CheckResult(CheckResult::STATUS_NONE, '');
68
                $checkResult->setResponse($response);
69
                $results = [$checkResult];
70
            }
71
72
            $this->eventDispatcher->simpleNotify('Scanner.Scan.Validate', array('results' => $results, 'response' => $response));
73
        }
74
75
        $this->eventDispatcher->simpleNotify('Scanner.Scan.Finish');
76
    }
77
78
    public function getStatus()
79
    {
80
        return $this->status;
81
    }
82
83
    private function checkResponse(Response $response)
84
    {
85
        $results = [];
86
87
        foreach ($this->rules as $name => $rule) {
88
            if ($this->eventDispatcher->notifyUntil(new Event('Scanner.CheckResponse.isFiltered', array('ruleName' => $name, 'rule' => $rule, 'response' => $response)))) {
89
                continue;
90
            }
91
            try {
92
                $result = $rule->validate($response);
93
                if (!$result) {
94
                    $result = new CheckResult(CheckResult::STATUS_SUCCESS, 'Check successful.');
95
                }
96
            } catch (ValidationFailedException $e) {
97
                $result = new CheckResult(CheckResult::STATUS_FAILURE, $e->getMessage());
98
            }
99
            $result->setResponse($response);
100
            $result->setRuleName($name);
101
            $results[$name] = $result;
102
        }
103
104
        return $results;
105
    }
106
}
107