Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.googlecode.android_scripting.facade.wifi;
     18 
     19 import com.googlecode.android_scripting.FileUtils;
     20 import com.googlecode.android_scripting.Log;
     21 import com.googlecode.android_scripting.facade.FacadeManager;
     22 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
     23 import com.googlecode.android_scripting.rpc.Rpc;
     24 import com.googlecode.android_scripting.rpc.RpcOptional;
     25 import com.googlecode.android_scripting.rpc.RpcParameter;
     26 
     27 import java.io.BufferedInputStream;
     28 import java.io.BufferedReader;
     29 import java.io.File;
     30 import java.io.FileOutputStream;
     31 import java.io.IOException;
     32 import java.io.InputStream;
     33 import java.io.InputStreamReader;
     34 import java.io.OutputStream;
     35 import java.net.HttpURLConnection;
     36 import java.net.ServerSocket;
     37 import java.net.Socket;
     38 import java.net.SocketException;
     39 import java.net.URL;
     40 import java.net.UnknownHostException;
     41 import java.nio.charset.StandardCharsets;
     42 import java.util.HashMap;
     43 
     44 
     45 /**
     46  * Basic http operations.
     47  */
     48 public class HttpFacade extends RpcReceiver {
     49 
     50     private ServerSocket mServerSocket = null;
     51     private int mServerTimeout = -1;
     52     private HashMap<Integer, Socket> mSockets = null;
     53     private int socketCnt = 0;
     54 
     55     public HttpFacade(FacadeManager manager) throws IOException {
     56         super(manager);
     57         mSockets = new HashMap<Integer, Socket>();
     58     }
     59 
     60     private void inputStreamToOutputStream(InputStream in, OutputStream out) throws IOException {
     61         if (in == null) {
     62             Log.e("InputStream is null.");
     63             return;
     64         }
     65         if (out == null) {
     66             Log.e("OutputStream is null.");
     67             return;
     68         }
     69         try {
     70             int read = 0;
     71             byte[] bytes = new byte[1024];
     72             while ((read = in.read(bytes)) != -1) {
     73                 out.write(bytes, 0, read);
     74             }
     75         } catch (IOException e) {
     76             e.printStackTrace();
     77         } finally {
     78             in.close();
     79             out.close();
     80         }
     81 
     82     }
     83 
     84     private String inputStreamToString(InputStream in) throws IOException {
     85         BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
     86         StringBuilder sb = new StringBuilder();
     87         String str = null;
     88         while ((str = r.readLine()) != null) {
     89             sb.append(str);
     90         }
     91         r.close();
     92         return sb.toString();
     93     }
     94 
     95     /**
     96      * Send an http request and get the response.
     97      *
     98      * @param url The url to send request to.
     99      * @return The HttpURLConnection object.
    100      */
    101     private HttpURLConnection httpRequest(String url) throws IOException {
    102         URL targetURL = new URL(url);
    103         HttpURLConnection urlConnection = null;
    104         try {
    105             urlConnection = (HttpURLConnection) targetURL.openConnection();
    106             urlConnection.connect();
    107             int respCode = urlConnection.getResponseCode();
    108             String respMsg = urlConnection.getResponseMessage();
    109             Log.d("Got response code: " + respCode + " and response msg: " + respMsg);
    110         } catch (IOException e) {
    111             Log.e("Failed to open a connection to " + url);
    112             Log.e(e.toString());
    113         }
    114         return urlConnection;
    115     }
    116 
    117     @Rpc(description = "Start waiting for a connection request on a specified port.",
    118             returns = "The index of the connection.")
    119     public Integer httpAcceptConnection(@RpcParameter(name = "port") Integer port) throws IOException {
    120         mServerSocket = new ServerSocket(port);
    121         if (mServerTimeout > 0) {
    122             mServerSocket.setSoTimeout(mServerTimeout);
    123         }
    124         Socket sock = mServerSocket.accept();
    125         socketCnt += 1;
    126         mSockets.put(socketCnt, sock);
    127         return socketCnt;
    128     }
    129 
    130     @Rpc(description = "Download a file from specified url, to an (optionally) specified path.")
    131     public void httpDownloadFile(@RpcParameter(name = "url") String url,
    132             @RpcParameter(name="outPath") @RpcOptional String outPath) throws IOException {
    133         // Create the input stream
    134         HttpURLConnection urlConnection = httpRequest(url);
    135         // Parse destination path and create the output stream. The function assumes that the path
    136         // is specified relative to the system default Download dir.
    137         File outFile = FileUtils.getExternalDownload();
    138         if (outPath != null && outPath.trim().length() != 0) {
    139             // Check to see if the path is absolute.
    140             if (outPath.startsWith("/")) {
    141                 outFile = new File(outPath);
    142             } else {
    143                 outFile = new File(outFile, outPath);
    144             }
    145             // Check to see if specified path should be a dir.
    146             if (outPath.endsWith("/")) {
    147                 if (!outFile.isDirectory() && !outFile.mkdirs()) {
    148                     throw new IOException("Failed to create the path: " + outPath);
    149                 }
    150             }
    151         }
    152         // If no filename was specified, use the filename provided by the server.
    153         if (outFile.isDirectory()) {
    154             String filename = "";
    155             String contentDisposition = urlConnection.getHeaderField("Content-Disposition");
    156             // Try to figure out the name of the file being downloaded.
    157             // If the server returned a filename, use it.
    158             if (contentDisposition != null) {
    159                 int idx = contentDisposition.toLowerCase().indexOf("filename");
    160                 if (idx != -1) {
    161                     filename = contentDisposition.substring(idx + 9);
    162                     Log.d("Using filename returned by server: " + filename);
    163                 }
    164             }
    165             // If the server did not provide a filename to us, use the last part of url.
    166             if (filename.trim().length() == 0) {
    167                int lastIdx = url.lastIndexOf('/');
    168                 filename = url.substring(lastIdx + 1);
    169                 Log.d("Using name from url: " + filename);
    170             }
    171             outFile = new File(outFile, filename);
    172         }
    173         InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    174         OutputStream output = new FileOutputStream(outFile);
    175         inputStreamToOutputStream(in, output);
    176         Log.d("Downloaded file from " + url + " to " + outPath);
    177         urlConnection.disconnect();
    178     }
    179 
    180     @Rpc(description = "Make an http request and return the response message.")
    181     public HttpURLConnection httpPing(@RpcParameter(name = "url") String url) throws IOException {
    182         try {
    183             HttpURLConnection urlConnection = null;
    184             urlConnection = httpRequest(url);
    185             urlConnection.disconnect();
    186             return urlConnection;
    187         } catch (UnknownHostException e) {
    188             return null;
    189         }
    190     }
    191 
    192     @Rpc(description = "Make an http request and return the response content as a string.")
    193     public String httpRequestString(@RpcParameter(name = "url") String url) throws IOException {
    194         HttpURLConnection urlConnection = httpRequest(url);
    195         InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    196         String result = inputStreamToString(in);
    197         Log.d("Fetched: " + result);
    198         urlConnection.disconnect();
    199         return result;
    200     }
    201 
    202     @Rpc(description = "Set how many milliseconds to wait for an incoming connection.")
    203     public void httpSetServerTimeout(@RpcParameter(name = "timeout") Integer timeout)
    204             throws SocketException {
    205         mServerSocket.setSoTimeout(timeout);
    206         mServerTimeout = timeout;
    207     }
    208 
    209     @Rpc(description = "Ping to host(URL or IP), return success (true) or fail (false).")
    210     // The optional timeout parameter is in unit of second.
    211     public Boolean pingHost(@RpcParameter(name = "host") String hostString,
    212             @RpcParameter(name = "timeout") @RpcOptional Integer timeout,
    213             @RpcParameter(name = "ping") @RpcOptional String pingType) {
    214         try {
    215             String host;
    216             try {
    217                 URL url = new URL(hostString);
    218                 host = url.getHost();
    219             } catch (java.net.MalformedURLException e) {
    220                 Log.d("hostString is not URL, it may be IP address.");
    221                 host = hostString;
    222             }
    223 
    224             Log.d("Host:" + host);
    225             String pingCmdString = "ping -c 1 ";
    226             if(pingType!=null && pingType.equals("ping6")) {
    227                 pingCmdString = "ping6 -c 1 ";
    228             }
    229             if (timeout != null) {
    230                 pingCmdString = pingCmdString + "-W " + timeout + " ";
    231             }
    232             pingCmdString = pingCmdString + host;
    233             Log.d("Execute command: " + pingCmdString);
    234             Process p1 = java.lang.Runtime.getRuntime().exec(pingCmdString);
    235             int returnVal = p1.waitFor();
    236             boolean reachable = (returnVal == 0);
    237             Log.d("Ping return Value:" + returnVal);
    238             return reachable;
    239         } catch (Exception e){
    240             e.printStackTrace();
    241             return false;
    242         }
    243         /*TODO see b/18899134 for more information.
    244         */
    245     }
    246 
    247     @Override
    248     public void shutdown() {
    249         for (int key : mSockets.keySet()) {
    250             Socket sock = mSockets.get(key);
    251             try {
    252                 sock.close();
    253             } catch (IOException e) {
    254                 Log.e("Failed to close socket " + key + " on port " + sock.getLocalPort());
    255                 e.printStackTrace();
    256             }
    257         }
    258     }
    259 }
    260