summaryrefslogtreecommitdiffstats
path: root/modules/orionode/lib/api.js
blob: 4307cb3f8d8af9bdf57b9a7ca028a4874cf81249 (plain)
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
/*******************************************************************************
 * Copyright (c) 2012 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*eslint-env node*/
var url = require('url');

/*
 * Sadly, the Orion client code expects http://orionserver/file and http://orionserver/file/ 
 * to both point to the File API. That's what this helper is for.
 */
function pathMatch(root, path) {
	var len = root.length;
	if (root[len-1] === '/') {
		root = root.substring(0, --len - 1);
	}
	return path.substring(0, len) === root && (path.length <= len || path[len] === '/');
}

/*
 * Returns the tail of the path after root has been matched.
 */
function rest(root, path) {
	if (!pathMatch(root, path)) {
		return null;
	}
	var tail = path.substring(root.length);
	return tail[0] === '/' ? tail.substring(1) : tail;
}

/*
 * Joins a bunch of junk into a path, like the path component of a URL.
 */
function join(/*varags*/) {
	var segs = Array.prototype.slice.call(arguments);
	var path = [];
	for (var i=0; i < segs.length; i++) {
		var segment = segs[i];
		// This is kind of cheesy: avoid double-slashes
		var last = segment.length-1;
		path.push(segment[last] === '/' ? segment.substring(0, last) : segment);
//		path.push(segment);
	}
	return path.join('/');
}

function toURLPath(p) {
	return p.replace(/\\/g, "/");
}

/**
 * Helper for writing a JSON response.
 * @param {Number} code
 * @param {HttpResponse} res
 * @param {Object} [headers]
 * @param {Object|String} [body] If Object, response will be JSON. If string, response will be text/plain.
 */
function write(code, res, headers, body) {
	if (typeof code === 'number') {
		res.status(code);
	}
	if (headers && typeof headers === 'object') {
		Object.keys(headers).forEach(function(header) {
			res.setHeader(header, headers[header]);
		});
	}
	if (typeof body !== 'undefined') {
		if (typeof body === 'object') {
			encodeLocation(body);
			return res.json(body);
		}
		res.send(body);
	} else {
		res.end();
	}
}

var LocationRegex = /Location$/;
var PercentReplaceRegex = /\%/g;
function encodeLocation(obj) {
	for (var p in obj) {
		if (p.match(LocationRegex)) {
			if (typeof obj[p] === "object") {
				obj[p].pathname = obj[p].pathname.replace(PercentReplaceRegex, "%25");
				obj[p] = url.format(obj[p]);
			} else {
				obj[p] = url.format({pathname: obj[p].replace(PercentReplaceRegex, "%25")});
			}
		} else if (typeof obj[p] === "object") {
			encodeLocation(obj[p]);
		}
	}
}

/**
 * Helper for writing an error JSON response.
 * @param {Number} code
 * @param {HttpResponse} res
 * @param {String|Error} [msg]
 */
function writeError(code, res, msg) {
	msg = msg instanceof Error ? msg.message : msg;
	if (typeof msg === 'string') {
		var err = JSON.stringify({Severity: "Error", Message: msg});
		res.setHeader('Content-Type', 'application/json');
		res.setHeader('Content-Length', err.length);
		res.writeHead(code, msg);
		res.end(err);
	} else {
		res.writeHead(code, msg);
		res.end();
	}
}

/**
 * Util for stripping host names from URLs on this server. If aUrl indicates a resource on this host (as given by the request's Host header),
 * returns the URL with this server's host removed. Otherwise, returns aUrl unmodified.
 * <p>
 * eg. matchHost({ host: 'foo.com:8081' }, 'http://foo.com/file/fizz.txt') returns '/file/fizz.txt'<br>
 * eg. matchHost({ host: 'foo.com:8081' }, 'http://bar.com/action?frob=quux') returns 'http://bar.com/action?frob=quux'
 * </p.
 * @param {HttpRequest}
 * @param {String} url
 * @returns {String} The resulting URL
 */
function matchHost(req, aUrl) {
	var thisServer = {
		host: req.headers.host
	};
	var parsedUrl = url.parse(aUrl);
	if (parsedUrl.host === thisServer.host) {
		parsedUrl.host = '';
		return url.format(parsedUrl);
	}
	return aUrl;
}

exports.toURLPath = toURLPath;
exports.pathMatch = pathMatch;
exports.matchHost = matchHost;
exports.rest = rest;
exports.join = join;
exports.writeError = writeError;
exports.write = write;