package de.fau.cs.mad.fly.HttpClient; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URL; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Net.HttpMethods; import com.badlogic.gdx.Net.HttpRequest; import com.badlogic.gdx.Net.HttpResponse; import com.badlogic.gdx.Net.HttpResponseListener; import com.badlogic.gdx.net.HttpStatus; import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.StreamUtils; import de.fau.cs.mad.fly.profile.PlayerProfileManager; public class NetHttpsJavaImpl { static class HttpClientResponse implements HttpResponse { private HttpsURLConnection connection; private HttpStatus status; public HttpClientResponse(HttpsURLConnection connection) throws IOException { this.connection = connection; try { this.status = new HttpStatus(connection.getResponseCode()); } catch (IOException e) { this.status = new HttpStatus(-1); } } @Override public byte[] getResult() { InputStream input = getInputStream(); try { return StreamUtils.copyStreamToByteArray(input, connection.getContentLength()); } catch (IOException e) { return StreamUtils.EMPTY_BYTES; } finally { StreamUtils.closeQuietly(input); } } @Override public String getResultAsString() { InputStream input = getInputStream(); try { return StreamUtils.copyStreamToString(input, connection.getContentLength()); } catch (IOException e) { return ""; } finally { StreamUtils.closeQuietly(input); } } @Override public InputStream getResultAsStream() { return getInputStream(); } @Override public HttpStatus getStatus() { return status; } @Override public String getHeader(String name) { return connection.getHeaderField(name); } @Override public Map<String, List<String>> getHeaders() { return connection.getHeaderFields(); } private InputStream getInputStream() { try { return connection.getInputStream(); } catch (IOException e) { return connection.getErrorStream(); } } } private final ExecutorService executorService; final ObjectMap<HttpRequest, HttpsURLConnection> connections; final ObjectMap<HttpRequest, HttpResponseListener> listeners; final Lock lock; public NetHttpsJavaImpl() { executorService = Executors.newCachedThreadPool(); connections = new ObjectMap<HttpRequest, HttpsURLConnection>(); listeners = new ObjectMap<HttpRequest, HttpResponseListener>(); lock = new ReentrantLock(); } public void sendHttpRequest(final HttpRequest httpRequest, final HttpResponseListener httpResponseListener) { if (httpRequest.getUrl() == null) { httpResponseListener.failed(new GdxRuntimeException("can't process a HTTP request without URL set")); return; } try { final String method = httpRequest.getMethod(); URL url; String token = System.getenv("FLY_SERVER_ACCESS_TOKEN"); if ( token == null ) switch ( Gdx.app.getType() ) { case Desktop: token = "ef78b5edd1e46531cc815b2cf7107bc5e6f7564c0b6cf253be2306b2edc53484"; break; case Android: token = "d96706409d2aaeb167944124041677b2073a2073c5e5a545e421097faee2ea38"; break; case iOS: token = "798a943f9e113f365ee8c546eff290b453801aac36e1087ab615fc920bc1db4a"; break; } String tokenString = "Token token=\"" + token + "\""; String secretKey = PlayerProfileManager.getInstance().getCurrentPlayerProfile().getSecretKey(); if ( secretKey != null ) tokenString += "; secret_key=\"" + secretKey + "\""; httpRequest.setHeader("Authorization", tokenString); if (method.equalsIgnoreCase(HttpMethods.GET)) { String queryString = ""; String value = httpRequest.getContent(); if (value != null && !value.isEmpty()) queryString = "?" + value; url = new URL(httpRequest.getUrl() + queryString); } else { url = new URL(httpRequest.getUrl()); } // HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { // @Override // public boolean verify(String s, SSLSession sslSession) { // return true; // } // }); final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); // should be enabled to upload data. final boolean doingOutPut = method.equalsIgnoreCase(HttpMethods.POST) || method.equalsIgnoreCase(HttpMethods.PUT); connection.setDoOutput(doingOutPut); connection.setDoInput(true); connection.setRequestMethod(method); connection.setSSLSocketFactory(RemoteServices.getSSLSocketFactory()); HttpsURLConnection.setFollowRedirects(httpRequest.getFollowRedirects()); lock.lock(); connections.put(httpRequest, connection); listeners.put(httpRequest, httpResponseListener); lock.unlock(); // Headers get set regardless of the method for (Map.Entry<String, String> header : httpRequest.getHeaders().entrySet()) connection.addRequestProperty(header.getKey(), header.getValue()); // Set Timeouts connection.setConnectTimeout(httpRequest.getTimeOut()); connection.setReadTimeout(httpRequest.getTimeOut()); executorService.submit(new Runnable() { @Override public void run() { try { // Set the content for POST and PUT (GET has the // information embedded in the URL) if (doingOutPut) { // we probably need to use the content as stream // here instead of using it as a string. String contentAsString = httpRequest.getContent(); if (contentAsString != null) { OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); try { writer.write(contentAsString); } finally { StreamUtils.closeQuietly(writer); } } else { InputStream contentAsStream = httpRequest.getContentStream(); if (contentAsStream != null) { OutputStream os = connection.getOutputStream(); try { StreamUtils.copyStream(contentAsStream, os); } finally { StreamUtils.closeQuietly(os); } } } } connection.connect(); final HttpClientResponse clientResponse = new HttpClientResponse(connection); try { lock.lock(); HttpResponseListener listener = listeners.get(httpRequest); if (listener != null) { listener.handleHttpResponse(clientResponse); listeners.remove(httpRequest); } connections.remove(httpRequest); } finally { connection.disconnect(); lock.unlock(); } } catch (final Exception e) { Gdx.app.log("NetHttpsJavaImpl", e.toString()); e.printStackTrace(); connection.disconnect(); lock.lock(); try { httpResponseListener.failed(e); } finally { connections.remove(httpRequest); listeners.remove(httpRequest); lock.unlock(); } } } }); } catch (Exception e) { Gdx.app.log("NetHttpsJavaImpl", e.toString()); e.printStackTrace(); lock.lock(); try { httpResponseListener.failed(e); } finally { connections.remove(httpRequest); listeners.remove(httpRequest); lock.unlock(); } return; } } public void cancelHttpRequest(HttpRequest httpRequest) { try { lock.lock(); HttpResponseListener httpResponseListener = listeners.get(httpRequest); if (httpResponseListener != null) { httpResponseListener.cancelled(); connections.remove(httpRequest); listeners.remove(httpRequest); } } finally { lock.unlock(); } } }