• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

funilrys / PyFunceble / 3866429906

pending completion
3866429906

push

github-actions

funilrys
fixup! Introduction of the support for postgresql DBs.

11160 of 11683 relevant lines covered (95.52%)

14.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

27.59
/PyFunceble/checker/availability/extras/rules.py
1
"""
2
The tool to check the availability or syntax of domain, IP or URL.
3

4
::
5

6

7
    ██████╗ ██╗   ██╗███████╗██╗   ██╗███╗   ██╗ ██████╗███████╗██████╗ ██╗     ███████╗
8
    ██╔══██╗╚██╗ ██╔╝██╔════╝██║   ██║████╗  ██║██╔════╝██╔════╝██╔══██╗██║     ██╔════╝
9
    ██████╔╝ ╚████╔╝ █████╗  ██║   ██║██╔██╗ ██║██║     █████╗  ██████╔╝██║     █████╗
10
    ██╔═══╝   ╚██╔╝  ██╔══╝  ██║   ██║██║╚██╗██║██║     ██╔══╝  ██╔══██╗██║     ██╔══╝
11
    ██║        ██║   ██║     ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
12
    ╚═╝        ╚═╝   ╚═╝      ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝
13

14
Provides the extra rules handler based on the status code.
15

16
Author:
17
    Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom
18

19
Special thanks:
20
    https://pyfunceble.github.io/#/special-thanks
21

22
Contributors:
23
    https://pyfunceble.github.io/#/contributors
24

25
Project link:
26
    https://github.com/funilrys/PyFunceble
27

28
Project documentation:
29
    https://pyfunceble.readthedocs.io/en/dev/
30

31
Project homepage:
32
    https://pyfunceble.github.io/
33

34
License:
35
::
36

37

38
    Copyright 2017, 2018, 2019, 2020, 2022 Nissar Chababy
39

40
    Licensed under the Apache License, Version 2.0 (the "License");
41
    you may not use this file except in compliance with the License.
42
    You may obtain a copy of the License at
43

44
        http://www.apache.org/licenses/LICENSE-2.0
45

46
    Unless required by applicable law or agreed to in writing, software
47
    distributed under the License is distributed on an "AS IS" BASIS,
48
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49
    See the License for the specific language governing permissions and
50
    limitations under the License.
51
"""
52

53
import socket
15✔
54
from typing import Callable, List, Optional
15✔
55

56
from box import Box
15✔
57

58
import PyFunceble.facility
15✔
59
import PyFunceble.factory
15✔
60
import PyFunceble.storage
15✔
61
from PyFunceble.checker.availability.extras.base import ExtraRuleHandlerBase
15✔
62
from PyFunceble.checker.availability.status import AvailabilityCheckerStatus
15✔
63
from PyFunceble.helpers.regex import RegexHelper
15✔
64

65

66
class ExtraRulesHandler(ExtraRuleHandlerBase):
15✔
67
    """
68
    Provides our very own extra rules handler.
69

70
    :param status:
71
        The previously gathered status.
72
    :type status:
73
        :class:`~PyFunceble.checker.availability.status.AvailabilityCheckerStatus`
74
    """
75

76
    regex_active2inactive: dict = {}
15✔
77
    http_codes_dataset: Optional[Box] = None
15✔
78

79
    def __init__(self, status: Optional[AvailabilityCheckerStatus] = None) -> None:
80

