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

funilrys / PyFunceble / 3791943222

pending completion
3791943222

push

github-actions

funilrys
Introduction of the imgur.com SPECIAL rule.

1 of 16 new or added lines in 1 file covered. (6.25%)

11095 of 11528 relevant lines covered (96.24%)

14.41 hits per line

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

26.09
/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:
×
NEW
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

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

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

NEW
267
        for response in req.history:
×
NEW
268
            if "Location" in req.response:
×
NEW
269
                if req.headers["Location"].endswith(("/removed.png")):
×
NEW
270
                    self.switch_to_down()
×
271

NEW
272
                if response.status_code in [404] and response.url.endswith(
×
273
                    f"/user/{username}"
274
                ):
NEW
275
                    self.switch_to_down()
×
276

NEW
277
        if req.url.endswith(f"/user/{username}"):
×
NEW
278
            self.switch_to_down()
×
279

NEW
280
        return self
×
281

282
    def __handle_active2inactive(self) -> "ExtraRulesHandler":
15✔
283
        """
284
        Handles the status deescalation.
285
        """
286

287
        if self.status.http_status_code:
×
288
            self.__regex_registry_handler(self.regex_active2inactive)
×
289

290
        return self
×
291

292
    @ExtraRuleHandlerBase.ensure_status_is_given
15✔
293
    @ExtraRuleHandlerBase.setup_status_before
15✔
294
    @ExtraRuleHandlerBase.setup_status_after
15✔
295
    def start(self) -> "ExtraRulesHandler":
15✔
296
        """
297
        Starts the process.
298
        """
299

300
        PyFunceble.facility.Logger.info(
301
            "Started to check %r against our own set of extra rules.",
302
            self.status.idna_subject,
303
        )
304

305
        if self.status.status_before_extra_rules == PyFunceble.storage.STATUS.up:
×
306
            self.__handle_active2inactive()
×
307

308
        if (
×
309
            not self.status.status_after_extra_rules
310
            and self.status.status_before_extra_rules in PyFunceble.storage.STATUS.down
311
        ):
312
            if self.status.ipv4_range_syntax or self.status.ipv6_range_syntax:
×
313
                self.switch_to_up()
×
314

315
        PyFunceble.facility.Logger.info(
316
            "Finished to check %r against our own set of extra rules.",
317
            self.status.idna_subject,
318
        )
319

320
        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

© 2026 Coveralls, Inc