[CCSDK-28] populated the seed code for dgbuilder
[ccsdk/distribution.git] / dgbuilder / core_nodes / io / 21-httpin.js
1 /**
2  * Copyright 2013,2014 IBM Corp.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  **/
16
17 module.exports = function(RED) {
18     "use strict";
19     var http = require("follow-redirects").http;
20     var https = require("follow-redirects").https;
21     var urllib = require("url");
22     var express = require("express");
23     var getBody = require('raw-body');
24     var mustache = require("mustache");
25     var querystring = require("querystring");
26
27     var cors = require('cors');
28     var jsonParser = express.json();
29     var urlencParser = express.urlencoded();
30
31     function rawBodyParser(req, res, next) {
32         if (req._body) { return next(); }
33         req.body = "";
34         req._body = true;
35         getBody(req, {
36             limit: '1mb',
37             length: req.headers['content-length'],
38             encoding: 'utf8'
39         }, function (err, buf) {
40             if (err) { return next(err); }
41             req.body = buf;
42             next();
43         });
44     }
45
46
47     function HTTPIn(n) {
48         RED.nodes.createNode(this,n);
49         if (RED.settings.httpNodeRoot !== false) {
50
51             this.url = n.url;
52             this.method = n.method;
53
54             var node = this;
55
56             this.errorHandler = function(err,req,res,next) {
57                 node.warn(err);
58                 res.send(500);
59             };
60
61             this.callback = function(req,res) {
62                 if (node.method == "post") {
63                     node.send({req:req,res:res,payload:req.body});
64                 } else if (node.method == "get") {
65                     node.send({req:req,res:res,payload:req.query});
66                 } else {
67                     node.send({req:req,res:res});
68                 }
69             }
70
71             var corsHandler = function(req,res,next) { next(); }
72
73             if (RED.settings.httpNodeCors) {
74                 corsHandler = cors(RED.settings.httpNodeCors);
75                 RED.httpNode.options(this.url,corsHandler);
76             }
77
78             if (this.method == "get") {
79                 RED.httpNode.get(this.url,corsHandler,this.callback,this.errorHandler);
80             } else if (this.method == "post") {
81                 RED.httpNode.post(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
82             } else if (this.method == "put") {
83                 RED.httpNode.put(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
84             } else if (this.method == "delete") {
85                 RED.httpNode.delete(this.url,corsHandler,this.callback,this.errorHandler);
86             }
87
88             this.on("close",function() {
89                 var routes = RED.httpNode.routes[this.method];
90                 for (var i = 0; i<routes.length; i++) {
91                     if (routes[i].path == this.url) {
92                         routes.splice(i,1);
93                         //break;
94                     }
95                 }
96                 if (RED.settings.httpNodeCors) {
97                     var route = RED.httpNode.route['options'];
98                     for (var j = 0; j<route.length; j++) {
99                         if (route[j].path == this.url) {
100                             route.splice(j,1);
101                             //break;
102                         }
103                     }
104                 }
105             });
106         } else {
107             this.warn("Cannot create http-in node when httpNodeRoot set to false");
108         }
109     }
110     RED.nodes.registerType("http in",HTTPIn);
111
112
113     function HTTPOut(n) {
114         RED.nodes.createNode(this,n);
115         var node = this;
116         this.on("input",function(msg) {
117             if (msg.res) {
118                 if (msg.headers) {
119                     msg.res.set(msg.headers);
120                 }
121                 var statusCode = msg.statusCode || 200;
122                 if (typeof msg.payload == "object" && !Buffer.isBuffer(msg.payload)) {
123                     msg.res.jsonp(statusCode,msg.payload);
124                 } else {
125                     if (msg.res.get('content-length') == null) {
126                         var len;
127                         if (msg.payload == null) {
128                             len = 0;
129                         } else if (typeof msg.payload == "number") {
130                             len = Buffer.byteLength(""+msg.payload);
131                         } else {
132                             len = Buffer.byteLength(msg.payload);
133                         }
134                         msg.res.set('content-length', len);
135                     }
136                     msg.res.send(statusCode,msg.payload);
137                 }
138             } else {
139                 node.warn("No response object");
140             }
141         });
142     }
143     RED.nodes.registerType("http response",HTTPOut);
144
145     function HTTPRequest(n) {
146         RED.nodes.createNode(this,n);
147         var nodeUrl = n.url;
148         var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
149         var nodeMethod = n.method || "GET";
150         var node = this;
151         this.on("input",function(msg) {
152             node.status({fill:"blue",shape:"dot",text:"requesting"});
153             var url;
154             if (msg.url) {
155                 url = msg.url;
156             } else if (isTemplatedUrl) {
157                 url = mustache.render(nodeUrl,msg);
158             } else {
159                 url = nodeUrl;
160             }
161             // url must start http:// or https:// so assume http:// if not set
162             if (!((url.indexOf("http://")===0) || (url.indexOf("https://")===0))) {
163                 url = "http://"+url;
164             }
165
166             var method = (msg.method||nodeMethod).toUpperCase();
167             //node.log(method+" : "+url);
168             var opts = urllib.parse(url);
169             opts.method = method;
170             opts.headers = {};
171             if (msg.headers) {
172                 for (var v in msg.headers) {
173                     if (msg.headers.hasOwnProperty(v)) {
174                         var name = v.toLowerCase();
175                         if (name !== "content-type" && name !== "content-length") {
176                             // only normalise the known headers used later in this
177                             // function. Otherwise leave them alone.
178                             name = v;
179                         }
180                         opts.headers[name] = msg.headers[v];
181                     }
182                 }
183             }
184             if (this.credentials && this.credentials.user) {
185                 opts.auth = this.credentials.user+":"+(this.credentials.password||"");
186             }
187             var payload = null;
188
189             if (msg.payload && (method == "POST" || method == "PUT") ) {
190                 if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
191                     payload = msg.payload;
192                 } else if (typeof msg.payload == "number") {
193                     payload = msg.payload+"";
194                 } else {
195                     if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
196                         payload = querystring.stringify(msg.payload);
197                     } else {
198                         payload = JSON.stringify(msg.payload);
199                         if (opts.headers['content-type'] == null) {
200                             opts.headers['content-type'] = "application/json";
201                         }
202                     }
203                 }
204                 if (opts.headers['content-length'] == null) {
205                     opts.headers['content-length'] = Buffer.byteLength(payload);
206                 }
207             }
208
209             var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
210                 res.setEncoding('utf8');
211                 msg.statusCode = res.statusCode;
212                 msg.headers = res.headers;
213                 msg.payload = "";
214                 res.on('data',function(chunk) {
215                     msg.payload += chunk;
216                 });
217                 res.on('end',function() {
218                     node.send(msg);
219                     node.status({});
220                 });
221             });
222             req.on('error',function(err) {
223                 msg.payload = err.toString() + " : " + url;
224                 msg.statusCode = err.code;
225                 node.send(msg);
226                 node.status({fill:"red",shape:"ring",text:err.code});
227             });
228             if (payload) {
229                 req.write(payload);
230             }
231             req.end();
232         });
233     }
234
235     RED.nodes.registerType("http request",HTTPRequest,{
236         credentials: {
237             user: {type:"text"},
238             password: {type: "password"}
239         }
240     });
241 }