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;
    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             throw e;
    114         }
    115         return urlConnection;
    116     }
    117 
    118     @Rpc(description = "Start waiting for a connection request on a specified port.",
    119             returns = "The index of the connection.")
    120     public Integer httpAcceptConnection(@RpcParameter(name = "port") Integer port) throws IOException {
    121         mServerSocket = new ServerSocket(port);
    122         if (mServerTimeout > 0) {
    123             mServerSocket.setSoTimeout(mServerTimeout);
    124         }
    125         Socket sock = mServerSocket.accept();
    126         socketCnt += 1;
    127         mSockets.put(socketCnt, sock);
    128         return socketCnt;
    129     }
    130 
    131     @Rpc(description = "Download a file from specified url, to an (optionally) specified path.")
    132     public void httpDownloadFile(@RpcParameter(name = "url") String url,
    133             @RpcParameter(name="outPath") @RpcOptional String outPath) throws IOException {
    134         // Create the input stream
    135         HttpURLConnection urlConnection = httpRequest(url);
    136         // Parse destination path and create the output stream. The function assumes that the path
    137         // is specified relative to the system default Download dir.
    138         File outFile = FileUtils.getExternalDownload();
    139         if (outPath != null && outPath.trim().length() != 0) {
    140             // Check to see if the path is absolute.
    141             if (outPath.startsWith("/")) {
    142                 outFile = new File(outPath);
    143             } else {
    144                 outFile = new File(outFile, outPath);
    145             }
    146             // Check to see if specified path should be a dir.
    147             if (outPath.endsWith("/")) {
    148                 if (!outFile.isDirectory() && !outFile.mkdirs()) {
    149                     throw new IOException("Failed to create the path: " + outPath);
    150                 }
    151             }
    152         }
    153         // If no filename was specified, use the filename provided by the server.
    154         if (outFile.isDirectory()) {
    155             String filename = "";
    156             String contentDisposition = urlConnection.getHeaderField("Content-Disposition");
    157             // Try to figure out the name of the file being downloaded.
    158             // If the server returned a filename, use it.
    159             if (contentDisposition != null) {
    160                 int idx = contentDisposition.toLowerCase().indexOf("filename");
    161                 if (idx != -1) {
    162                     filename = contentDisposition.substring(idx + 9);
    163                     Log.d("Using filename returned by server: " + filename);
    164                 }
    165             }
    166             // If the server did not provide a filename to us, use the last part of url.
    167             if (filename.trim().length() == 0) {
    168                int lastIdx = url.lastIndexOf('/');
    169                 filename = url.substring(lastIdx + 1);
    170                 Log.d("Using name from url: " + filename);
    171             }
    172             outFile = new File(outFile, filename);
    173         }
    174         InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    175         OutputStream output = new FileOutputStream(outFile);
    176         inputStreamToOutputStream(in, output);
    177         Log.d("Downloaded file from " + url + " to " + outPath);
    178         urlConnection.disconnect();
    179     }
    180 
    181     @Rpc(description = "Make an http request and return the response message.")
    182     public HttpURLConnection httpPing(@RpcParameter(name = "url") String url) throws IOException {
    183         try {
    184             HttpURLConnection urlConnection = null;
    185             urlConnection = httpRequest(url);
    186             urlConnection.disconnect();
    187             return urlConnection;
    188         } catch (UnknownHostException e) {
    189             return null;
    190         }
    191     }
    192 
    193     @Rpc(description = "Make an http request and return the response content as a string.")
    194     public String httpRequestString(@RpcParameter(name = "url") String url) throws IOException {
    195         HttpURLConnection urlConnection = httpRequest(url);
    196         InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    197         String result = inputStreamToString(in);
    198         Log.d("Fetched: " + result);
    199         urlConnection.disconnect();
    200         return result;
    201     }
    202 
    203     @Rpc(description = "Set how many milliseconds to wait for an incoming connection.")
    204     public void httpSetServerTimeout(@RpcParameter(name = "timeout") Integer timeout)
    205             throws SocketException {
    206         mServerSocket.setSoTimeout(timeout);
    207         mServerTimeout = timeout;
    208     }
    209 
    210     @Rpc(description = "Ping to host(URL or IP), return success (true) or fail (false).")
    211     // The optional timeout parameter is in unit of second.
    212     public Boolean pingHost(@RpcParameter(name = "host") String hostString,
    213             @RpcParameter(name = "timeout") @RpcOptional Integer timeout,
    214             @RpcParameter(name = "ping") @RpcOptional String pingType) {
    215         try {
    216             String host;
    217             try {
    218                 URL url = new URL(hostString);
    219                 host = url.getHost();
    220             } catch (java.net.MalformedURLException e) {
    221                 Log.d("hostString is not URL, it may be IP address.");
    222                 host = hostString;
    223             }
    224 
    225             Log.d("Host:" + host);
    226             String pingCmdString = "ping -c 1 ";
    227             if(pingType!=null && pingType.equals("ping6")) {
    228                 pingCmdString = "ping6 -c 1 ";
    229             }
    230             if (timeout != null) {
    231                 pingCmdString = pingCmdString + "-W " + timeout + " ";
    232             }
    233             pingCmdString = pingCmdString + host;
    234             Log.d("Execute command: " + pingCmdString);
    235             Process p1 = java.lang.Runtime.getRuntime().exec(pingCmdString);
    236             int returnVal = p1.waitFor();
    237             boolean reachable = (returnVal == 0);
    238             Log.d("Ping return Value:" + returnVal);
    239             return reachable;
    240         } catch (Exception e){
    241             e.printStackTrace();
    242             return false;
    243         }
    244         /*TODO see b/18899134 for more information.
    245         */
    246     }
    247 
    248     @Override
    249     public void shutdown() {
    250         for (int key : mSockets.keySet()) {
    251             Socket sock = mSockets.get(key);
    252             try {
    253                 sock.close();
    254             } catch (IOException e) {
    255                 Log.e("Failed to close socket " + key + " on port " + sock.getLocalPort());
    256                 e.printStackTrace();
    257             }
    258         }
    259     }
    260 }
    261