BrowserMob   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 307
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 0
Metric Value
wmc 37
lcom 2
cbo 6
dl 0
loc 307
rs 9.44
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A _initialize() 0 18 4
A __pingProxy() 0 10 2
C __setProxyCapabilities() 0 39 13
A getProxyPort() 0 4 1
A setProxyPort() 0 6 1
A openProxy() 0 9 2
A closeProxy() 0 4 1
A startHar() 0 5 1
A addPage() 0 5 1
A getHar() 0 4 1
A setHeaders() 0 5 1
A redirectUrl() 0 5 1
A filterRequest() 0 5 1
A filterResponse() 0 5 1
B __call() 0 26 6
1
<?php
2
namespace Codeception\Extension;
3
4
use Codeception\Module;
5
use Codeception\Exception\ModuleException;
6
use Codeception\Exception\ModuleConfigException;
7
use \PHPBrowserMobProxy_Client as BMP;
8
use \Requests;
9
use \RuntimeException;
10
11
/**
12
 * @method void _open() Open a new proxy using the PHPBrowserMobProxy_Client method
13
 * @method void _close() Close current proxy using the PHPBrowserMobProxy_Client method
14
 * @method \Requests_Response _newHar(string $label='') Start new HAR using the PHPBrowserMobProxy_Client method
15
 * @method \Requests_Response _newPage(string $label='') Start new HAR page using the PHPBrowserMobProxy_Client method
16
 * @method \Requests_Response _blacklist(string $regexp, integer $status_code) Blacklist URLs using the PHPBrowserMobProxy_Client method
17
 * @method \Requests_Response _whitelist(string $regexp, integer $status_code) Whitelist URLs using the PHPBrowserMobProxy_Client method
18
 * @method \Requests_Response _basicAuth(string $domain, string[] $options) Set HTTP authentication headers using the PHPBrowserMobProxy_Client method
19
 * @method \Requests_Response _headers(string[] $options) Override requests HTTP headers using the PHPBrowserMobProxy_Client method
20
 * @method \Requests_Response _responseInterceptor(string $js) Intercept HTTP responses using the PHPBrowserMobProxy_Client method
21
 * @method \Requests_Response _requestInterceptor(string $js) Intercept HTTP requests using the PHPBrowserMobProxy_Client method
22
 * @method \Requests_Response _limits(string[] $options) Set proxy limits using the PHPBrowserMobProxy_Client method
23
 * @method \Requests_Response _timeouts(string[] $options) Set proxy timeouts using the PHPBrowserMobProxy_Client method
24
 * @method \Requests_Response _remapHosts(string $address, string $ip_address) Map hosts to IP using the PHPBrowserMobProxy_Client method
25
 * @method \Requests_Response _waitForTrafficToStop(integer $quiet_period, integer $timeout) Wait for traffic before stopping proxy using the PHPBrowserMobProxy_Client method
26
 * @method \Requests_Response _clearDnsCache() Flux proxy DNS cache using the PHPBrowserMobProxy_Client method
27
 * @method \Requests_Response _rewriteUrl(string $match, string $replace) Rewrite URLs using the PHPBrowserMobProxy_Client method
28
 * @method \Requests_Response _retry(integer $retry_count) Set proxy retries using the PHPBrowserMobProxy_Client method
29
 */
