Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2014, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

package org.restcomm.connect.http.client.rcmlserver.resolver;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* A relative URI resolver for Rcmlserver/RVD. It values defined in rcmlserver restcomm.xml configuration
* section (rcmlserver.base-url, rcmlserver.api-path) to convert relative urls to absolute i.e. prepent Rcmlserver origin (http://rcmlserver.domain:port).
* By design, the resolver is used when resolving Application.rcmlUrl only. An additional filter prefix
* is used and helps the resolver affect only urls that start with "/restcomm-rvd/". This filter value is
* configurable through rcmlserver.api-path. It will use whatever it between the first pair of slashes "/.../".
* If configuration is missing or rcmlserver is deployed bundled with restcomm the resolver won't affect the
* uri resolved, typically leaving UriUtils class take care of it.
*
* @author otsakir@gmail.com - Orestis Tsakiridis
*/
public class RcmlserverResolver {
protected static Logger logger = Logger.getLogger(RcmlserverResolver.class);
static RcmlserverResolver singleton;

String rvdOrigin;
String filterPrefix; // a pattern used to match against relative urls in application.rcmlUrl. If null, to resolving will occur.

static final String DEFAULT_FILTER_PREFIX = "/restcomm-rvd/";

// not really a clean singleton pattern but a way to init once and use many. Only the first time this method is called the parameters are used in the initialization
public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath, boolean reinit) {
if (singleton == null || reinit) {
singleton = new RcmlserverResolver(rvdOrigin, apiPath);
}
return singleton;
}

public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath) {
return getInstance(rvdOrigin, apiPath, false);
}

public RcmlserverResolver(String rvdOrigin, String apiPath) {
this.rvdOrigin = rvdOrigin;
if ( ! StringUtils.isEmpty(apiPath) ) {
// extract the first part of the path and use it as a filter prefix
Pattern pattern = Pattern.compile("/([^/]*)((/.*)|$)");
Matcher matcher = pattern.matcher(apiPath);
if (matcher.matches() && matcher.group(1) != null) {
filterPrefix = "/" + matcher.group(1) + "/";
} else
filterPrefix = DEFAULT_FILTER_PREFIX;
logger.info("RcmlserverResolver initialized. Urls starting with '" + filterPrefix + "' will get prepended with '" + (rvdOrigin == null ? "" : rvdOrigin) + "'");
} else
filterPrefix = null;
}

// if rvdOrigin is null no point in trying to resolve RVD location. We will return passed uri instead
public URI resolveRelative(URI uri) {
if (uri != null && rvdOrigin != null && filterPrefix != null) {
if (uri.isAbsolute())
return uri;
try {
String uriString = uri.toString();
if (uriString.startsWith(filterPrefix))
return new URI(rvdOrigin + uri.toString());
} catch (URISyntaxException e) {
logger.error("Cannot resolve uri: " + uri.toString() + ". Ignoring...", e);
}
}
return uri;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2014, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

package org.restcomm.connect.http.client.rcmlserver.resolver;

import junit.framework.Assert;
import org.junit.Test;

import java.net.URI;
import java.net.URISyntaxException;

/**
* @author otsakir@gmail.com - Orestis Tsakiridis
*/
public class RcmlserverResolverTest {
@Test
public void testResolving() throws URISyntaxException {
RcmlserverResolver resolver = RcmlserverResolver.getInstance("http://rvdserver.org","/restcomm-rvd/services/", true);
URI uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/AP5f58b0baf6e14001b6eec02295fab05a/controller"));
// relative urls to actual RVD applications should get prefixed
Assert.assertEquals("http://rvdserver.org/restcomm-rvd/services/apps/AP5f58b0baf6e14001b6eec02295fab05a/controller", uri.toString());
// absolute urls should not be touched
uri = resolver.resolveRelative(new URI("http://externalserver/AP5f58b0baf6e14001b6eec02295fab05a/controller"));
Assert.assertEquals("http://externalserver/AP5f58b0baf6e14001b6eec02295fab05a/controller", uri.toString());
// relative urls pointing to other (non-rvd) apps
uri = resolver.resolveRelative(new URI("/restcomm/demos/hellp-play.xml"));
Assert.assertEquals("/restcomm/demos/hellp-play.xml", uri.toString());
// make sure that RVD path can vary. Assume it's '/new-rvd' now
resolver = RcmlserverResolver.getInstance("http://rvdserver.org","/new-rvd/services/", true);
uri = resolver.resolveRelative(new URI("/new-rvd/myapp.xml"));
Assert.assertEquals("http://rvdserver.org/new-rvd/myapp.xml", uri.toString());
// if rcmlserver.baseUrl is null, no resolving should occur
resolver = RcmlserverResolver.getInstance(null,"/restcomm-rvd/services", true);
uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
// if rcmlserver.apiPath is null or empty, no resolving should occur
resolver = RcmlserverResolver.getInstance("http://rvdotsakir.org","", true);
uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
// all nulls
resolver = RcmlserverResolver.getInstance(null,null, true);
uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
import org.apache.commons.configuration.Configuration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
Expand All @@ -53,6 +55,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.SmsInterpreter;
import org.restcomm.connect.interpreter.SmsInterpreterParams;
import org.restcomm.connect.interpreter.StartInterpreter;
Expand Down Expand Up @@ -299,7 +302,9 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ
final Sid sid = number.getSmsApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(appUri));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import com.cloudhopper.smpp.type.UnrecoverablePduException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.apache.commons.configuration.Configuration;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
Expand All @@ -32,6 +34,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.monitoringservice.MonitoringService;
import org.restcomm.connect.sms.SmsSession;
Expand Down Expand Up @@ -166,7 +169,9 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SmppInboundMes
final Sid sid = number.getSmsApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else if (appUri != null) {
builder.setUrl(UriUtils.resolve(appUri));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.patterns.StopObserving;
Expand Down Expand Up @@ -65,6 +66,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.interpreter.StopInterpreter;
import org.restcomm.connect.interpreter.VoiceInterpreter;
Expand Down Expand Up @@ -1124,7 +1126,9 @@ private void transfer(SipServletRequest request) throws Exception {

if (number.getReferApplicationSid() != null) {
Application application = storage.getApplicationsDao().getApplication(number.getReferApplicationSid());
builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getReferUrl()));
}
Expand Down Expand Up @@ -1229,7 +1233,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe
final Sid sid = number.getVoiceApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver rcmlserverResolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
builder.setUrl(UriUtils.resolve(rcmlserverResolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getVoiceUrl()));
}
Expand Down Expand Up @@ -1287,7 +1293,9 @@ private boolean redirectToClientVoiceApp(final ActorRef self, final SipServletRe
URI clientAppVoiceUrl = null;
if (applicationSid != null) {
final Application application = applications.getApplication(applicationSid);
clientAppVoiceUrl = UriUtils.resolve(application.getRcmlUrl());
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
clientAppVoiceUrl = UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl()));
}
if (clientAppVoiceUrl == null) {
clientAppVoiceUrl = client.getVoiceUrl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.apache.commons.configuration.Configuration;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
Expand All @@ -36,6 +38,7 @@
import org.restcomm.connect.dao.entities.Account;
import org.restcomm.connect.dao.entities.Application;
import org.restcomm.connect.dao.entities.IncomingPhoneNumber;
import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.telephony.api.CallManagerResponse;
import org.restcomm.connect.telephony.api.CreateCall;
Expand Down Expand Up @@ -217,7 +220,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe
final Sid sid = number.getUssdApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getUssdUrl()));
}
Expand Down