-
Notifications
You must be signed in to change notification settings - Fork 0
/
http-client.js
177 lines (139 loc) · 6.23 KB
/
http-client.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/***********************************************************************************
Abstractor | HTTP Client | MIT License | ©2016 Hexagon <github.com/hexagon>
Gets the response code, body and response headers from an url.
Does follow redirects.
----------------------------------------------------------------------------
Options
-----------------+-----------------+----------------------+-----------------
Option | Type | Default | Mandatory
-----------------+-----------------+----------------------+-----------------
method | string | "GET" | yes
url | string | undefined | no
data | object | undefined | no
-----------------+-----------------+----------------------+-----------------
I/O
-------------------------------+----------------------+---------------------
Input | Possible triggers | Sets parameter
-------------------------------+----------------------+---------------------
| | payload
| success | redirects
GET: <any message> | | response
POST: payload: <object> | | statusCode
+----------------------+---------------------
| error | error
-------------------------------+----------------------+---------------------
***********************************************************************************/
"use strict";
const
Node = require("../node.js"),
http = require("http"),
https = require("https"),
url = require("url");
class HTTP extends Node {
constructor(parameters) {
var defaults = {
timeout: 600000,
headers: {},
method: "GET"
};
super(parameters, defaults);
}
invoke(msg) {
var self = this,
// Mandatory options
method = this.getConfig("method", msg, true),
// Optinal options, defaults are append, read/write permissions to all and utf8 encoding
headers = this.getConfig("headers", msg, true),
requestedUrl = this.getConfig("url", msg, false) || msg.topic,
data = this.getConfig("data", msg, false),
// Derived options
host,
port,
path,
handler,
options;
// Set up method, overridable by msg.method
if ( msg.method ) {
if( msg.method === "GET" || msg.method == "POST" ) {
method = msg.method;
} else {
return this.error(msg, "Unsupported method requested: " + msg.method + ". Supported options is GET or POST.");
}
}
// Parse url
if ( requestedUrl ) {
let parsedUrl = url.parse( requestedUrl );
// Check for supported protocol
if ( ! ( parsedUrl.protocol == "http:" || parsedUrl.protocol == "https:" ) ) {
this.error(msg, "Unsupported protocol in URL, available protocols are http and https.");
return;
} else {
handler = (parsedUrl.protocol == "http:") ? http : https;
}
//
host = parsedUrl.hostname;
port = parsedUrl.port ? parsedUrl.port : (parsedUrl.protocol == "http:" ? 80 : 443);
path = parsedUrl.path;
} else {
msg.error = "No URL provided, config.url or msg.topic need to contain an URL.";
this.trigger("error", msg);
return;
}
// In case of post, check that data is stringifiable, or undefined
if ( method == "POST") {
data = data || msg.payload;
if ( data === undefined ) {
data = "";
} else if ( msg.payload.toString ) {
data = msg.payload.toString();
} else {
return this.error( msg , "Invalid POST data provided to msg.payload or config.data, must be string or stringifiable.");
}
}
// If headers is supplied in msg.headers, they need to be an object
if ( msg.headers && typeof msg.headers !== "object" ) {
return this.error(msg, "Invalid headers provided, msg.headers must be an javascript object with key/value pairs.");
} else if ( msg.headers ) {
headers = msg.headers;
}
// All should be ok by now
options = { host, path, port, method, headers };
// Set up request
var req = handler.request(options, function(response) {
let data = [];
response.on("data", (chunk) => { data.push(chunk); });
response.on("end", () => {
// Follow redirect?
if ( response.statusCode == 301 || response.statusCode == 302 ) {
if ( msg.redirects === undefined ) {
msg.redirects = 0;
}
msg.redirects++;
if ( msg.redirects > 5 ) {
// Uh oh, we seem to be stuck in a redirect loop
return this.error(msg, "HTTP Request got stuck in a redirect loop (>5 redirects), bailing out.");
} else {
// All good, follow redirect!
msg.topic = response.headers.location;
self.invoke(msg);
return;
}
// Ok, next!
} else {
msg.response = response.headers;
msg.statusCode = response.statusCode;
msg.payload = data.join("");
self.trigger("response", msg);
}
});
});
req.on("error", (e) => { self.error(msg, e); });
// Write data in case of POST
if ( method == "POST" ) {
req.write( msg.payload.toString() );
}
// Finalize
req.end();
}
}
module.exports = HTTP;