30
class BrowserMob extends Module
31
{
32
33
    /**
34
     * @var string[] $config
35
     */
36
    protected $config = ['host', 'port', 'autostart', 'blacklist', 'whitelist', 'limits', 'timeouts', 'dns', 'retry', 'basicAuth', 'littleproxy'];
37
38
    /**
39
     * @var string[] $requiredFields
40
     */
41
    protected $requiredFields = ['host', 'port'];
42
43
    /**
44
     * @var Requests $response
45
     */
46
    protected $response;
47
48
    /**
49
     * @var PHPBrowserMobProxy_Client $bmp
50
     */
51
    private $bmp;
52
53
    /**
54
     * @codeCoverageIgnore
55
     * @ignore Codeception specific
56
     */
57
    public function _initialize()
58
    {
59
        $host = $this->config['host'].':'.$this->config['port'];
60
61
        // test if proxy is available
62
        if (static::__pingProxy($host)) {
63
            $this->bmp = new BMP($host);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \PHPBrowserMobProxy_Client($host) of type object<PHPBrowserMobProxy_Client> is incompatible with the declared type object<Codeception\Exten...BrowserMobProxy_Client> of property $bmp.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
64
        } else {
65
            throw new ModuleConfigException(__CLASS__, "Proxy '{$host}' cannot be reached");
66
        }
67
68
        // start a new BrowserMobProxy session
69
        if (isset($this->config['autostart'])) {
70
            if (true === (bool) $this->config['autostart']) {
71
                $this->openProxy();
72
            }
73
        }
74
    }
75
76
    /**
77
     * Verify if the BrowserMobProxy is reachable
78
     *
79
     * @param string $host BrowserMob Proxy host, format host:port
80
     *
81
     * @return boolean Returns true if proxy available, else false
82
     */
83
    protected static function __pingProxy($host)
84
    {
85
        try {
86
            $response = Requests::get('http://'.$host.'/proxy/');
87
        } catch (\Exception $e) {
88
            throw new ModuleException(__CLASS__, $e->getMessage());
89
        }
90
91
        return $response->success;
92
    }
93
94
    /**
95
     * Set proxy capabilitites: blacklist, whitelist, limits, timeouts, dns, retry, basicAuth
96
     *
97
     * @uses BrowserMob::_blacklist
98
     * @uses BrowserMob::_whitelist
99
     * @uses BrowserMob::_limits
100
     * @uses BrowserMob::_timeouts
101
     * @uses BrowserMob::_remapHosts
102
     * @uses BrowserMob::_retry
103
     * @uses BrowserMob::_basicAuth
104
     *
105
     * @param mixed[] $options Array of options (see extension configuration)
106
     *
107
     * @return void
108
     */
109
    protected function __setProxyCapabilities($options)
110
    {
111
        foreach ($options as $config => $data) {
112
            if (false === empty($data)) {
113
                switch ((string) $config) {
114
                    case 'blacklist':
115
                        foreach ($data['patterns'] as $pattern) {
116
                            $this->_blacklist($pattern, $data['code']);
117
                        }
118
                        break;
119
                    case 'whitelist':
120
                        $patterns = implode(',', $data['patterns']);
121
                        $this->_whitelist($patterns, $data['code']);
122
                        break;
123
                    case 'limits':
124
                        $this->_limits($data);
125
                        break;
126
                    case 'timeouts':
127
                        $this->_timeouts($data);
128
                        break;
129
                    case 'dns':
130
                        foreach ($data as $entry) {
131
                            $this->_remapHosts($entry['domain'], $entry['ip']);
132
                        }
133
                        break;
134
                    case 'retry':
135
                        $this->_retry($data);
136
                        break;
137
                    case 'basicAuth':
138
                        foreach ($data as $entry) {
139
                            $this->_basicAuth($entry['domain'], $entry['options']);
140
                        }
141
                        break;
142
                    default:
143
                        // do nothing
144
                }
145
            }
146
        }
147
    }
148
149
    /**
150
     * Return current proxy port opened on BrowserMobProxy
151
     *
152
     * @return integer Proxy port
153
     */
154
    public function getProxyPort()
155
    {
156
        return $this->bmp->port;
157
    }
158
159
    /**
160
     * Set current proxy port to use on BrowserMobProxy
161
     *
162
     * @param integer $port Proxy port
163
     */
164
    public function setProxyPort($port)
165
    {
166
        $prop = new \ReflectionProperty($this->bmp, 'port');
167
        $prop->setAccessible(true);
168
        $prop->setValue($this->bmp, $port);
169
    }
170
171
    /**
172
     * Open a new proxy on BrowserMobProxy
173
     *
174
     * @see BrowserMob::__setProxyCapabilities
175
     *
176
     * @uses BrowserMob::_open
177
     * @uses BrowserMob::__setProxyCapabilities
178
     * @uses BrowserMob::getProxyPort
179
     *
180
     * @param mixed[]|null $capabilities Array of capabilities. Use extension configuration if null
181
     *
182
     * @return integer Proxy port
183
     */
184
    public function openProxy($capabilities = null)
185
    {
186
        $this->_open();
187
        if (empty($capabilities)) {
188
            $capabilities = $this->config;
189
        }
190
        $this->__setProxyCapabilities($capabilities);
191
        return $this->getProxyPort();
192
    }
193
194
    /**
195
     * Close the current proxy opened BrowserMobProxy
196
     * Not supported by library chartjes/php-browsermob-proxy
197
     *
198
     * @uses BrowserMob::_close
199
     *
200
     * @return void
201
     */
202
    public function closeProxy()
203
    {
204
        $this->_close();
205
    }
206
207
    /**
208
     * Start to capture the HTTP archive
209
     *
210
     * @uses BrowserMob::_newHar
211
     *
212
     * @param string|null $label Title of first HAR page
213
     *
214
     * @return boolean Command status
215
     */
216
    public function startHar($label = '')
217
    {
218
        $this->_newHar($label);
219
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
220
    }
221
222
    /**
223
     * Add a new page to the HTTP archive
224
     *
225
     * @uses BrowserMob::_newPage
226
     *
227
     * @param string|null $label Title of new HAR page
228
     *
229
     * @return boolean Command status
230
     */
231
    public function addPage($label = '')
232
    {
233
        $this->_newPage($label);
234
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
235
    }
236
237
    /**
238
     * Get the HTTP archive captured
239
     *
240
     * @return mixed[] HTTP archive
241
     */
242
    public function getHar()
243
    {
244
        return $this->bmp->har;
245
    }
246
247
    /**
248
     * Override HTTP request headers
249
     *
250
     * @uses BrowserMob::_headers
251
     *
252
     * @param string[] $headers Array of HTTP headers
253
     *
254
     * @return boolean Command status
255
     */
256
    public function setHeaders($headers)
257
    {
258
        $this->_headers($headers);
259
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
260
    }
261
262
    /**
263
     * Rewrite URLs with regex
264
     *
265
     * @uses BrowserMob::_rewriteUrl
266
     *
267
     * @param string $match Matching URL regular expression
268
     * @param string $replace Replacement URL
269
     *
270
     * @return boolean Command status
271
     */
272
    public function redirectUrl($match, $replace)
273
    {
274
        $this->_rewriteUrl($match, $replace);
275
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
276
    }
277
278
    /**
279
     * Run Javascript against requests before sending them
280
     *
281
     * @param string $script Javascript code
282
     *
283
     * @return boolean Command status
284
     */
285
    public function filterRequest($script)
286
    {
287
        $this->_requestInterceptor($script);
288
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
289
    }
290
291
    /**
292
     * Run Javascript against responses received
293
     *
294
     * @param string $script Javascript code
295
     *
296
     * @return boolean Command status
297
     */
298
    public function filterResponse($script)
299
    {
300
        $this->_responseInterceptor($script);
301
        return $this->response->success;
0 ignored issues
show
Bug introduced by
The property success does not seem to exist in Requests.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
302
    }
303
304
    /**
305
     * Magic function that exposes BrowserMobProxy API pulic methods
306
     *
307
     * @ignore Exclude from documentation
308
     */
309
    public function __call($name, $args)
310
    {
311
        // check if is a command call
312
        if (preg_match('/^_[A-z]+$/', $name)) {
313
            // extract standard method name
314
            $name = preg_filter('/_/', '', $name);
315
            // set call array for calling method
316
            $call = array($this->bmp, $name);
317
            // check if method is callable
318
            if (is_callable($call)) {
319
                $ret = call_user_func_array($call, $args);
320
                if (get_class($ret) === 'Requests_Response') {
321
                    $this->response = $ret;
0 ignored issues
show
Documentation Bug introduced by
It seems like $ret of type object<Requests_Response> is incompatible with the declared type object<Requests> of property $response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
322
                    if (false === $ret->success) {
323
                        throw new ModuleConfigException(__CLASS__, "Proxy response error '{$ret->status_code}' {$ret->body}");
324
                    }
325
                }
326
            } else {
327
                throw new RuntimeException("Method ${name} does not exist or is not callable");
328
            }
329
        } else {
330
            throw new RuntimeException("Method ${method} does not exist or is not callable");
331
        }
332
        $ret = (isset($ret)) ? $ret : null;
333
        return $ret;
334
    }
335
336
}
337