-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
161 lines (146 loc) · 6.09 KB
/
Copy pathindex.js
File metadata and controls
161 lines (146 loc) · 6.09 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* This will create a proxy that massages a target JSON response into GEOJSON format.
* Settings are in the config directory by default
*/
var http = require("http")
var httpProxy = require("http-proxy");
var modifyResponse = require("node-http-proxy-json");
var lib = require("./lib")
process.env.NODE_ENV = "local_default"; // uses any settings in "local_default" to override "default"
const config = require('config');
// get proxy options from config
var options = {
target: config.get('target'),
changeOrigin: config.get('changeOrigin') }
// settings for procesing of request Accept headers
var geoCollectionAccept = null; var geoFeatureAccept = null;
if (config.has('geoCollectionAccept') && config.get('geoCollectionAccept')) {
geoCollectionAccept = config.get('geoCollectionAccept');
if (config.has('geoFeatureAccept') && config.get('geoFeatureAccept')) {
geoFeatureAccept = config.get('geoFeatureAccept');
}
}
var sendError = function(res, err) {
res.writeHead(500, { 'Content-Type': 'text/plain' } );
if (err.name) {
res.end('An error occured in the GeoJSON proxy: ' + err.name + ': ' + err.message);
} else {
res.end('An error occured in the GeoJSON proxy: ' + err);
}
};
var modifyGeo = function(res, proxyRes) { // modify GEOJSON and OpenAPI JSON
modifyResponse(res, proxyRes, function (body) {
var ct_header = proxyRes.headers['content-type'] || '';
if (ct_header.indexOf('application/json') == 0 || ct_header.indexOf('application/vnd.pgrst.object+json') == 0) {
return lib.jsonToGeoJSON(body); // massage the response only if it is proper JSON
} else if (ct_header.indexOf('application/openapi+json') == 0) {
return lib.openAPIJSON(body); // remove inapplicable verbs from OpenAPI JSON
} else {
return body; // otherwise return as is
}
});
};
var modifyNoGeo = function(res, proxyRes) { // just modify the OpenAPI JSON
modifyResponse(res, proxyRes, function (body) {
var ct_header = proxyRes.headers['content-type'] || '';
if (ct_header.indexOf('application/openapi+json') == 0) {
return lib.openAPIJSON(body); // remove inapplicable verbs from OpenAPI JSON
} else {
return body; // otherwise return as is
}
});
};
var parserange = /^(\d+)-(\d+)\/(.*)$/;
var modifyCount = function(res, proxyRes) { // replace body with simple JSON record total (also does OpenAPI JSON)
modifyResponse(res, proxyRes, function (body) {
var ct_header = proxyRes.headers['content-type'] || '';
if (ct_header.indexOf('application/json') == 0) {
var cr_header = proxyRes.headers['content-range'] || '';
var ranged = cr_header.match(parserange);
var newbody = { 'from': 0, 'to': 0, 'total': 0 };
if (ranged != null) {
newbody['from'] = parseInt(ranged[1]);
newbody['to'] = parseInt(ranged[2]);
newbody['total'] = parseInt(ranged[3]);
if (isNaN(newbody['total'])) {
newbody['total'] = null;
}
}
return newbody; // returns the header count values only
} else if (ct_header.indexOf('application/openapi+json') == 0) {
return lib.openAPIJSON(body); // remove inapplicable verbs from OpenAPI JSON
} else {
return body; // otherwise return as is
}
});
};
// Create a geo proxy server using the options
var geoproxy = httpProxy.createProxyServer(options);
geoproxy.on("error", function (err, req, res) { // error handling
sendError(res, err);
});
geoproxy.on("proxyRes", function(proxyRes, req, res) { // CORS and modify response
lib.corsHeaders(req, res);
modifyGeo(res, proxyRes);
});
var nogeoproxy = null; // if necessary also create a no geo proxy server using the options (used when the Accept header does not match)
if (geoCollectionAccept) {
nogeoproxy = httpProxy.createProxyServer(options);
nogeoproxy.on("error", function (err, req, res) {
sendError(res, err);
});
nogeoproxy.on("proxyRes", function(proxyRes, req, res) {
lib.corsHeaders(req, res);
modifyNoGeo(res, proxyRes);
});
}
// **UNDOCUMENTED** a proxy to return the record count values as a simple JSON response see modifyCount above
// currently triggered by request header 'Accept' 'application/vnd.pgrst.count+json' see below
// could be made configurable
var countproxy = httpProxy.createProxyServer(options);
countproxy.on("error", function (err, req, res) {
sendError(res, err);
});
countproxy.on('proxyReq', function(proxyReq, req, res) {
if (req.method == 'GET') { // ask for headers only from target
proxyReq.method = 'HEAD';
}
});
countproxy.on("proxyRes", function(proxyRes, req, res) { // CORS and modify response
lib.corsHeaders(req, res);
res.method = req.method; # dont send back as HEAD
modifyCount(res, proxyRes);
});
// Create real server which proxies the request
var server = http.createServer(function (req, res) {
if (req.method === 'OPTIONS') {
lib.corsHeaders(req, res);
res.writeHead(200, { 'Allow': 'GET, POST, OPTIONS, HEAD' } );
res.end();
return;
} else if (req.method === 'GET' || req.method === 'POST' || req.method === 'HEAD') {
var ac_header = req.headers['accept'] || '';
if (ac_header == 'application/vnd.pgrst.count+json') {
req.headers['accept'] = 'application/json';
if (!req.headers['prefer']) {
req.headers['prefer'] = 'count=estimated';
}
countproxy.web(req, res);
} else if (nogeoproxy) {
if (ac_header && geoCollectionAccept.indexOf(ac_header) >= 0) {
req.headers['accept'] = 'application/json';
geoproxy.web(req, res);
} else if (ac_header && geoFeatureAccept && geoFeatureAccept.indexOf(ac_header) >= 0) {
req.headers['accept'] = 'application/vnd.pgrst.object+json';
geoproxy.web(req, res);
} else {
nogeoproxy.web(req, res); // do not massage into GeoJSON if the Accept headers dont match
}
} else {
geoproxy.web(req, res); // default is to always massage into GeoJSON
}
}
});
// Start proxying
console.log("Starting GeoJSON proxy on port", config.get('port'), "for", config.get('target'));
server.listen(config.get('port'));