/*******************************************************************************
* Copyright (c) 2012, 2014 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
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.server.servlets;
import java.net.URI;
import java.net.URISyntaxException;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.tasks.IURIUnqualificationStrategy;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Controls which URLs found in JSON API response bodies will be "unqualified" (rewritten to remove the hostname
* and port of this server).
*/
public abstract class JsonURIUnqualificationStrategy implements IURIUnqualificationStrategy {
/**
* A strategy that unqualifies all URLs in the JSON body.
*/
public static final IURIUnqualificationStrategy ALL = new JsonURIUnqualificationStrategy() {
@Override
protected URI unqualifyObjectProperty(String key, URI uri, String scheme, String hostname, int port) {
return unqualifyURI(uri, scheme, hostname, port);
}
@Override
protected URI unqualifyArrayValue(int index, URI uri, String scheme, String hostname, int port) {
return unqualifyURI(uri, scheme, hostname, port);
}
public String getName() {
return "ALL";
}
};
/**
* A strategy that unqualifies only the URLs that are values of a "Location" key in JSON objects.
*/
public static final IURIUnqualificationStrategy LOCATION_ONLY = new JsonURIUnqualificationStrategy() {
@Override
protected URI unqualifyObjectProperty(String key, URI uri, String scheme, String hostname, int port) {
if (!ProtocolConstants.KEY_LOCATION.equals(key))
return uri;
else
return unqualifyURI(uri, scheme, hostname, port);
}
@Override
protected URI unqualifyArrayValue(int index, URI uri, String scheme, String hostname, int port) {
return uri;
}
public String getName() {
return "LOCATION_ONLY";
}
};
/**
* A strategy that unqualifies all URLs but doesn't alter URLS that are values of a "GitUrl" key in JSON objects.
*/
public static final IURIUnqualificationStrategy ALL_NO_GIT = new JsonURIUnqualificationStrategy() {
@Override
protected URI unqualifyObjectProperty(String key, URI uri, String scheme, String hostname, int port) {
//need to make this real constant
if ("GitUrl".equals(key))
return uri;
else
return unqualifyURI(uri, scheme, hostname, port);
}
@Override
protected URI unqualifyArrayValue(int index, URI uri, String scheme, String hostname, int port) {
return uri;
}
public String getName() {
return "ALL_NO_GIT";
}
};
/* (non-Javadoc)
* @see org.eclipse.orion.server.servlets.IURIUnqualificationStrategy#run(javax.servlet.http.HttpServletRequest, java.lang.Object)
*/
public void run(HttpServletRequest req, Object result) {
rewrite(result, req.getScheme(), req.getServerName(), req.getServerPort(), req.getContextPath());
}
private void rewrite(JSONObject json, String scheme, String hostname, int port, String contextPath) {
String[] names = JSONObject.getNames(json);
if (names == null)
return;
for (String name : names) {
Object o = json.opt(name);
if (o instanceof URI) {
try {
URI uri = (URI) o;
if ("orion".equals(uri.getScheme())) {
uri = new URI(null, null, contextPath + uri.getPath(), uri.getQuery(), uri.getFragment());
}
json.put(name, unqualifyObjectProperty(name, uri, scheme, hostname, port));
} catch (JSONException e) {
} catch (URISyntaxException e) {
}
} else if (o instanceof String) {
String string = (String) o;
if (string.startsWith(scheme) || string.startsWith("orion:/")) {
try {
URI uri = new URI(string);
if ("orion".equals(uri.getScheme())) {
uri = new URI(null, null, contextPath + uri.getPath(), uri.getQuery(), uri.getFragment());
}
json.put(name, unqualifyObjectProperty(name, uri, scheme, hostname, port));
} catch (JSONException e) {
} catch (URISyntaxException e) {
}
}
} else {
rewrite(o, scheme, hostname, port, contextPath);
}
}
}
private void rewrite(Object o, String scheme, String hostname, int port, String contextPath) {
if (o instanceof JSONObject) {
rewrite((JSONObject) o, scheme, hostname, port, contextPath);
} else if (o instanceof JSONArray) {
JSONArray a = (JSONArray) o;
for (int i = 0; i < a.length(); i++) {
Object v = a.opt(i);
if (v instanceof URI) {
try {
a.put(i, unqualifyArrayValue(i, (URI) v, scheme, hostname, port));
} catch (JSONException e) {
}
} else if (v instanceof String) {
String string = (String) v;
if (string.startsWith(scheme)) {
try {
a.put(i, unqualifyArrayValue(i, new URI(string), scheme, hostname, port));
} catch (JSONException e) {
} catch (URISyntaxException e) {
}
}
} else {
rewrite(v, scheme, hostname, port, contextPath);
}
}
}
}
protected abstract URI unqualifyObjectProperty(String key, URI uri, String scheme, String hostname, int port);
protected abstract URI unqualifyArrayValue(int index, URI uri, String scheme, String hostname, int port);
protected static URI unqualifyURI(URI uri, String scheme, String hostname, int port) {
URI simpleURI = uri;
int uriPort = uri.getPort();
if (uriPort == -1) {
uriPort = getDefaultPort(uri.getScheme());
}
if (scheme.equals(uri.getScheme()) && hostname.equals(uri.getHost()) && port == uriPort) {
try {
simpleURI = new URI(null, null, null, -1, uri.getPath(), uri.getQuery(), uri.getFragment());
} catch (URISyntaxException e) {
simpleURI = uri;
}
}
return simpleURI;
}
private static int getDefaultPort(String scheme) {
if ("http".equalsIgnoreCase(scheme)) {
return 80;
}
if ("https".equalsIgnoreCase(scheme)) {
return 443;
}
return -1;
}
}