06a4e726309a2a32375d45bff7d0219449f55d99
[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 //NOTE: We need to go into the sessionStore because express-session
54 // does not reliably update the session.
55 // See https://github.com/expressjs/session/issues/450
56 var projectId = (req.session &&
57 req.sessionStore &&
58 req.sessionStore.sessions &&
59 req.sessionStore.sessions[req.session.id] &&
60 JSON.parse(req.sessionStore.sessions[req.session.id])['projectId']) ||
61 (null);
62 if (projectId) {
63 return url.replace(/(\/api\/operational\/|\/api\/config\/|\/api\/operations\/)(.*)/, '$1project/' + projectId + '/$2');
64
65 }
66 return url;
67 }
68
69
70 var validateResponse = function(callerName, error, response, body, resolve, reject) {
71 var res = {};
72
73 if (error) {
74 console.log('Problem with "', callerName, '": ', error);
75 res.statusCode = 500;
76 res.errorMessage = {
77 error: 'Problem with ' + callerName + ': ' + error
78 };
79 reject(res);
80 return false;
81 } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
82 console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
83 res.statusCode = response.statusCode;
84
85 // auth specific
86 if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
87 res.errorMessage = {
88 error: 'Authentication needed' + body
89 };
90 reject(res);
91 return false;
92 }
93
94 res.errorMessage = {
95 error: 'Problem with ' + callerName + ': ' + response.statusCode + ': ' + typeof(body) == 'string' ? body : JSON.stringify(body),
96 body: body
97 };
98
99 reject(res);
100 return false;
101 } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
102 resolve({
103 statusCode: response.statusCode,
104 data: {}
105 });
106 return false;
107 } else {
108 return true;
109 }
110 };
111
112
113 var checkAuthorizationHeader = function(req) {
114 return new Promise(function(resolve, reject) {
115 if (req.session && req.session.authorization == null) {
116 reject();
117 } else {
118 resolve();
119 }
120 });
121 };
122
123 if (process.env.LOG_REQUESTS) {
124 var logFile = process.env.REQUESTS_LOG_FILE;
125
126 if (logFile && logFile != '') {
127 validateResponse = function(callerName, error, response, body, resolve, reject) {
128 var res = {};
129
130 if (error) {
131 console.log('Problem with "', callerName, '": ', error);
132 res.statusCode = 500;
133 res.errorMessage = {
134 error: 'Problem with ' + callerName + ': ' + error
135 };
136 reject(res);
137 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error: ' + error);
138 return false;
139 } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
140 console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
141 res.statusCode = response.statusCode;
142
143 // auth specific
144 if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
145 res.errorMessage = {
146 error: 'Authentication needed' + body
147 };
148 reject(res);
149 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
150 return false;
151 }
152
153 res.errorMessage = {
154 error: 'Problem with ' + callerName + ': ' + response.statusCode + ': ' + body
155 };
156
157 reject(res);
158 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
159 return false;
160 } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
161 resolve();
162 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
163 return false;
164 } else {
165 fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
166 return true;
167 }
168 };
169 }
170 }
171
172 /**
173 * Serve the error response back back to HTTP requester
174 * @param {Object} error - object of the format
175 * {
176 * statusCode - HTTP code to respond back with
177 * error - actual error JSON object to serve
178 * }
179 * @param {Function} res - a handle to the express response function
180 */
181 var sendErrorResponse = function(error, res) {
182 res.status(error.statusCode);
183 res.send(error);
184 }
185
186 /**
187 * Serve the success response back to HTTP requester
188 * @param {Object} response - object of the format
189 * {
190 * statusCode - HTTP code to respond back with
191 * data - actual data JSON object to serve
192 * }
193 * @param {Function} res - a handle to the express response function
194 */
195 var sendSuccessResponse = function(response, res) {
196 res.status(response.statusCode);
197 res.send(response.data);
198 }
199
200 var passThroughConstructor = function(app) {
201 app.get('/passthrough/:type/*', function(req, res) {
202 var url = req.params[0];
203 var type = req.params.type;
204 var api_server = req.query["api_server"];
205 var uri = confdPort(api_server) + APIVersion + '/' + url + '?deep';
206 // Check that type is valid
207 switch (type) {
208 case 'data':
209 ;
210 case 'collection':
211 break;
212 default:
213 res.send({});
214 }
215 new Promise(function(resolve, reject) {
216 request({
217 uri: projectContextUrl(req, uri),
218 method: 'GET',
219 headers: _.extend({}, CONSTANTS.HTTP_HEADERS.accept[type], {
220 'Authorization': req.session && req.session.authorization,
221 forever: CONSTANTS.FOREVER_ON,
222 rejectUnauthorized: false,
223 })
224 }, function(error, response, body) {
225 if (validateResponse('Passthrough: ' + url, error, response, body, resolve, reject)) {
226 resolve(JSON.parse(response.body))
227 };
228 });
229 }).then(function(data) {
230 res.send(data);
231 }, function(error) {
232 res.send({'error': error, uri: uri})
233 });;
234 });
235 }
236
237 var getPortForProtocol = function(protocol) {
238 switch (protocol) {
239 case 'http':
240 return 8000;
241 case 'https':
242 return 8443;
243 }
244 }
245
246 module.exports = {
247 /**
248 * Ensure confd port is on api_server variable.
249 **/
250 confdPort: confdPort,
251
252 validateResponse: validateResponse,
253
254 checkAuthorizationHeader: checkAuthorizationHeader,
255
256 request: requestWrapper.call(null, request),
257
258 sendErrorResponse: sendErrorResponse,
259
260 sendSuccessResponse: sendSuccessResponse,
261
262 passThroughConstructor: passThroughConstructor,
263
264 getPortForProtocol: getPortForProtocol,
265
266 projectContextUrl: projectContextUrl
267 };