185c7c6e3940d2aa9018ef79f43a9a90f1729063
[osm/UI.git] / skyquake / framework / core / api_utils / utils.js
1 /*
2 *
3 * Copyright 2016 RIFT.IO Inc
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 // Helper Functions
19
20
21 /**
22 * Utils for use across the api_server.
23 * @module framework/core/utils
24 */
25
26 var fs = require('fs');
27 var request = require('request');
28 var Promise = require('promise');
29 var CONSTANTS = require('./constants.js');
30 var CONFD_PORT = '8008';
31 var APIVersion = '/v1';
32 var _ = require('lodash');
33
34 var requestWrapper = function(request) {
35 if (process.env.HTTP_PROXY && process.env.HTTP_PROXY != '') {
36 request = request.defaults({
37 'proxy': process.env.HTTP_PROXY
38 });
39 }
40 return request;
41 }
42
43 var confdPort = function(api_server) {
44 try {
45 api_server = api_server.replace(api_server.match(/[0-9](:[0-9]+)/)[1], '')
46 } catch (e) {
47
48 }
49 return api_server + ':' + CONFD_PORT;
50 };
51
52 var projectContextUrl = function(req, url) {
53 if (req.session && req.session.projectId) {
54 return url.replace(/(\/api\/operational\/|\/api\/config\/|\/api\/operations\/)(.*)/, '$1project/' + req.session.projectId + '/$2');
55
56 }
57 return url;
58 }
59
60
61 var validateResponse = function(callerName, error, response, body, resolve, reject) {
62 var res = {};
63
64 if (error) {
65 console.log('Problem with "', callerName, '": ', error);
66 res.statusCode = 500;
67 res.errorMessage = {
68 error: 'Problem with ' + callerName + ': ' + error
69 };
70 reject(res);
71 return false;
72 } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
73 console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
74 res.statusCode = response.statusCode;
75
76 // auth specific
77 if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
78 res.errorMessage = {
79 error: 'Authentication needed' + body
80 };
81 reject(res);
82 return false;
83 }
84
85 res.errorMessage = {
86 error: 'Problem with ' + callerName + ': ' + response.statusCode + ': ' + typeof(body) == 'string' ? body : JSON.stringify(body),
87 body: body
88 };
89
90 reject(res);
91 return false;
92 } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
93 resolve({
94 statusCode: response.statusCode,
95 data: {}
96 });
97 return false;
98 } else {
99 return true;
100 }
101 };
102
103
104 var checkAuthorizationHeader = function(req) {
105 return new Promise(function(resolve, reject) {
106 if (req.session && req.session.authorization == null) {
107 reject();
108 } else {
109 resolve();
110 }
111 });
112 };
113
114 if (process.env.LOG_REQUESTS) {
115 var logFile = process.env.REQUESTS_LOG_FILE;
116
117 if (logFile && logFile != '') {
118 validateResponse = function(callerName, error, response, body, resolve, reject) {
119 var res = {};
120
121 if (error) {
122 console.log('Problem with "', callerName, '": ', error);
123 res.statusCode = 500;
124 res.errorMessage = {
125 error: 'Problem with ' + callerName + ': ' + error
126 };
127 reject(res);
128 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error: ' + error);
129 return false;
130 } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
131 console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
132 res.statusCode = response.statusCode;
133
134 // auth specific
135 if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
136 res.errorMessage = {
137 error: 'Authentication needed' + body
138 };
139 reject(res);
140 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
141 return false;
142 }
143
144 res.errorMessage = {
145 error: 'Problem with ' + callerName + ': ' + response.statusCode + ': ' + body
146 };
147
148 reject(res);
149 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
150 return false;
151 } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
152 resolve();
153 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
154 return false;
155 } else {
156 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
157 return true;
158 }
159 };
160 }
161 }
162
163 /**
164 * Serve the error response back back to HTTP requester
165 * @param {Object} error - object of the format
166 * {
167 * statusCode - HTTP code to respond back with
168 * error - actual error JSON object to serve
169 * }
170 * @param {Function} res - a handle to the express response function
171 */
172 var sendErrorResponse = function(error, res) {
173 res.status(error.statusCode);
174 res.send(error);
175 }
176
177 /**
178 * Serve the success response back to HTTP requester
179 * @param {Object} response - object of the format
180 * {
181 * statusCode - HTTP code to respond back with
182 * data - actual data JSON object to serve
183 * }
184 * @param {Function} res - a handle to the express response function
185 */
186 var sendSuccessResponse = function(response, res) {
187 res.status(response.statusCode);
188 res.send(response.data);
189 }
190
191 var passThroughConstructor = function(app) {
192 app.get('/passthrough/:type/*', function(req, res) {
193 var url = req.params[0];
194 var type = req.params.type;
195 var api_server = req.query["api_server"];
196 var uri = confdPort(api_server) + APIVersion + '/' + url + '?deep';
197 // Check that type is valid
198 switch (type) {
199 case 'data':
200 ;
201 case 'collection':
202 break;
203 default:
204 res.send({});
205 }
206 new Promise(function(resolve, reject) {
207 request({
208 uri: projectContextUrl(req, uri),
209 method: 'GET',
210 headers: _.extend({}, CONSTANTS.HTTP_HEADERS.accept[type], {
211 'Authorization': req.session && req.session.authorization,
212 forever: CONSTANTS.FOREVER_ON,
213 rejectUnauthorized: false,
214 })
215 }, function(error, response, body) {
216 if (validateResponse('Passthrough: ' + url, error, response, body, resolve, reject)) {
217 resolve(JSON.parse(response.body))
218 };
219 });
220 }).then(function(data) {
221 res.send(data);
222 }, function(error) {
223 res.send({'error': error, uri: uri})
224 });;
225 });
226 }
227
228 var getPortForProtocol = function(protocol) {
229 switch (protocol) {
230 case 'http':
231 return 8000;
232 case 'https':
233 return 8443;
234 }
235 }
236
237 module.exports = {
238 /**
239 * Ensure confd port is on api_server variable.
240 **/
241 confdPort: confdPort,
242
243 validateResponse: validateResponse,
244
245 checkAuthorizationHeader: checkAuthorizationHeader,
246
247 request: requestWrapper.call(null, request),
248
249 sendErrorResponse: sendErrorResponse,
250
251 sendSuccessResponse: sendSuccessResponse,
252
253 passThroughConstructor: passThroughConstructor,
254
255 getPortForProtocol: getPortForProtocol,
256
257 projectContextUrl: projectContextUrl
258 };