3 * Copyright 2016 RIFT.IO Inc
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * Utils for use across the api_server.
23 * @module framework/core/utils
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');
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
43 var confdPort = function(api_server
) {
45 api_server
= api_server
.replace(api_server
.match(/[0-9](:[0-9]+)/)[1], '')
49 return api_server
+ ':' + CONFD_PORT
;
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
&&
58 req
.sessionStore
.sessions
&&
59 req
.sessionStore
.sessions
[req
.session
.id
] &&
60 JSON
.parse(req
.sessionStore
.sessions
[req
.session
.id
])['projectId']) ||
63 return url
.replace(/(\/api\/operational\/|\/api\/config\/)(.*)/, '$1project/' + projectId
+ '/$2');
68 var addProjectContextToRPCPayload = function(req
, url
, inputPayload
) {
69 //NOTE: We need to go into the sessionStore because express-session
70 // does not reliably update the session.
71 // See https://github.com/expressjs/session/issues/450
72 var projectId
= (req
.session
&&
74 req
.sessionStore
.sessions
&&
75 req
.sessionStore
.sessions
[req
.session
.id
] &&
76 JSON
.parse(req
.sessionStore
.sessions
[req
.session
.id
])['projectId']) ||
79 if (url
.indexOf('/api/operations/')) {
80 inputPayload
['project-name'] = projectId
;
87 var validateResponse = function(callerName
, error
, response
, body
, resolve
, reject
) {
91 console
.log('Problem with "', callerName
, '": ', error
);
94 error
: 'Problem with ' + callerName
+ ': ' + error
98 } else if (response
.statusCode
>= CONSTANTS
.HTTP_RESPONSE_CODES
.ERROR
.BAD_REQUEST
) {
99 console
.log('Problem with "', callerName
, '": ', response
.statusCode
, ':', body
);
100 res
.statusCode
= response
.statusCode
;
103 if (response
.statusCode
== CONSTANTS
.HTTP_RESPONSE_CODES
.ERROR
.UNAUTHORIZED
) {
105 error
: 'Authentication needed' + body
112 error
: 'Problem with ' + callerName
+ ': ' + response
.statusCode
+ ': ' + typeof(body
) == 'string' ? body
: JSON
.stringify(body
),
118 } else if (response
.statusCode
== CONSTANTS
.HTTP_RESPONSE_CODES
.SUCCESS
.NO_CONTENT
) {
120 statusCode
: response
.statusCode
,
130 var checkAuthorizationHeader = function(req
) {
131 return new Promise(function(resolve
, reject
) {
132 if (req
.session
&& req
.session
.authorization
== null) {
140 if (process
.env
.LOG_REQUESTS
) {
141 var logFile
= process
.env
.REQUESTS_LOG_FILE
;
143 if (logFile
&& logFile
!= '') {
144 validateResponse = function(callerName
, error
, response
, body
, resolve
, reject
) {
148 console
.log('Problem with "', callerName
, '": ', error
);
149 res
.statusCode
= 500;
151 error
: 'Problem with ' + callerName
+ ': ' + error
154 fs
.appendFileSync(logFile
, 'Request API: ' + response
.request
.uri
.href
+ ' ; ' + 'Error: ' + error
);
156 } else if (response
.statusCode
>= CONSTANTS
.HTTP_RESPONSE_CODES
.ERROR
.BAD_REQUEST
) {
157 console
.log('Problem with "', callerName
, '": ', response
.statusCode
, ':', body
);
158 res
.statusCode
= response
.statusCode
;
161 if (response
.statusCode
== CONSTANTS
.HTTP_RESPONSE_CODES
.ERROR
.UNAUTHORIZED
) {
163 error
: 'Authentication needed' + body
166 fs
.appendFileSync(logFile
, 'Request API: ' + response
.request
.uri
.href
+ ' ; ' + 'Error Body: ' + body
);
171 error
: 'Problem with ' + callerName
+ ': ' + response
.statusCode
+ ': ' + body
175 fs
.appendFileSync(logFile
, 'Request API: ' + response
.request
.uri
.href
+ ' ; ' + 'Error Body: ' + body
);
177 } else if (response
.statusCode
== CONSTANTS
.HTTP_RESPONSE_CODES
.SUCCESS
.NO_CONTENT
) {
179 fs
.appendFileSync(logFile
, 'Request API: ' + response
.request
.uri
.href
+ ' ; ' + 'Response Body: ' + body
);
182 fs
.appendFileSync(logFile
, 'Request API: ' + response
.request
.uri
.href
+ ' ; ' + 'Response Body: ' + body
);
190 * Serve the error response back back to HTTP requester
191 * @param {Object} error - object of the format
193 * statusCode - HTTP code to respond back with
194 * error - actual error JSON object to serve
196 * @param {Function} res - a handle to the express response function
198 var sendErrorResponse = function(error
, res
) {
199 if (!error
.statusCode
) {
200 console
.error('Status Code has not been set in error object: ', error
);
202 res
.status(error
.statusCode
);
207 * Serve the success response back to HTTP requester
208 * @param {Object} response - object of the format
210 * statusCode - HTTP code to respond back with
211 * data - actual data JSON object to serve
213 * @param {Function} res - a handle to the express response function
215 var sendSuccessResponse = function(response
, res
) {
216 res
.status(response
.statusCode
);
217 res
.send(response
.data
);
220 var passThroughConstructor = function(app
) {
221 app
.get('/passthrough/:type/*', function(req
, res
) {
222 var url
= req
.params
[0];
223 var type
= req
.params
.type
;
224 var api_server
= req
.query
["api_server"];
225 var uri
= confdPort(api_server
) + APIVersion
+ '/' + url
+ '?deep';
226 // Check that type is valid
235 new Promise(function(resolve
, reject
) {
237 uri
: projectContextUrl(req
, uri
),
239 headers
: _
.extend({}, CONSTANTS
.HTTP_HEADERS
.accept
[type
], {
240 'Authorization': req
.session
&& req
.session
.authorization
,
241 forever
: CONSTANTS
.FOREVER_ON
,
242 rejectUnauthorized
: false,
244 }, function(error
, response
, body
) {
245 if (validateResponse('Passthrough: ' + url
, error
, response
, body
, resolve
, reject
)) {
246 resolve(JSON
.parse(response
.body
))
249 }).then(function(data
) {
252 res
.send({'error': error
, uri
: uri
})
257 var getPortForProtocol = function(protocol
) {
268 * Ensure confd port is on api_server variable.
270 confdPort
: confdPort
,
272 validateResponse
: validateResponse
,
274 checkAuthorizationHeader
: checkAuthorizationHeader
,
276 request
: requestWrapper
.call(null, request
),
278 sendErrorResponse
: sendErrorResponse
,
280 sendSuccessResponse
: sendSuccessResponse
,
282 passThroughConstructor
: passThroughConstructor
,
284 getPortForProtocol
: getPortForProtocol
,
286 projectContextUrl
: projectContextUrl
,
288 addProjectContextToRPCPayload
: addProjectContextToRPCPayload