forked from codemanki/cloudscraper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.js
145 lines (121 loc) · 4.55 KB
/
errors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
'use strict';
// The purpose of this library:
// 1. Have errors consistent with request/promise-core
// 2. Prevent request/promise core from wrapping our errors
// 3. Create descriptive errors.
// There are two differences between these errors and the originals.
// 1. There is a non-enumerable errorType attribute.
// 2. The error constructor is hidden from the stacktrace.
const EOL = require('os').EOL;
const original = require('request-promise-core/errors');
const http = require('http');
const BUG_REPORT = format([
'### Cloudflare may have changed their technique, or there may be a bug.',
'### Bug Reports: https://github.com/codemanki/cloudscraper/issues',
'### Check the detailed exception message that follows for the cause.'
]);
const ERROR_CODES = {
// Non-standard 5xx server error HTTP status codes
520: 'Web server is returning an unknown error',
521: 'Web server is down',
522: 'Connection timed out',
523: 'Origin is unreachable',
524: 'A timeout occurred',
525: 'SSL handshake failed',
526: 'Invalid SSL certificate',
527: 'Railgun Listener to Origin Error',
530: 'Origin DNS error',
// Other codes
1000: 'DNS points to prohibited IP',
1001: 'DNS resolution error',
1002: 'Restricted or DNS points to Prohibited IP',
1003: 'Access Denied: Direct IP Access Not Allowed',
1004: 'Host Not Configured to Serve Web Traffic',
1005: 'Access Denied: IP of banned ASN/ISP',
1010: 'The owner of this website has banned your access based on your browser\'s signature',
1011: 'Access Denied (Hotlinking Denied)',
1012: 'Access Denied',
1013: 'HTTP hostname and TLS SNI hostname mismatch',
1016: 'Origin DNS error',
1018: 'Domain is misconfigured',
1020: 'Access Denied (Custom Firewall Rules)'
};
ERROR_CODES[1006] =
ERROR_CODES[1007] =
ERROR_CODES[1008] = 'Access Denied: Your IP address has been banned';
const OriginalError = original.RequestError;
const RequestError = create('RequestError', 0);
const CaptchaError = create('CaptchaError', 1);
// errorType 4 is a CloudflareError so this constructor is reused.
const CloudflareError = create('CloudflareError', 2, function (error) {
if (!isNaN(error.cause)) {
const description = ERROR_CODES[error.cause] || http.STATUS_CODES[error.cause];
if (description) {
error.message = error.cause + ', ' + description;
}
}
});
const ParserError = create('ParserError', 3, function (error) {
error.message = BUG_REPORT + error.message;
});
// The following errors originate from promise-core and it's dependents.
// Give them an errorType for consistency.
original.StatusCodeError.prototype.errorType = 5;
original.TransformError.prototype.errorType = 6;
// This replaces the RequestError for all libraries using request/promise-core
// and prevents silent failure.
Object.defineProperty(original, 'RequestError', {
configurable: true,
enumerable: true,
writable: true,
value: RequestError
});
// Export our custom errors along with StatusCodeError, etc.
Object.assign(module.exports, original, {
RequestError: RequestError,
CaptchaError: CaptchaError,
ParserError: ParserError,
CloudflareError: CloudflareError
});
const desc = { configurable: true, writable: true, enumerable: false };
const descriptors = {
error: desc,
cause: desc,
response: desc,
options: desc
};
function create (name, errorType, customize) {
function CustomError (cause, options, response) {
// This prevents nasty things e.g. `error.cause.error` and
// is why replacing the original RequestError is necessary.
if (cause instanceof OriginalError) {
return cause;
}
// Cleanup error output
Object.defineProperties(this, descriptors);
OriginalError.apply(this, arguments);
// Change the name to match this constructor
this.name = name;
if (typeof customize === 'function') {
customize(this);
}
if (Error.captureStackTrace) { // required for non-V8 environments
// Provide a proper stack trace that hides this constructor
Error.captureStackTrace(this, CustomError);
}
}
CustomError.prototype = Object.create(OriginalError.prototype);
CustomError.prototype.constructor = CustomError;
// Keeps things stealthy by defining errorType on the prototype.
// This makes it non-enumerable and safer to add.
CustomError.prototype.errorType = errorType;
Object.setPrototypeOf(CustomError, Object.getPrototypeOf(OriginalError));
Object.defineProperty(CustomError, 'name', {
configurable: true,
value: name
});
return CustomError;
}
function format (lines) {
return EOL + lines.join(EOL) + EOL + EOL;
}