1 /*
2 * Licensed to The Apereo Foundation under one or more contributor license
3 * agreements. See the NOTICE file distributed with this work for additional
4 * information regarding copyright ownership.
5 *
6 *
7 * The Apereo Foundation licenses this file to you under the Educational
8 * Community License, Version 2.0 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of the License
10 * at:
11 *
12 * http://opensource.org/licenses/ecl2.txt
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 * License for the specific language governing permissions and limitations under
18 * the License.
19 *
20 */
21 package org.opencastproject.security.urlsigning;
22
23 import org.opencastproject.urlsigning.common.ResourceStrategy;
24
25 import org.apache.commons.lang3.StringUtils;
26
27 import java.net.URI;
28 import java.net.URISyntaxException;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31
32 /**
33 * A {@link ResourceStrategy} that transforms URLs for a Wowza streaming server. Based upon:
34 * http://www.wowza.com/forums/content.php?55-How-to-format-Adobe-Flash-RTMP-URLs and http://docs.aws.amazon.com/
35 * AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html
36 */
37 public class WowzaResourceStrategyImpl implements ResourceStrategy {
38 /** Regex pattern that matches something like mp4:path/to/resource/video */
39 private static final String FIND_STREAM_FORMAT = ".{3}[:].*$";
40 /** The URI scheme that an RTMP address uses. */
41 private static final String RTMP_SCHEME = "rtmp";
42 /** The URI scheme that an http address uses. */
43 private static final String ADAPTIVESTREAMING_HTTP_SCHEME = "http";
44 /** The URI scheme that an https address uses. */
45 private static final String ADAPTIVESTREAMING_HTTPS_SCHEME = "https";
46 /** The possible delimiter between the server & application and the stream path and file. */
47 private static final String WOWZA_STREAM_DELIMITER = "_definst_";
48
49 /**
50 * Transform a base URI into a proper stream location without the host and application name.
51 *
52 * @param baseUri
53 * The full URI to the resource including the host and application.
54 * @return A safe standard RTMP or HTTP resource location.
55 */
56 @Override
57 public String getResource(String baseUri) {
58 try {
59 URI uri = new URI(baseUri);
60 String scheme = uri.getScheme();
61
62 if (ADAPTIVESTREAMING_HTTP_SCHEME.equals(scheme)
63 || ADAPTIVESTREAMING_HTTPS_SCHEME.equals(scheme)) {
64 return getHTTPResource(uri);
65 } else if (RTMP_SCHEME.equals(scheme)) {
66 return getRTMPResource(uri);
67 } else {
68 //return getHTTPResource(uri);
69 throw new IllegalArgumentException(WowzaResourceStrategyImpl.class.getSimpleName()
70 + " is unable to sign urls with scheme " + scheme);
71 }
72 } catch (URISyntaxException e) {
73 throw new IllegalStateException(e);
74 }
75 }
76
77 /**
78 * Transform a base URI into a proper stream location without the host and application name.
79 *
80 * @param baseUri
81 * The full URI to the resource including the host and application.
82 * @return A safe standard RTMP resource location.
83 */
84 protected static String getRTMPResource(URI baseUri) {
85 String stream = null;
86 if (baseUri.toString().contains(WOWZA_STREAM_DELIMITER)) {
87 // There is the explicit delimiter so return the stream as the resource.
88 stream = baseUri.toString().split(WOWZA_STREAM_DELIMITER)[1];
89 if (stream.charAt(0) == '/') {
90 return stream.substring(1);
91 }
92 return stream;
93 } else if (baseUri.getPath().contains(":")) {
94 // The path contains a ":" denoting the type e.g. mp4 which is always the start of the stream path.
95 Pattern pattern = Pattern.compile(FIND_STREAM_FORMAT);
96 Matcher matcher = pattern.matcher(baseUri.getPath());
97 if (matcher.find()) {
98 return baseUri.getPath().substring(matcher.start())
99 + (StringUtils.isNotBlank(baseUri.getQuery()) ? "?" + baseUri.getQuery() : "");
100 }
101 }
102 // There are no special delimiters so assume the first value between two forward slashes (/.../) is the application.
103 return baseUri.getPath().substring(baseUri.getPath().indexOf("/", 1) + 1)
104 + (StringUtils.isNotBlank(baseUri.getQuery()) ? "?" + baseUri.getQuery() : "");
105 }
106 /**
107 * Transform a base URI into a proper stream location without the host.
108 *
109 * @param baseUri
110 * The full URI to the resource including the host and application.
111 * @return A safe standard RTMP resource location.
112 */
113 protected static String getHTTPResource(URI baseUri) {
114 // There are no special delimiters so assume the first value between two forward slashes (/.../) is the application.
115 return baseUri.getPath().substring(baseUri.getPath().indexOf("/") + 1, baseUri.getPath().lastIndexOf("/"));
116 }
117 }