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