UNPKG

4.43 kBJavaScriptView Raw
1"use strict";
2
3var http = require('http');
4var url = require('url');
5var util = require('util');
6var qs = require('qs');
7
8var co = require('co');
9var coBody = require('co-body');
10var bluebird = require('bluebird');
11
12var ActionError = require('skinny-bone-actions/lib/errors/actionError');
13
14var createError = require('create-error');
15
16function HttpTransport(skinny, options) {
17 this.skinny = skinny;
18 this.options = options;
19
20 this.server = this._createServer();
21
22 if (options.connectionTimeout) {
23 this.server.timeout = options.connectionTimeout;
24 }
25}
26
27var HttpTransportError = createError('HttpTransportError', { responseCode: 500 });
28var ServiceError = createError(HttpTransportError, 'ServiceError', { responseCode: 500 });
29var WrongSecretError = createError(HttpTransportError, 'WrongSecretError', { responseCode: 401 });
30var BadRequestError = createError(HttpTransportError, 'InvalidRequestError', { responseCode: 400 });
31var ActionNotPresent = createError(BadRequestError, 'ActionNotPresent', { responseCode: 404 });
32
33HttpTransport.prototype.ERRORS = {
34 HttpTransportError: HttpTransportError,
35 ServiceError: ServiceError,
36 WrongSecretError: WrongSecretError,
37 BadRequestError: BadRequestError,
38 ActionNotPresent: ActionNotPresent
39};
40
41HttpTransport.prototype.listen = function listen() {
42 return this.server.listenAsync(this.options.port, this.options.host);
43};
44
45HttpTransport.prototype.close = function close() {
46 if (this.server.address()) {
47 return this.server.closeAsync();
48 } else {
49 return Promise.resolve();
50 }
51};
52
53HttpTransport.prototype._handleRequest = function _handleRequest(req, res) {
54 return co(function *() {
55 try {
56 // Authenticate
57 var token = (req.headers.authorization || '').split(/\s+/).pop() || '';
58 var auth = new Buffer(token, 'base64').toString();
59 var requestSecret = auth.split(/:/).shift() || '';
60
61 if (this.options.secret !== undefined && requestSecret !== this.options.secret) {
62 throw new WrongSecretError('Wrong secret!');
63 }
64
65 // Get params
66 var parsedUrl = url.parse(req.url);
67
68 var actionName = parsedUrl.pathname.substring(1);
69
70 if (!this.skinny.actions[actionName]) {
71 throw new ActionNotPresent('Action "' + actionName + '" not present!');
72 }
73
74 var params = qs.parse(parsedUrl.query);
75
76 if (req.method == "POST") {
77 var bodyParams = yield coBody.json(req);
78 params = util._extend(bodyParams, params);
79 }
80
81 // Run action
82 var actionSkinny = this.skinny.newSkinny();
83
84 actionSkinny.httpRequest = req;
85 actionSkinny.httpResponse = res;
86
87 var actionResponse = yield this.skinny.actions[actionName](params, actionSkinny);
88
89 if (!res.headersSent) {
90 if (!res.getHeader('Content-Type')) {
91 res.setHeader('Content-Type', 'application/json');
92 }
93
94 res.writeHead(res.statusCode || 200);
95
96 var response = { status: 'success' };
97 if (actionResponse !== undefined) {
98 response.data = actionResponse;
99 }
100
101 res.write(JSON.stringify(response));
102 }
103
104 res.end();
105 } catch (e) {
106 this.skinny.emit('warning', e);
107
108 if (e instanceof ActionError) {
109 e = new BadRequestError(e.name + ': ' + e.message);
110 } else if (!(e instanceof HttpTransportError)) {
111 e = new ServiceError(e.name + ': ' + e.message);
112 }
113
114 var status = e.responseCode >= 400 && e.responseCode <= 499 ? 'error' : 'fail';
115 var response = JSON.stringify({ status: status, errorCode: e.name, errorMessage: e.message });
116
117 res.writeHead(e.responseCode, { 'Content-Type': 'application/json' });
118 res.end(response);
119 }
120 }.bind(this)).catch(function(error) {
121 this.skinny.emit('error', error);
122
123 return error;
124 }.bind(this));
125};
126
127HttpTransport.prototype._createServer = function _createServer() {
128 var server = http.createServer(this._handleRequest.bind(this));
129
130 bluebird.promisifyAll(server);
131
132 return server;
133};
134
135module.exports = HttpTransport;
\No newline at end of file