package com.mobiperf.util; import com.mobiperf.Logger; import android.content.Context; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.Reader; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.zip.GZIPInputStream; import org.apache.http.Header; import org.apache.http.HeaderElement; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.ParseException; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public class MLabNS { /** Used by measurement tests if MLabNS should be used to retrieve the real server target. */ static public final String TARGET = "mlab"; /** * Query MLab-NS to get an FQDN for the given tool. */ static public ArrayList<String> Lookup(Context context, String tool) { return Lookup(context, tool, null, "fqdn"); } /** * Query MLab-NS to get an FQDN/IP for the given tool and address family. * @param field: fqdn or ip */ static public ArrayList<String> Lookup(Context context, String tool, String address_family, String field) { final int maxResponseSize = 1024; // Set the timeout in milliseconds until a connection is established. final int timeoutConnection = 5000; // Set the socket timeout in milliseconds. final int timeoutSocket = 5000; ByteBuffer body = ByteBuffer.allocate(maxResponseSize); InputStream inputStream = null; // Sanitize for possible returned field if ( field != "fqdn" && field != "ip" ) { return null; } try { HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters); Logger.d("Creating request GET for mlab-ns"); String url = "http://mlab-ns.appspot.com/" + tool + "?format=json"; if (address_family == "ipv4" || address_family == "ipv6") { url += "&address_family=" + address_family; } HttpGet request = new HttpGet(url); request.setHeader("User-Agent", Util.prepareUserAgent(context)); HttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() != 200) { throw new InvalidParameterException( "Received status " + response.getStatusLine().getStatusCode() + " from mlab-ns"); } Logger.d("STATUS OK"); String body_str = getResponseBody(response); JSONObject json = new JSONObject(body_str); Logger.d("Field Type is " + json.get(field).getClass().getName()); ArrayList<String> mlabNSResult = new ArrayList<String>(); if (json.get(field) instanceof JSONArray) { // Convert array value into ArrayList JSONArray jsonArray = (JSONArray)json.get(field); for (int i = 0; i < jsonArray.length(); i++) { mlabNSResult.add(jsonArray.get(i).toString()); } } else if (json.get(field) instanceof String) { // Append the string into ArrayList mlabNSResult.add(String.valueOf(json.getString(field))); } else { throw new InvalidParameterException("Unknown type " + json.get(field).getClass().toString() + " of value " + json.get(field)); } return mlabNSResult; } catch (SocketTimeoutException e) { Logger.e("SocketTimeoutException trying to contact m-lab-ns"); // e.getMessage() is null throw new InvalidParameterException("Connect to m-lab-ns timeout. Please try again."); } catch (IOException e) { Logger.e("IOException trying to contact m-lab-ns: " + e.getMessage()); throw new InvalidParameterException(e.getMessage()); } catch (JSONException e) { Logger.e("JSONException trying to contact m-lab-ns: " + e.getMessage()); throw new InvalidParameterException(e.getMessage()); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { Logger.e("Failed to close the input stream from the HTTP response"); } } } } static private String getContentCharSet(final HttpEntity entity) throws ParseException { if (entity == null) { throw new IllegalArgumentException("entity may not be null"); } String charset = null; if (entity.getContentType() != null) { HeaderElement values[] = entity.getContentType().getElements(); if (values.length > 0) { NameValuePair param = values[0].getParameterByName("charset"); if (param != null) { charset = param.getValue(); } } } return charset; } static private String getResponseBodyFromEntity(HttpEntity entity) throws IOException, ParseException { if (entity == null) { throw new IllegalArgumentException("entity may not be null"); } InputStream instream = entity.getContent(); if (instream == null) { return ""; } if (entity.getContentEncoding() != null) { if ("gzip".equals(entity.getContentEncoding().getValue())) { instream = new GZIPInputStream(instream); } } if (entity.getContentLength() > Integer.MAX_VALUE) { throw new IllegalArgumentException("HTTP entity too large to be buffered into memory"); } String charset = getContentCharSet(entity); if (charset == null) { charset = HTTP.DEFAULT_CONTENT_CHARSET; } Reader reader = new InputStreamReader(instream, charset); StringBuilder buffer = new StringBuilder(); try { char[] tmp = new char[1024]; int l; while ((l = reader.read(tmp, 0, tmp.length)) != -1) { Logger.d(" reading: " + tmp); buffer.append(tmp); } } finally { reader.close(); } return buffer.toString(); } static private String getResponseBody(HttpResponse response) throws IllegalArgumentException { String response_text = null; HttpEntity entity = null; if (response == null) { throw new IllegalArgumentException("response may not be null"); } try { entity = response.getEntity(); response_text = getResponseBodyFromEntity(entity); } catch (ParseException e) { e.printStackTrace(); } catch (IOException e) { if (entity != null) { try { entity.consumeContent(); } catch (IOException e1) { } } } return response_text; } }