81
        self.regex_active2inactive = {
82
            r"\.000webhostapp\.com": [
83
                (self.__switch_to_down_if, 410),
84
            ],
85
            r"\.24\.eu$": [(self.__switch_to_down_if, 503)],
86
            r"\.altervista\.org$": [(self.__switch_to_down_if, 403)],
87
            r"\.angelfire\.com$": [(self.__switch_to_down_if, 404)],
88
            r"\.blogspot\.": [self.__handle_blogspot],
89
            r"\.canalblog\.com$": [(self.__switch_to_down_if, 404)],
90
            r"\.dr\.ag$": [(self.__switch_to_down_if, 503)],
91
            r"\.fc2\.com$": [self.__handle_fc2_dot_com],
92
            r"\.github\.io$": [(self.__switch_to_down_if, 404)],
93
            r"\.godaddysites\.com$": [(self.__switch_to_down_if, 404)],
94
            r"\.hpg.com.br$": [(self.__switch_to_down_if, 404)],
95
            r"\.imgur\.com$": [self.__handle_imgur_dot_com],
96
            r"\.liveadvert\.com$": [(self.__switch_to_down_if, 404)],
97
            r"\.skyrock\.com$": [(self.__switch_to_down_if, 404)],
98
            r"\.tumblr\.com$": [(self.__switch_to_down_if, 404)],
99
            r"\.wix\.com$": [(self.__switch_to_down_if, 404)],
100
            r"\.wordpress\.com$": [
101
                (self.__switch_to_down_if, 410),
102
                self.__handle_wordpress_dot_com,
103
            ],
104
            r"\.weebly\.com$": [(self.__switch_to_down_if, 404)],
105
        }
106

107
        if PyFunceble.facility.ConfigLoader.is_already_loaded():
108
            self.http_codes_dataset = PyFunceble.storage.HTTP_CODES
109
        else:
110
            self.http_codes_dataset = PyFunceble.storage.STD_HTTP_CODES
111

112
        super().__init__(status)
113

114
    def __web_regex_handler(
15✔
115
        self,
116
        url: str,
117
        regex_list: List[str],
118
        method: Callable[..., "ExtraRulesHandler"],
119
    ) -> "ExtraRulesHandler":
120
        """
121
        Handles a web request along with a regex filter.
122
        """
123

124
        try:
×
125
            req = PyFunceble.factory.Requester.get(url, allow_redirects=True)
×
126

127
            for regex in regex_list:
×
128
                if regex in req.text or RegexHelper(regex).match(
×
129
                    req.text, return_match=False
130
                ):
131
                    method()
×
132
                    break
×
133
        except (
×
134
            PyFunceble.factory.Requester.exceptions.RequestException,
135
            PyFunceble.factory.Requester.exceptions.InvalidURL,
136
            PyFunceble.factory.Requester.exceptions.Timeout,
137
            PyFunceble.factory.Requester.exceptions.ConnectionError,
138
            PyFunceble.factory.Requester.urllib3_exceptions.InvalidHeader,
139
            socket.timeout,
140
        ):
141
            pass
×
142

143
        return self
×
144

145
    def __regex_registry_handler(self, regex_registry: dict) -> "ExtraRulesHandler":
15✔
146
        """
147
        Handles the standard regex lookup case.
148
        """
149

150
        for (
×
151
            regex,
152
            data,
153
        ) in regex_registry.items():
154
            broken = False
×
155
            for element in data:
×
156
                if not RegexHelper(regex).match(self.status.netloc, return_match=False):
×
157
                    continue
×
158

159
                if isinstance(element, tuple):
×
160
                    element[0](*element[1:])
×
161
                else:
162
                    element()
×
163

164
                if self.status.status_after_extra_rules:
×
165
                    broken = True
×
166
                    break
×
167

168
            if broken:
×
169
                break
×
170

171
        return self
×
172

173
    def __switch_to_down_if(self, status_code: int) -> "ExtraRulesHandler":
15✔
174
        """
175
        Switches the status to inactive if the status code is matching the
176
        given one.
177
        """
178

179
        if self.status.http_status_code == status_code:
×
180
            self.switch_to_down()
×
181

182
        return self
×
183

184
    def __handle_blogspot(self) -> "ExtraRulesHandler":
15✔
185
        """
186
        Handles the :code:`blogspot.*` case.
187

188
        .. warning::
189
            This method assume that we know that we are handling a blogspot domain.
190
        """
191

192
        regex_blogger = [r"create-blog.g?", r"87065", r"doesn’t exist"]
×
193

194
        if self.status.idna_subject.startswith(
×
195
            "http:"
196
        ) or self.status.idna_subject.startswith("https://"):
197
            url = self.status.idna_subject
×
198
        else:
