Passed
Push — master ( 991b71...894585 )
by Fabian
02:23
created

Connector::delayResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace LE_ACME2\Connector;
4
5
use LE_ACME2\Request;
6
use LE_ACME2\Response;
7
8
use LE_ACME2\SingletonTrait;
9
use LE_ACME2\Cache;
10
use LE_ACME2\Utilities;
11
use LE_ACME2\Exception;
12
13
class Connector {
14
15
    use SingletonTrait;
16
    
17
    const METHOD_GET = 'GET';
18
    const METHOD_HEAD = 'HEAD';
19
    const METHOD_POST = 'POST';
20
21
    private function __construct() {}
22
23
    protected $_baseURL = 		 'https://acme-v02.api.letsencrypt.org';
24
    protected $_stagingBaseURL = 'https://acme-staging-v02.api.letsencrypt.org';
25
26
    protected $_useStagingServer = true;
27
28
    protected $_delayedResponseTime = 0;
29
30
    public function useStagingServer(bool $useStagingServer) {
31
        $this->_useStagingServer = $useStagingServer;
32
    }
33
34
    public function isUsingStagingServer() : bool {
35
        return $this->_useStagingServer;
36
    }
37
38
    public function getBaseURL() : string {
39
        return $this->_useStagingServer ? $this->_stagingBaseURL : $this->_baseURL;
40
    }
41
42
    /**
43
     * Delay the response to prevent bleaching rate limits
44
     *
45
     * @param int $milliSeconds
46
     * @return void
47
     */
48
    public function delayResponse(int $milliSeconds) : void {
49
        $this->_delayedResponseTime = $milliSeconds;
50
    }
51
52
    /**
53
     * Makes a Curl request.
54
     *
55
     * @param string	$method	The HTTP method to use. Accepting GET, POST and HEAD requests.
56
     * @param string 	$url 	The URL to make the request to.
57
     * @param string 	$data  	The body to attach to a POST request. Expected as a JSON encoded string.
58
     *
59
     * @return RawResponse
60
     * @throws Exception\InvalidResponse
61
     * @throws Exception\RateLimitReached
62
     */
63
    public function request(string $method, string $url, string $data = null) : RawResponse {
64
65
        Utilities\Event::getInstance()->trigger(Utilities\Event::EVENT_CONNECTOR_WILL_REQUEST, [
0 ignored issues
show
Bug introduced by
It seems like trigger() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

65
        Utilities\Event::getInstance()->/** @scrutinizer ignore-call */ trigger(Utilities\Event::EVENT_CONNECTOR_WILL_REQUEST, [
Loading history...
66
            'method' => $method,
67
            'url' => $url,
68
            'data' => $data,
69
        ]);
70
        Utilities\Logger::getInstance()->add(Utilities\Logger::LEVEL_INFO, 'will request from ' . $url, ['data' => $data]);
0 ignored issues
show
Bug introduced by
It seems like add() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

70
        Utilities\Logger::getInstance()->/** @scrutinizer ignore-call */ add(Utilities\Logger::LEVEL_INFO, 'will request from ' . $url, ['data' => $data]);
Loading history...
71
72
        $handle = curl_init();
73
74
        $headers = array(
75
            'Accept: application/json',
76
            'Content-Type: ' . ($method == self::METHOD_POST ? 'application/jose+json' : 'application/json') //  ACME draft-10, section 6.2
77
        );
78
79
        curl_setopt($handle, CURLOPT_URL, $url);
80
        curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
81
        curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
82
        curl_setopt($handle, CURLOPT_HEADER, true);
83
84
        switch ($method) {
85
            case self::METHOD_GET:
86
                break;
87
            case self::METHOD_POST:
88
                curl_setopt($handle, CURLOPT_POST, true);
89
                curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
90
                break;
91
            case self::METHOD_HEAD:
92
                curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'HEAD');
93
                curl_setopt($handle, CURLOPT_NOBODY, true);
94
                break;
95
            default:
96
                throw new \RuntimeException('HTTP request ' . $method . ' not supported.');
97
                break;
98
        }
99
        $response = curl_exec($handle);
100
101
        if($this->_delayedResponseTime > 0) {
102
            usleep($this->_delayedResponseTime * 1000);
103
        }
104
105
        if(curl_errno($handle)) {
106
            throw new \RuntimeException('Curl: ' . curl_error($handle));
107
        }
108
109
        $header_size = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
110
111
        $rawResponse = RawResponse::createFrom($method, $url, $response, $header_size);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $response of LE_ACME2\Connector\RawResponse::createFrom() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

111
        $rawResponse = RawResponse::createFrom($method, $url, /** @scrutinizer ignore-type */ $response, $header_size);
Loading history...
112
113
        Utilities\Logger::getInstance()->add(Utilities\Logger::LEVEL_INFO, self::class . ': response received', [get_class($rawResponse) => $rawResponse]);
114
115
        $this->_saveNewNonceFrom($rawResponse, $method);
116
117
        return $rawResponse;
118
    }
119
120
    /**
121
     * @param RawResponse $rawResponse
122
     * @param string $method
123
     * @throws Exception\InvalidResponse
124
     * @throws Exception\RateLimitReached
125
     */
126
    private function _saveNewNonceFrom(RawResponse $rawResponse, string $method) : void {
127
128
        try {
129
            $getNewNonceResponse = new Response\GetNewNonce($rawResponse);
130
            Cache\NewNonceResponse::getInstance()->set($getNewNonceResponse);
0 ignored issues
show
Bug introduced by
It seems like set() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

130
            Cache\NewNonceResponse::getInstance()->/** @scrutinizer ignore-call */ set($getNewNonceResponse);
Loading history...
131
132
        } catch(Exception\InvalidResponse $e) {
133
134
            if($method == self::METHOD_POST) {
135
                $request = new Request\GetNewNonce();
136
                $getNewNonceResponse = $request->getResponse();
137
                Cache\NewNonceResponse::getInstance()->set($getNewNonceResponse);
138
            }
139
        }
140
    }
141
}