HttpInstallerpublic class HttpInstaller extends Installer An Installer allowing to install a midlet suite from an http server.
If the midlet suite is given by a descriptor file, the jar URL
specified in the descriptor must have an "http" or "https" scheme. |
Fields Summary |
---|
private static final int | MAX_DL_SIZEMax number of bytes to download at one time (1K). | private static final String | BASIC_TAGTag that signals that the HTTP server supports basic auth. | private javax.microedition.io.HttpConnection | httpConnectionHTTP connection to close when we stop the installation. | private InputStream | httpInputStreamHTTP stream to close when we stop the installation. |
Constructors Summary |
---|
public HttpInstaller()Constructor of the HttpInstaller.
super();
|
Methods Summary |
---|
private void | checkIfBasicAuthSupported(java.lang.String wwwAuthField)Checks to make sure the HTTP server will support Basic authentication.
if (wwwAuthField != null) {
wwwAuthField = wwwAuthField.trim();
if (wwwAuthField.regionMatches(true, 0, BASIC_TAG, 0,
BASIC_TAG.length())) {
return;
}
}
throw new InvalidJadException(InvalidJadException.CANNOT_AUTH);
| protected byte[] | downloadJAD()Downloads an application descriptor file from the given URL.
String[] encoding = new String[1];
ByteArrayOutputStream bos = new ByteArrayOutputStream(MAX_DL_SIZE);
String[] acceptableTypes = {JAD_MT};
String[] extraFieldKeys = new String[3];
String[] extraFieldValues = new String[3];
String locale;
String prof = System.getProperty(MICROEDITION_PROFILES);
int space = prof.indexOf(' ");
if (space != -1) {
prof = prof.substring(0, space);
}
extraFieldKeys[0] = "User-Agent";
extraFieldValues[0] = "Profile/" + prof
+ " Configuration/" +
System.getProperty(MICROEDITION_CONFIG);
extraFieldKeys[1] = "Accept-Charset";
extraFieldValues[1] = "UTF-8, ISO-8859-1";
/* locale can be null */
locale = System.getProperty(MICROEDITION_LOCALE);
if (locale != null) {
extraFieldKeys[2] = "Accept-Language";
extraFieldValues[2] = locale;
}
state.beginTransferDataStatus = DOWNLOADING_JAD;
state.transferStatus = DOWNLOADED_1K_OF_JAD;
/*
* Do not send the list of acceptable types because some servers
* will send a 406 if the URL is to a JAR. It is better to
* reject the resource at the client after check the media-type so
* if the type is JAR a JAR only install can be performed.
*/
downloadResource(info.jadUrl, extraFieldKeys,
extraFieldValues,
acceptableTypes, false, false, bos, encoding,
InvalidJadException.INVALID_JAD_URL,
InvalidJadException.JAD_SERVER_NOT_FOUND,
InvalidJadException.JAD_NOT_FOUND,
InvalidJadException.INVALID_JAD_TYPE);
state.jadEncoding = encoding[0];
return bos.toByteArray();
| protected int | downloadJAR(java.lang.String filename)Downloads an application archive file from the given URL into the
given file. Automatically handle re-tries.
HttpUrl parsedUrl;
String url;
String[] acceptableTypes = {JAR_MT_1, JAR_MT_2};
String[] extraFieldKeys = new String[3];
String[] extraFieldValues = new String[3];
int jarSize;
String locale;
String prof;
int space;
RandomAccessStream jarOutputStream = null;
OutputStream outputStream = null;
parsedUrl = new HttpUrl(info.jarUrl);
if (parsedUrl.authority == null && info.jadUrl != null) {
// relative URL, add the JAD URL as the base
try {
parsedUrl.addBaseUrl(info.jadUrl);
} catch (IOException e) {
postInstallMsgBackToProvider(
OtaNotifier.INVALID_JAD_MSG);
throw new InvalidJadException(
InvalidJadException.INVALID_JAR_URL);
}
url = parsedUrl.toString();
// The JAR URL saved to storage MUST be absolute
info.jarUrl = url;
} else {
url = info.jarUrl;
}
jarOutputStream = new RandomAccessStream();
jarOutputStream.connect(filename,
RandomAccessStream.READ_WRITE_TRUNCATE);
outputStream = jarOutputStream.openOutputStream();
prof = System.getProperty(MICROEDITION_PROFILES);
space = prof.indexOf(' ");
if (space != -1) {
prof = prof.substring(0, space);
}
extraFieldKeys[0] = "User-Agent";
extraFieldValues[0] = "Profile/" + prof
+ " Configuration/" +
System.getProperty(MICROEDITION_CONFIG);
extraFieldKeys[1] = "Accept-Charset";
extraFieldValues[1] = "UTF-8, ISO-8859-1";
/* locale can be null */
locale = System.getProperty(MICROEDITION_LOCALE);
if (locale != null) {
extraFieldKeys[2] = "Accept-Language";
extraFieldValues[2] = locale;
}
try {
state.beginTransferDataStatus = DOWNLOADING_JAR;
state.transferStatus = DOWNLOADED_1K_OF_JAR;
jarSize = downloadResource(url, extraFieldKeys, extraFieldValues,
acceptableTypes, true, true, outputStream, null,
InvalidJadException.INVALID_JAR_URL,
InvalidJadException.JAR_SERVER_NOT_FOUND,
InvalidJadException.JAR_NOT_FOUND,
InvalidJadException.INVALID_JAR_TYPE);
return jarSize;
} catch (InvalidJadException ije) {
switch (ije.getReason()) {
case InvalidJadException.INVALID_JAR_URL:
case InvalidJadException.JAR_SERVER_NOT_FOUND:
case InvalidJadException.JAR_NOT_FOUND:
case InvalidJadException.INVALID_JAR_TYPE:
postInstallMsgBackToProvider(
OtaNotifier.INVALID_JAR_MSG);
break;
default:
// for safety/completeness.
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_AMS,
"Installer InvalidJadException: " + ije.getMessage());
}
break;
}
throw ije;
} finally {
try {
jarOutputStream.disconnect();
} catch (Exception e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_AMS,
"disconnect threw a Exception");
}
}
}
| private int | downloadResource(java.lang.String url, java.lang.String[] extraFieldKeys, java.lang.String[] extraFieldValues, java.lang.String[] acceptableTypes, boolean sendAcceptableTypes, boolean allowNoMediaType, java.io.OutputStream output, java.lang.String[] encoding, int invalidURLCode, int serverNotFoundCode, int resourceNotFoundCode, int invalidMediaTypeCode)Downloads an resource from the given URL into the output stream.
Connection conn = null;
StringBuffer acceptField;
int responseCode;
String retryAfterField;
int retryInterval;
String mediaType;
try {
for (; ; ) {
try {
conn = Connector.open(url, Connector.READ);
} catch (IllegalArgumentException e) {
throw new InvalidJadException(invalidURLCode, url);
} catch (ConnectionNotFoundException e) {
// protocol not found
throw new InvalidJadException(invalidURLCode, url);
}
if (!(conn instanceof HttpConnection)) {
// only HTTP or HTTPS are supported
throw new InvalidJadException(invalidURLCode, url);
}
httpConnection = (HttpConnection)conn;
if (extraFieldKeys != null) {
for (int i = 0; i < extraFieldKeys.length &&
extraFieldKeys[i] != null; i++) {
httpConnection.setRequestProperty(extraFieldKeys[i],
extraFieldValues[i]);
}
}
// 256 is given to avoid resizing without adding lengths
acceptField = new StringBuffer(256);
if (sendAcceptableTypes) {
// there must be one or more acceptable media types
acceptField.append(acceptableTypes[0]);
for (int i = 1; i < acceptableTypes.length; i++) {
acceptField.append(", ");
acceptField.append(acceptableTypes[i]);
}
} else {
/* Send at least a wildcard to satisfy WAP gateways. */
acceptField.append("*/*");
}
httpConnection.setRequestProperty("Accept",
acceptField.toString());
httpConnection.setRequestMethod(HttpConnection.GET);
if (state.username != null &&
state.password != null) {
httpConnection.setRequestProperty("Authorization",
formatAuthCredentials(state.username,
state.password));
}
if (state.proxyUsername != null &&
state.proxyPassword != null) {
httpConnection.setRequestProperty("Proxy-Authorization",
formatAuthCredentials(state.proxyUsername,
state.proxyPassword));
}
try {
responseCode = httpConnection.getResponseCode();
} catch (IOException ioe) {
if (httpConnection.getHost() == null) {
throw new InvalidJadException(invalidURLCode, url);
}
throw new InvalidJadException(serverNotFoundCode, url);
}
if (responseCode != HttpConnection.HTTP_UNAVAILABLE) {
break;
}
retryAfterField = httpConnection.getHeaderField("Retry-After");
if (retryAfterField == null) {
break;
}
try {
/*
* see if the retry interval is in seconds, and
* not an absolute date
*/
retryInterval = Integer.parseInt(retryAfterField);
if (retryInterval > 0) {
if (retryInterval > 60) {
// only wait 1 min
retryInterval = 60;
}
Thread.sleep(retryInterval * 1000);
}
} catch (InterruptedException ie) {
// ignore thread interrupt
break;
} catch (NumberFormatException ne) {
// ignore bad format
break;
}
httpConnection.close();
if (state.stopInstallation) {
postInstallMsgBackToProvider(
OtaNotifier.USER_CANCELLED_MSG);
throw new IOException("stopped");
}
} // end for
if (responseCode == HttpConnection.HTTP_NOT_FOUND) {
throw new InvalidJadException(resourceNotFoundCode);
}
if (responseCode == HttpConnection.HTTP_NOT_ACCEPTABLE) {
throw new InvalidJadException(invalidMediaTypeCode, "");
}
if (responseCode == HttpConnection.HTTP_UNAUTHORIZED) {
// automatically throws the correct exception
checkIfBasicAuthSupported(
httpConnection.getHeaderField("WWW-Authenticate"));
state.exception =
new InvalidJadException(InvalidJadException.UNAUTHORIZED);
return 0;
}
if (responseCode == HttpConnection.HTTP_PROXY_AUTH) {
// automatically throws the correct exception
checkIfBasicAuthSupported(
httpConnection.getHeaderField("WWW-Authenticate"));
state.exception =
new InvalidJadException(InvalidJadException.PROXY_AUTH);
return 0;
}
if (responseCode != HttpConnection.HTTP_OK) {
throw new IOException("Failed to download " + url +
" HTTP response code: " + responseCode);
}
mediaType = Util.getHttpMediaType(httpConnection.getType());
if (mediaType != null) {
boolean goodType = false;
for (int i = 0; i < acceptableTypes.length; i++) {
if (mediaType.equals(acceptableTypes[i])) {
goodType = true;
break;
}
}
if (!goodType) {
throw new InvalidJadException(invalidMediaTypeCode,
mediaType);
}
} else if (!allowNoMediaType) {
throw new InvalidJadException(invalidMediaTypeCode, "");
}
if (encoding != null) {
encoding[0] = getCharset(httpConnection.getType());
}
httpInputStream = httpConnection.openInputStream();
return transferData(httpInputStream, output, MAX_DL_SIZE);
} finally {
// Close the streams or connections this method opened.
try {
httpInputStream.close();
} catch (Exception e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_AMS,
"stream close threw an Exception");
}
}
try {
conn.close();
} catch (Exception e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_AMS,
"connection close threw an Exception");
}
}
}
| private static java.lang.String | formatAuthCredentials(java.lang.String username, java.lang.String password)Formats the username and password for HTTP basic authentication
according RFC 2617.
byte[] data = new byte[username.length() + password.length() + 1];
int j = 0;
for (int i = 0; i < username.length(); i++, j++) {
data[j] = (byte)username.charAt(i);
}
data[j] = (byte)':";
j++;
for (int i = 0; i < password.length(); i++, j++) {
data[j] = (byte)password.charAt(i);
}
return "Basic " + Base64.encode(data, 0, data.length);
| private static java.lang.String | getCharset(java.lang.String contentType)Parses out the charset from the content-type field.
The charset parameter is after the ';' in the content-type field.
int start;
int end;
if (contentType == null) {
return null;
}
start = contentType.indexOf("charset");
if (start < 0) {
return null;
}
start = contentType.indexOf('=", start);
if (start < 0) {
return null;
}
// start past the '='
start++;
end = contentType.indexOf(';", start);
if (end < 0) {
end = contentType.length();
}
return contentType.substring(start, end).trim();
| protected boolean | isSameUrl(java.lang.String url1, java.lang.String url2)Compares two URLs for equality in sense that they have the same
scheme, host and path.
HttpUrl newUrl;
HttpUrl originalUrl;
try {
newUrl = new HttpUrl(url1);
originalUrl = new HttpUrl(url2);
if (newUrl.scheme.equals(originalUrl.scheme) &&
newUrl.host.equals(originalUrl.host) &&
newUrl.path.equals(originalUrl.path)) {
return true;
}
} catch (NullPointerException npe) {
// no match, fall through
}
return false;
| public boolean | stopInstalling()Stops the installation. If installer is not installing then this
method has no effect. This will cause the install method to
throw an IOException if the install is not writing the suite
to storage which is the point of no return.
boolean res = super.stopInstalling();
if (!res) {
return res;
}
try {
httpInputStream.close();
} catch (Exception e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_AMS,
"stream close threw an Exception");
}
}
try {
httpConnection.close();
} catch (Exception e) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_AMS,
"stream close threw an Exception");
}
}
return true;
|
|