199
            url = f"http://{self.status.idna_subject}:80"
×
200

201
        self.__web_regex_handler(url, regex_blogger, self.switch_to_down)
×
202

203
        return self
×
204

205
    def __handle_wordpress_dot_com(self) -> "ExtraRulesHandler":
15✔
206
        """
207
        Handles the :code:`wordpress.com` case.
208

209
        .. warning::
210
            This method assume that we know that we are handling a blogspot domain.
211
        """
212

213
        regex_wordpress = [r"doesn’t exist", r"no\slonger\savailable"]
×
214

215
        if self.status.idna_subject.startswith(
×
216
            "http:"
217
        ) or self.status.idna_subject.startswith("https://"):
218
            url = self.status.idna_subject
×
219
        else:
220
            url = f"http://{self.status.idna_subject}:80"
×
221

222
        self.__web_regex_handler(url, regex_wordpress, self.switch_to_down)
×
223

224
        return self
×
225

226
    def __handle_fc2_dot_com(self) -> "ExtraRulesHandler":
15✔
227
        """
228
        Handles the :code:`fc2.com` case.
229

230
        .. warning::
231
            This method assume that we know that we are handling a fc2 domain.
232
        """
233

234
        if self.status.idna_subject.startswith(
×
235
            "http:"
236
        ) or self.status.idna_subject.startswith("https://"):
237
            url = self.status.idna_subject
×
238
        else:
239
            url = f"http://{self.status.idna_subject}:80"
×
240

241
        req = PyFunceble.factory.Requester.get(url, allow_redirects=False)
×
242

243
        if "Location" in req.headers and "error.fc2.com" in req.headers["Location"]:
×
244
            self.switch_to_down()
×
245

246
        return self
×
247

248
    def __handle_imgur_dot_com(self) -> "ExtraRulesHandler":
15✔
249
        """
250
        Handles the :code:`imgur.com` case.
251

252
        .. warning:.
253
            This method assume that we know that we are handling a imgur.com
254
            sub-domain.
255
        """
256

257
        if self.status.idna_subject.startswith(
×
258
            "http:"
259
        ) or self.status.idna_subject.startswith("https://"):
260
            url = self.status.idna_subject
×
261
        else:
262
            url = f"https://{self.status.idna_subject}"
×
263

264
        req = PyFunceble.factory.Requester.get(url, allow_redirects=False)
×
265
        username = self.status.netloc.replace(".imgur.com", "")
×
266

267
        if "Location" in req.headers:
×
268
            if req.headers["Location"].endswith(("/removed.png", f"/user/{username}")):
×
269
                self.switch_to_down()
×
270

271
        return self
×
272

273
    def __handle_active2inactive(self) -> "ExtraRulesHandler":
15✔
274
        """
275
        Handles the status deescalation.
276
        """
277

278
        if self.status.http_status_code:
×
279
            self.__regex_registry_handler(self.regex_active2inactive)
×
280

281
        return self
×
282

283
    @ExtraRuleHandlerBase.ensure_status_is_given
15✔
284
    @ExtraRuleHandlerBase.setup_status_before
15✔
285
    @ExtraRuleHandlerBase.setup_status_after
15✔
286
    def start(self) -> "ExtraRulesHandler":
15✔
287
        """
288
        Starts the process.
289
        """
290

291
        PyFunceble.facility.Logger.info(
292
            "Started to check %r against our own set of extra rules.",
293
            self.status.idna_subject,
294
        )
295

296
        if self.status.status_before_extra_rules == PyFunceble.storage.STATUS.up:
×
297
            self.__handle_active2inactive()
×
298

299
        if (
×
300
            not self.status.status_after_extra_rules
301
            and self.status.status_before_extra_rules in PyFunceble.storage.STATUS.down
302
        ):
303
            if self.status.ipv4_range_syntax or self.status.ipv6_range_syntax:
×
304
                self.switch_to_up()
×
305

306
        PyFunceble.facility.Logger.info(
307
            "Finished to check %r against our own set of extra rules.",
308
            self.status.idna_subject,
309
        )
310

311
        return self
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc