/*
* ServeStream: A HTTP stream browser/player for Android
* Copyright 2010 William Seemann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.servestream.transport;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Map;
import net.sourceforge.servestream.bean.UriBean;
import net.sourceforge.servestream.database.StreamDatabase;
import net.sourceforge.servestream.utils.Utils;
import android.net.Uri;
public class HTTP extends AbsTransport {
private static final String PROTOCOL = "http";
private static final int DEFAULT_PORT = 80;
private HttpURLConnection conn = null;
private InputStream is = null;
private int mResponseCode = -1;
private String mContentType = null;
public HTTP() {
super();
}
public HTTP(UriBean uri) {
super(uri);
}
public static String getProtocolName() {
return PROTOCOL;
}
protected String getPrivateProtocolName() {
return PROTOCOL;
}
/**
* Encode the current transport into a URI that can be passed via intent calls.
* @return URI to host
*/
public static Uri getUri(String input) {
return getUri(input, false);
}
/**
* Encode the current transport into a URI that can be passed via intent calls.
* @return URI to host
*/
private static Uri getUri(String input, boolean scrubUri) {
if (input == null) {
return null;
}
String hostname = null;
int port = -1;
try {
input = URLDecoder.decode(input, "UTF-8");
} catch (UnsupportedEncodingException e1) {
return null;
}
URL url = null;
try {
url = new URL(input);
} catch (MalformedURLException e) {
return null;
}
// the following code is used as a temporary fix to deal with Android's
// handling of URL's that contain "special characters" such as "[" (Issue 12724)
String [] split = url.getHost().split("\\:");
if (split.length == 2) {
hostname = split[0];
port = Integer.valueOf(split[1]);
}
StringBuilder sb = new StringBuilder();
sb.append(PROTOCOL)
.append("://");
if (!scrubUri) {
if (url.getUserInfo() != null) {
String [] authInfo = url.getUserInfo().split("\\:");
if (authInfo.length == 2) {
sb.append(authInfo[0])
.append(":")
.append(authInfo[1])
.append("@");
}
}
}
if (hostname != null) {
sb.append(hostname)
.append(":");
} else {
sb.append(url.getHost())
.append(":");
}
if (port != -1) {
sb.append(port);
} else {
if (url.getPort() == -1) {
sb.append(DEFAULT_PORT);
} else {
sb.append(url.getPort());
}
}
sb.append(url.getPath());
if (url.getQuery() != null) {
sb.append("?")
.append(url.getQuery());
}
if (url.getRef() != null) {
sb.append("#")
.append(url.getRef());
}
Uri uri = Uri.parse(sb.toString());
return uri;
}
@Override
public void connect() throws IOException {
URL url = null;
final String username = uri.getUsername();
final String password = uri.getPassword();
if (username != null && password != null) {
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
};
});
url = uri.getScrubbedURL();
} else {
url = uri.getURL();
}
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6000);
conn.setReadTimeout(6000);
conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "ServeStream");
mResponseCode = conn.getResponseCode();
if (mResponseCode == -1) {
mResponseCode = HttpURLConnection.HTTP_OK;
}
mContentType = conn.getContentType();
is = conn.getInputStream();
}
@Override
public void close() {
Utils.closeInputStream(is);
Utils.closeHttpConnection(conn);
}
@Override
public boolean exists() {
return true;
}
@Override
public boolean isConnected() {
return is != null;
}
@Override
public int getDefaultPort() {
return DEFAULT_PORT;
}
@Override
public void getSelectionArgs(Uri uri, Map<String, String> selection) {
selection.put(StreamDatabase.FIELD_STREAM_PROTOCOL, PROTOCOL);
if (uri.getUserInfo() != null) {
String [] authInfo = uri.getUserInfo().split("\\:");
if (authInfo.length == 2) {
selection.put(StreamDatabase.FIELD_STREAM_USERNAME, authInfo[0]);
selection.put(StreamDatabase.FIELD_STREAM_PASSWORD, authInfo[1]);
}
} else {
selection.put(StreamDatabase.FIELD_STREAM_USERNAME, null);
selection.put(StreamDatabase.FIELD_STREAM_PASSWORD, null);
}
selection.put(StreamDatabase.FIELD_STREAM_HOSTNAME, uri.getHost());
int port = uri.getPort();
if (port < 0)
port = DEFAULT_PORT;
selection.put(StreamDatabase.FIELD_STREAM_PORT, Integer.toString(port));
if (uri.getPath() != null) {
selection.put(StreamDatabase.FIELD_STREAM_PATH, uri.getPath());
}
selection.put(StreamDatabase.FIELD_STREAM_QUERY, uri.getQuery());
selection.put(StreamDatabase.FIELD_STREAM_REFERENCE, uri.getFragment());
}
@Override
public UriBean createUri(Uri uri) {
UriBean host = new UriBean();
host.setProtocol(PROTOCOL);
if (uri.getUserInfo() != null) {
String [] authInfo = uri.getUserInfo().split("\\:");
if (authInfo.length == 2) {
host.setUsername(authInfo[0]);
host.setPassword(authInfo[1]);
}
}
host.setHostname(uri.getHost());
int port = uri.getPort();
if (port < 0)
port = DEFAULT_PORT;
host.setPort(port);
host.setPath(uri.getPath());
host.setQuery(uri.getQuery());
host.setReference(uri.getFragment());
String nickname = getUri(uri.toString(), true).toString();
host.setNickname(nickname);
return host;
}
@Override
public String getContentType() {
return mContentType;
}
@Override
public boolean usesNetwork() {
return true;
}
@Override
public InputStream getConnection() {
return is;
}
@Override
public boolean isPotentialPlaylist() {
return true;
}
}