-
Notifications
You must be signed in to change notification settings - Fork 84
/
index.js
99 lines (80 loc) · 2.66 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright 2019 SmugMug, Inc.
// Licensed under the terms of the MIT license. Please see LICENSE file in the project root for terms.
var Promise = require('bluebird');
var messageHash = require('incoming-message-hash');
var assert = require('assert');
var mkdirp = require('mkdirp');
var path = require('path');
var buffer = require('./lib/buffer');
var proxy = require('./lib/proxy');
var record = require('./lib/record');
var curl = require('./lib/curl');
var debug = require('debug')('yakbak:server');
/**
* Returns a new yakbak proxy middleware.
* @param {String} host The hostname to proxy to
* @param {Object} opts
* @param {String} opts.dirname The tapes directory
* @param {Boolean} opts.noRecord if true, requests will return a 404 error if the tape doesn't exist
* @returns {Function}
*/
module.exports = function (host, opts) {
assert(opts.dirname, 'You must provide opts.dirname');
return function (req, res) {
mkdirp.sync(opts.dirname);
debug('req', req.url);
return buffer(req).then(function (body) {
var file = path.join(opts.dirname, tapename(req, body));
return Promise.try(function () {
return require.resolve(file);
}).catch(ModuleNotFoundError, function (/* err */) {
if (opts.noRecord) {
throw new RecordingDisabledError('Recording Disabled');
} else {
return proxy(req, body, host).then(function (pres) {
return record(pres.req, pres, file);
});
}
});
}).then(function (file) {
return require(file);
}).then(function (tape) {
return tape(req, res);
}).catch(RecordingDisabledError, function (err) {
/* eslint-disable no-console */
console.log('An HTTP request has been made that yakbak does not know how to handle');
console.log(curl.request(req));
/* eslint-enable no-console */
res.statusCode = err.status;
res.end(err.message);
});
};
/**
* Returns the tape name for `req`.
* @param {http.IncomingMessage} req
* @param {Array.<Buffer>} body
* @returns {String}
*/
function tapename(req, body) {
var hash = opts.hash || messageHash.sync;
return hash(req, Buffer.concat(body)) + '.js';
}
};
/**
* Bluebird error predicate for matching module not found errors.
* @param {Error} err
* @returns {Boolean}
*/
function ModuleNotFoundError(err) {
return err.code === 'MODULE_NOT_FOUND';
}
/**
* Error class that is thrown when an unmatched request
* is encountered in noRecord mode
* @constructor
*/
function RecordingDisabledError(message) {
this.message = message;
this.status = 404;
}
RecordingDisabledError.prototype = Object.create(Error.prototype);