Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core;
18
 
19
use core\local\guzzle\cache_handler;
20
use core\local\guzzle\cache_storage;
21
use core\local\guzzle\check_request;
22
use core\local\guzzle\redirect_middleware;
23
use GuzzleHttp\Client;
24
use GuzzleHttp\HandlerStack;
25
use GuzzleHttp\RequestOptions;
26
use Kevinrob\GuzzleCache\CacheMiddleware;
27
use Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy;
28
 
29
/**
30
 * Guzzle Integration for Moodle.
31
 *
32
 * @package   core
33
 * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
34
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class http_client extends Client {
37
 
38
    public function __construct(array $config = []) {
39
        $config = $this->get_options($config);
40
 
41
        parent::__construct($config);
42
    }
43
 
44
    /**
45
     * Get the custom options and handlers for guzzle integration in moodle.
46
     *
47
     * @param array $settings The settings or options from client.
48
     * @return array
49
     */
50
    protected function get_options(array $settings): array {
51
        if (empty($settings['handler'])) {
52
            // Configure the default handlers.
53
            $settings['handler'] = $this->get_handlers($settings);
54
        }
55
 
56
        // Request debugging {@link https://docs.guzzlephp.org/en/stable/request-options.html#debug}.
57
        if (!empty($settings[RequestOptions::DEBUG])) {
58
            // Accepts either a bool, or fopen resource.
59
            if (!is_resource($settings[RequestOptions::DEBUG])) {
60
                $settings[RequestOptions::DEBUG] = !empty($settings['debug']);
61
            }
62
        }
63
 
64
        // Proxy.
65
        $proxy = $this->setup_proxy($settings);
66
        if (!empty($proxy)) {
67
            $settings[RequestOptions::PROXY] = $proxy;
68
        }
69
 
70
        // Add the default user-agent header.
71
        if (!isset($settings['headers'])) {
72
            $settings['headers'] = ['User-Agent' => \core_useragent::get_moodlebot_useragent()];
73
        } else if (is_array($settings['headers'])) {
74
            $headers = array_keys(array_change_key_case($settings['headers']));
75
            // Add the User-Agent header if one was not already set.
76
            if (!in_array('user-agent', $headers)) {
77
                $settings['headers']['User-Agent'] = \core_useragent::get_moodlebot_useragent();
78
            }
79
        }
80
 
81
        return $settings;
82
    }
83
 
84
    /**
85
     * Get the handler stack according to the settings/options from client.
86
     *
87
     * @param array $settings The settings or options from client.
88
     * @return HandlerStack
89
     */
90
    protected function get_handlers(array $settings): HandlerStack {
91
        global $CFG;
92
        // If a mock handler is set, add to stack. Mainly used for tests.
93
        if (isset($settings['mock'])) {
94
            $stack = HandlerStack::create($settings['mock']);
95
        } else {
96
            $stack = HandlerStack::create();
97
        }
98
 
99
        // Ensure that the first piece of middleware checks the block list.
100
        $stack->unshift(check_request::setup($settings), 'moodle_check_initial_request');
101
 
102
        // Replace the standard redirect handler with our custom Moodle one.
103
        // This handler checks the block list.
104
        // It extends the standard 'allow_redirects' handler so supports the same options.
105
        $stack->after('allow_redirects', redirect_middleware::setup($settings), 'moodle_allow_redirect');
106
        $stack->remove('allow_redirects');
107
 
108
        // Use cache middleware if cache is enabled.
109
        if (!empty($settings['cache'])) {
110
            $module = 'misc';
111
            if (!empty($settings['module_cache'])) {
112
                $module = $settings['module_cache'];
113
            }
114
 
115
            // Set TTL for the cache.
116
            if ($module === 'repository') {
117
                if (empty($CFG->repositorycacheexpire)) {
118
                    $CFG->repositorycacheexpire = 120;
119
                }
120
                $ttl = $CFG->repositorycacheexpire;
121
            } else {
122
                if (empty($CFG->curlcache)) {
123
                    $CFG->curlcache = 120;
124
                }
125
                $ttl = $CFG->curlcache;
126
            }
127
 
128
            $stack->push(new CacheMiddleware (new PrivateCacheStrategy (new cache_storage (new cache_handler($module), $ttl))),
129
                    'cache');
130
        }
131
 
132
        return $stack;
133
    }
134
 
135
    /**
136
     * Get the proxy configuration.
137
     *
138
     * @see {https://docs.guzzlephp.org/en/stable/request-options.html#proxy}
139
     * @param array $settings The incoming settings.
140
     * @return array The proxy settings
141
     */
142
    protected function setup_proxy(array $settings): ?array {
143
        global $CFG;
144
 
145
        if (empty($CFG->proxyhost)) {
146
            return null;
147
        }
148
 
149
        $proxy = $this->get_proxy($settings);
150
        $noproxy = [];
151
 
152
        if (!empty($CFG->proxybypass)) {
153
            $noproxy = array_map(function(string $hostname): string {
154
                return trim($hostname);
155
            }, explode(',', $CFG->proxybypass));
156
        }
157
 
158
        return [
159
            'http' => $proxy,
160
            'https' => $proxy,
161
            'no' => $noproxy,
162
        ];
163
    }
164
 
165
    /**
166
     * Get the proxy server identified.
167
     *
168
     * @param array $settings The incoming settings.
169
     * @return string The URI for the Proxy Server
170
     */
171
    protected function get_proxy(array $settings): string {
172
        global $CFG;
173
        $proxyhost = $CFG->proxyhost;
174
        if (!empty($CFG->proxyport)) {
175
            $proxyhost = "{$CFG->proxyhost}:{$CFG->proxyport}";
176
        }
177
 
178
        $proxyauth = "";
179
        if (!empty($CFG->proxyuser) && !empty($CFG->proxypassword)) {
180
            $proxyauth = "{$CFG->proxyuser}{$CFG->proxypassword}";
181
        }
182
 
183
        $protocol = "http://";
184
        if (!empty($CFG->proxytype) && $CFG->proxytype === 'SOCKS5') {
185
            $protocol = "socks5://";
186
        }
187
 
188
        return "{$protocol}{$proxyauth}{$proxyhost}";
189
    }
190
}