blob: c1326b6d6ce497f5b58f1712175a4671dd60daab [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 com.googlecode.android_scripting.facade.wifi;
import com.googlecode.android_scripting.FileUtils;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.facade.FacadeManager;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcOptional;
import com.googlecode.android_scripting.rpc.RpcParameter;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
/**
* Basic http operations.
*/
public class HttpFacade extends RpcReceiver {
private ServerSocket mServerSocket = null;
private int mServerTimeout = -1;
private HashMap<Integer, Socket> mSockets = null;
private int socketCnt = 0;
public HttpFacade(FacadeManager manager) throws IOException {
super(manager);
mSockets = new HashMap<Integer, Socket>();
}
private void inputStreamToOutputStream(InputStream in, OutputStream out) throws IOException {
if (in == null) {
Log.e("InputStream is null.");
return;
}
if (out == null) {
Log.e("OutputStream is null.");
return;
}
try {
int read = 0;
byte[] bytes = new byte[1024];
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
in.close();
out.close();
}
}
private String inputStreamToString(InputStream in) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
String str = null;
while ((str = r.readLine()) != null) {
sb.append(str);
}
r.close();
return sb.toString();
}
/**
* Send an http request and get the response.
*
* @param url The url to send request to.
* @param timeout Time to load the page
* @return The HttpURLConnection object.
*/
private HttpURLConnection httpRequest(String url, Integer timeout) throws IOException {
if (timeout == null) {
timeout = 50000;
}
URL targetURL = new URL(url);
HttpURLConnection urlConnection;
try {
urlConnection = (HttpURLConnection) targetURL.openConnection();
urlConnection.setConnectTimeout(9000);
urlConnection.setReadTimeout(timeout);
urlConnection.connect();
int respCode = urlConnection.getResponseCode();
String respMsg = urlConnection.getResponseMessage();
Log.d("Got response code: " + respCode + " and response msg: " + respMsg);
} catch (IOException e) {
Log.e("Failed to open a connection to " + url);
Log.e(e.toString());
throw e;
}
return urlConnection;
}
@Rpc(description = "Start waiting for a connection request on a specified port.",
returns = "The index of the connection.")
public Integer httpAcceptConnection(@RpcParameter(name = "port") Integer port) throws IOException {
mServerSocket = new ServerSocket(port);
if (mServerTimeout > 0) {
mServerSocket.setSoTimeout(mServerTimeout);
}
Socket sock = mServerSocket.accept();
socketCnt += 1;
mSockets.put(socketCnt, sock);
return socketCnt;
}
@Rpc(description = "Download a file from specified url, to an (optionally) specified path.")
public void httpDownloadFile(@RpcParameter(name = "url") String url,
@RpcParameter(name="outPath") @RpcOptional String outPath) throws IOException {
// Create the input stream
HttpURLConnection urlConnection = httpRequest(url, null);
// Parse destination path and create the output stream. The function assumes that the path
// is specified relative to the system default Download dir.
File outFile = FileUtils.getExternalDownload();
if (outPath != null && outPath.trim().length() != 0) {
// Check to see if the path is absolute.
if (outPath.startsWith("/")) {
outFile = new File(outPath);
} else {
outFile = new File(outFile, outPath);
}
// Check to see if specified path should be a dir.
if (outPath.endsWith("/")) {
if (!outFile.isDirectory() && !outFile.mkdirs()) {
throw new IOException("Failed to create the path: " + outPath);
}
}
}
// If no filename was specified, use the filename provided by the server.
if (outFile.isDirectory()) {
String filename = "";
String contentDisposition = urlConnection.getHeaderField("Content-Disposition");
// Try to figure out the name of the file being downloaded.
// If the server returned a filename, use it.
if (contentDisposition != null) {
int idx = contentDisposition.toLowerCase().indexOf("filename");
if (idx != -1) {
filename = contentDisposition.substring(idx + 9);
Log.d("Using filename returned by server: " + filename);
}
}
// If the server did not provide a filename to us, use the last part of url.
if (filename.trim().length() == 0) {
int lastIdx = url.lastIndexOf('/');
filename = url.substring(lastIdx + 1);
Log.d("Using name from url: " + filename);
}
outFile = new File(outFile, filename);
}
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
OutputStream output = new FileOutputStream(outFile);
inputStreamToOutputStream(in, output);
Log.d("Downloaded file from " + url + " to " + outPath);
urlConnection.disconnect();
}
@Rpc(description = "Make an http request and return the response message.")
public HttpURLConnection httpPing(
@RpcParameter(name = "url") String url,
@RpcParameter(name = "timeout") @RpcOptional Integer timeout) throws IOException {
HttpURLConnection urlConnection = null;
urlConnection = httpRequest(url, timeout);
urlConnection.disconnect();
return urlConnection;
}
@Rpc(description = "Make an http request and return the response content as a string.")
public String httpRequestString(@RpcParameter(name = "url") String url) throws IOException {
HttpURLConnection urlConnection = httpRequest(url, null);
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
String result = inputStreamToString(in);
Log.d("Fetched: " + result);
urlConnection.disconnect();
return result;
}
@Rpc(description = "Set how many milliseconds to wait for an incoming connection.")
public void httpSetServerTimeout(@RpcParameter(name = "timeout") Integer timeout)
throws SocketException {
mServerSocket.setSoTimeout(timeout);
mServerTimeout = timeout;
}
@Rpc(description = "Ping to host(URL or IP), return success (true) or fail (false).")
// The optional timeout parameter is in unit of second.
public Boolean pingHost(@RpcParameter(name = "host") String hostString,
@RpcParameter(name = "timeout") @RpcOptional Integer timeout,
@RpcParameter(name = "ping") @RpcOptional String pingType) {
try {
String host;
try {
URL url = new URL(hostString);
host = url.getHost();
} catch (java.net.MalformedURLException e) {
Log.d("hostString is not URL, it may be IP address.");
host = hostString;
}
Log.d("Host:" + host);
String pingCmdString = "ping -c 1 ";
if(pingType!=null && pingType.equals("ping6")) {
pingCmdString = "ping6 -c 1 ";
}
if (timeout != null) {
pingCmdString = pingCmdString + "-W " + timeout + " ";
}
pingCmdString = pingCmdString + host;
Log.d("Execute command: " + pingCmdString);
Process p1 = java.lang.Runtime.getRuntime().exec(pingCmdString);
int returnVal = p1.waitFor();
boolean reachable = (returnVal == 0);
Log.d("Ping return Value:" + returnVal);
return reachable;
} catch (Exception e){
e.printStackTrace();
return false;
}
/*TODO see b/18899134 for more information.
*/
}
@Override
public void shutdown() {
for (int key : mSockets.keySet()) {
Socket sock = mSockets.get(key);
try {
sock.close();
} catch (IOException e) {
Log.e("Failed to close socket " + key + " on port " + sock.getLocalPort());
e.printStackTrace();
}
}
}
}