Home | History | Annotate | Download | only in gdx
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      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.badlogic.gdx;
     18 
     19 import java.io.InputStream;
     20 import java.io.OutputStream;
     21 import java.util.HashMap;
     22 import java.util.List;
     23 import java.util.Map;
     24 
     25 import com.badlogic.gdx.Application.ApplicationType;
     26 import com.badlogic.gdx.net.HttpRequestHeader;
     27 import com.badlogic.gdx.net.HttpResponseHeader;
     28 import com.badlogic.gdx.net.HttpStatus;
     29 import com.badlogic.gdx.net.ServerSocket;
     30 import com.badlogic.gdx.net.ServerSocketHints;
     31 import com.badlogic.gdx.net.Socket;
     32 import com.badlogic.gdx.net.SocketHints;
     33 import com.badlogic.gdx.utils.GdxRuntimeException;
     34 import com.badlogic.gdx.utils.Pool.Poolable;
     35 
     36 /** Provides methods to perform networking operations, such as simple HTTP get and post requests, and TCP server/client socket
     37  * communication.</p>
     38  *
     39  * To perform an HTTP request create a {@link HttpRequest} with the HTTP method (see {@link HttpMethods} for common methods) and
     40  * invoke {@link #sendHttpRequest(HttpRequest, HttpResponseListener)} with it and a {@link HttpResponseListener}. After the HTTP
     41  * request was processed, the {@link HttpResponseListener} is called with a {@link HttpResponse} with the HTTP response values and
     42  * an status code to determine if the request was successful or not.</p>
     43  *
     44  * To create a TCP client socket to communicate with a remote TCP server, invoke the
     45  * {@link #newClientSocket(Protocol, String, int, SocketHints)} method. The returned {@link Socket} offers an {@link InputStream}
     46  * and {@link OutputStream} to communicate with the end point.</p>
     47  *
     48  * To create a TCP server socket that waits for incoming connections, invoke the
     49  * {@link #newServerSocket(Protocol, int, ServerSocketHints)} method. The returned {@link ServerSocket} offers an
     50  * {@link ServerSocket#accept(SocketHints options)} method that waits for an incoming connection.
     51  *
     52  * @author mzechner
     53  * @author noblemaster
     54  * @author arielsan */
     55 public interface Net {
     56 
     57 	/** HTTP response interface with methods to get the response data as a byte[], a {@link String} or an {@link InputStream}. */
     58 	public static interface HttpResponse {
     59 		/** Returns the data of the HTTP response as a byte[].
     60 		 * <p>
     61 		 * <b>Note</b>: This method may only be called once per response.
     62 		 * </p>
     63 		 * @return the result as a byte[] or null in case of a timeout or if the operation was canceled/terminated abnormally. The
     64 		 *         timeout is specified when creating the HTTP request, with {@link HttpRequest#setTimeOut(int)} */
     65 		byte[] getResult ();
     66 
     67 		/** Returns the data of the HTTP response as a {@link String}.
     68 		 * <p>
     69 		 * <b>Note</b>: This method may only be called once per response.
     70 		 * </p>
     71 		 * @return the result as a string or null in case of a timeout or if the operation was canceled/terminated abnormally. The
     72 		 *         timeout is specified when creating the HTTP request, with {@link HttpRequest#setTimeOut(int)} */
     73 		String getResultAsString ();
     74 
     75 		/** Returns the data of the HTTP response as an {@link InputStream}. <b><br>
     76 		 * Warning:</b> Do not store a reference to this InputStream outside of
     77 		 * {@link HttpResponseListener#handleHttpResponse(HttpResponse)}. The underlying HTTP connection will be closed after that
     78 		 * callback finishes executing. Reading from the InputStream after it's connection has been closed will lead to exception.
     79 		 * @return An {@link InputStream} with the {@link HttpResponse} data. */
     80 		InputStream getResultAsStream ();
     81 
     82 		/** Returns the {@link HttpStatus} containing the statusCode of the HTTP response. */
     83 		HttpStatus getStatus ();
     84 
     85 		/** Returns the value of the header with the given name as a {@link String}, or null if the header is not set. See
     86 		 * {@link HttpResponseHeader}. */
     87 		String getHeader (String name);
     88 
     89 		/** Returns a Map of the headers. The keys are Strings that represent the header name. Each values is a List of Strings that
     90 		 * represent the corresponding header values. See {@link HttpResponseHeader}. */
     91 		Map<String, List<String>> getHeaders ();
     92 	}
     93 
     94 	/** Provides common HTTP methods to use when creating a {@link HttpRequest}.
     95 	 * <ul>
     96 	 * <li>GET</li>
     97 	 * <li>POST</li>
     98 	 * <li>PUT</li>
     99 	 * <li>DELETE</li>
    100 	 * </ul> */
    101 	public static interface HttpMethods {
    102 
    103 		public static final String GET = "GET";
    104 		public static final String POST = "POST";
    105 		public static final String PUT = "PUT";
    106 		public static final String DELETE = "DELETE";
    107 
    108 	}
    109 
    110 	/** Contains getters and setters for the following parameters:
    111 	 * <ul>
    112 	 * <li><strong>httpMethod:</strong> GET or POST are most common, can use {@link Net.HttpMethods HttpMethods} for static
    113 	 * references</li>
    114 	 * <li><strong>url:</strong> the url</li>
    115 	 * <li><strong>headers:</strong> a map of the headers, setter can be called multiple times</li>
    116 	 * <li><strong>timeout:</strong> time spent trying to connect before giving up</li>
    117 	 * <li><strong>content:</strong> A string containing the data to be used when processing the HTTP request.</li>
    118 	 * </ul>
    119 	 *
    120 	 * Abstracts the concept of a HTTP Request:
    121 	 *
    122 	 * <pre>
    123 	 * Map<String, String> parameters = new HashMap<String, String>();
    124 	 * parameters.put("user", "myuser");
    125 	 *
    126 	 * HttpRequest httpGet = new HttpRequest(HttpMethods.Get);
    127 	 * httpGet.setUrl("http://somewhere.net");
    128 	 * httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters));
    129 	 * ...
    130 	 * Gdx.net.sendHttpRequest (httpGet, new HttpResponseListener() {
    131 	 * 	public void handleHttpResponse(HttpResponse httpResponse) {
    132 	 * 		status = httpResponse.getResultAsString();
    133 	 * 		//do stuff here based on response
    134 	 * 	}
    135 	 *
    136 	 * 	public void failed(Throwable t) {
    137 	 * 		status = "failed";
    138 	 * 		//do stuff here based on the failed attempt
    139 	 * 	}
    140 	 * });
    141 	 * </pre> */
    142 	public static class HttpRequest implements Poolable {
    143 
    144 		private String httpMethod;
    145 		private String url;
    146 		private Map<String, String> headers;
    147 		private int timeOut = 0;
    148 
    149 		private String content;
    150 		private InputStream contentStream;
    151 		private long contentLength;
    152 
    153 		private boolean followRedirects = true;
    154 
    155 		private boolean includeCredentials = false;
    156 
    157 		public HttpRequest () {
    158 			this.headers = new HashMap<String, String>();
    159 		}
    160 
    161 		/** Creates a new HTTP request with the specified HTTP method, see {@link HttpMethods}.
    162 		 * @param httpMethod This is the HTTP method for the request, see {@link HttpMethods} */
    163 		public HttpRequest (String httpMethod) {
    164 			this();
    165 			this.httpMethod = httpMethod;
    166 		}
    167 
    168 		/** Sets the URL of the HTTP request.
    169 		 * @param url The URL to set. */
    170 		public void setUrl (String url) {
    171 			this.url = url;
    172 		}
    173 
    174 		/** Sets a header to this HTTP request, see {@link HttpRequestHeader}.
    175 		 * @param name the name of the header.
    176 		 * @param value the value of the header. */
    177 		public void setHeader (String name, String value) {
    178 			headers.put(name, value);
    179 		}
    180 
    181 		/** Sets the content to be used in the HTTP request.
    182 		 * @param content A string encoded in the corresponding Content-Encoding set in the headers, with the data to send with the
    183 		 *           HTTP request. For example, in case of HTTP GET, the content is used as the query string of the GET while on a
    184 		 *           HTTP POST it is used to send the POST data. */
    185 		public void setContent (String content) {
    186 			this.content = content;
    187 		}
    188 
    189 		/** Sets the content as a stream to be used for a POST for example, to transmit custom data.
    190 		 * @param contentStream The stream with the content data. */
    191 		public void setContent (InputStream contentStream, long contentLength) {
    192 			this.contentStream = contentStream;
    193 			this.contentLength = contentLength;
    194 		}
    195 
    196 		/** Sets the time to wait for the HTTP request to be processed, use 0 block until it is done. The timeout is used for both
    197 		 * the timeout when establishing TCP connection, and the timeout until the first byte of data is received.
    198 		 * @param timeOut the number of milliseconds to wait before giving up, 0 or negative to block until the operation is done */
    199 		public void setTimeOut (int timeOut) {
    200 			this.timeOut = timeOut;
    201 		}
    202 
    203 		/** Sets whether 301 and 302 redirects are followed. By default true. Can't be changed in the GWT backend because this uses
    204 		 * XmlHttpRequests which always redirect.
    205 		 * @param followRedirects whether to follow redirects.
    206 		 * @exception IllegalArgumentException if redirection is disabled on the GWT backend. */
    207 		public void setFollowRedirects (boolean followRedirects) throws IllegalArgumentException {
    208 			if (followRedirects == true || Gdx.app.getType() != ApplicationType.WebGL) {
    209 				this.followRedirects = followRedirects;
    210 			} else {
    211 				throw new IllegalArgumentException("Following redirects can't be disabled using the GWT/WebGL backend!");
    212 			}
    213 		}
    214 
    215 		/** Sets whether a cross-origin request will include credentials. Only used on GWT backend to allow cross-origin requests
    216 		 * to include credentials such as cookies, authorization headers, etc... */
    217 		public void setIncludeCredentials (boolean includeCredentials) {
    218 			this.includeCredentials = includeCredentials;
    219 		}
    220 
    221 		/** Sets the HTTP method of the HttpRequest. */
    222 		public void setMethod (String httpMethod) {
    223 			this.httpMethod = httpMethod;
    224 		}
    225 
    226 		/** Returns the timeOut of the HTTP request.
    227 		 * @return the timeOut. */
    228 		public int getTimeOut () {
    229 			return timeOut;
    230 		}
    231 
    232 		/** Returns the HTTP method of the HttpRequest. */
    233 		public String getMethod () {
    234 			return httpMethod;
    235 		}
    236 
    237 		/** Returns the URL of the HTTP request. */
    238 		public String getUrl () {
    239 			return url;
    240 		}
    241 
    242 		/** Returns the content string to be used for the HTTP request. */
    243 		public String getContent () {
    244 			return content;
    245 		}
    246 
    247 		/** Returns the content stream. */
    248 		public InputStream getContentStream () {
    249 			return contentStream;
    250 		}
    251 
    252 		/** Returns the content length in case content is a stream. */
    253 		public long getContentLength () {
    254 			return contentLength;
    255 		}
    256 
    257 		/** Returns a Map<String, String> with the headers of the HTTP request. */
    258 		public Map<String, String> getHeaders () {
    259 			return headers;
    260 		}
    261 
    262 		/** Returns whether 301 and 302 redirects are followed. By default true. Whether to follow redirects. */
    263 		public boolean getFollowRedirects () {
    264 			return followRedirects;
    265 		}
    266 
    267 		/** Returns whether a cross-origin request will include credentials. By default false. */
    268 		public boolean getIncludeCredentials () {
    269 			return includeCredentials;
    270 		}
    271 
    272 		@Override
    273 		public void reset () {
    274 			httpMethod = null;
    275 			url = null;
    276 			headers.clear();
    277 			timeOut = 0;
    278 
    279 			content = null;
    280 			contentStream = null;
    281 			contentLength = 0;
    282 
    283 			followRedirects = true;
    284 		}
    285 
    286 	}
    287 
    288 	/** Listener to be able to do custom logic once the {@link HttpResponse} is ready to be processed, register it with
    289 	 * {@link Net#sendHttpRequest(HttpRequest, HttpResponseListener)}. */
    290 	public static interface HttpResponseListener {
    291 
    292 		/** Called when the {@link HttpRequest} has been processed and there is a {@link HttpResponse} ready. Passing data to the
    293 		 * rendering thread should be done using {@link Application#postRunnable(java.lang.Runnable runnable)} {@link HttpResponse}
    294 		 * contains the {@link HttpStatus} and should be used to determine if the request was successful or not (see more info at
    295 		 * {@link HttpStatus#getStatusCode()}). For example:
    296 		 *
    297 		 * <pre>
    298 		 *  HttpResponseListener listener = new HttpResponseListener() {
    299 		 *  	public void handleHttpResponse (HttpResponse httpResponse) {
    300 		 *  		HttpStatus status = httpResponse.getStatus();
    301 		 *  		if (status.getStatusCode() >= 200 && status.getStatusCode() < 300) {
    302 		 *  			// it was successful
    303 		 *  		} else {
    304 		 *  			// do something else
    305 		 *  		}
    306 		 *  	}
    307 		 *  }
    308 		 * </pre>
    309 		 *
    310 		 * @param httpResponse The {@link HttpResponse} with the HTTP response values. */
    311 		void handleHttpResponse (HttpResponse httpResponse);
    312 
    313 		/** Called if the {@link HttpRequest} failed because an exception when processing the HTTP request, could be a timeout any
    314 		 * other reason (not an HTTP error).
    315 		 * @param t If the HTTP request failed because an Exception, t encapsulates it to give more information. */
    316 		void failed (Throwable t);
    317 
    318 		void cancelled ();
    319 	}
    320 
    321 	/** Process the specified {@link HttpRequest} and reports the {@link HttpResponse} to the specified {@link HttpResponseListener}
    322 	 * .
    323 	 * @param httpRequest The {@link HttpRequest} to be performed.
    324 	 * @param httpResponseListener The {@link HttpResponseListener} to call once the HTTP response is ready to be processed. Could
    325 	 *           be null, in that case no listener is called. */
    326 	public void sendHttpRequest (HttpRequest httpRequest, HttpResponseListener httpResponseListener);
    327 
    328 	public void cancelHttpRequest (HttpRequest httpRequest);
    329 
    330 	/** Protocol used by {@link Net#newServerSocket(Protocol, int, ServerSocketHints)} and
    331 	 * {@link Net#newClientSocket(Protocol, String, int, SocketHints)}.
    332 	 * @author mzechner */
    333 	public enum Protocol {
    334 		TCP
    335 	}
    336 
    337 	/** Creates a new server socket on the given address and port, using the given {@link Protocol}, waiting for incoming connections.
    338 	 *
    339 	 * @param hostname the hostname or ip address to bind the socket to
    340 	 * @param port the port to listen on
    341 	 * @param hints additional {@link ServerSocketHints} used to create the socket. Input null to use the default setting provided
    342 	 *           by the system.
    343 	 * @return the {@link ServerSocket}
    344 	 * @throws GdxRuntimeException in case the socket couldn't be opened */
    345 	public ServerSocket newServerSocket (Protocol protocol, String hostname, int port, ServerSocketHints hints);
    346 
    347 	/** Creates a new server socket on the given port, using the given {@link Protocol}, waiting for incoming connections.
    348 	 *
    349 	 * @param port the port to listen on
    350 	 * @param hints additional {@link ServerSocketHints} used to create the socket. Input null to use the default setting provided
    351 	 *           by the system.
    352 	 * @return the {@link ServerSocket}
    353 	 * @throws GdxRuntimeException in case the socket couldn't be opened */
    354 	public ServerSocket newServerSocket (Protocol protocol, int port, ServerSocketHints hints);
    355 
    356 	/** Creates a new TCP client socket that connects to the given host and port.
    357 	 *
    358 	 * @param host the host address
    359 	 * @param port the port
    360 	 * @param hints additional {@link SocketHints} used to create the socket. Input null to use the default setting provided by the
    361 	 *           system.
    362 	 * @return GdxRuntimeException in case the socket couldn't be opened */
    363 	public Socket newClientSocket (Protocol protocol, String host, int port, SocketHints hints);
    364 
    365 	/** Launches the default browser to display a URI. If the default browser is not able to handle the specified URI, the
    366 	 * application registered for handling URIs of the specified type is invoked. The application is determined from the protocol
    367 	 * and path of the URI. A best effort is made to open the given URI; however, since external applications are involved, no guarantee
    368 	 * can be made as to whether the URI was actually opened. If it is known that the URI was not opened, false will be returned;
    369 	 * otherwise, true will be returned.
    370 	 *
    371 	 * @param URI the URI to be opened.
    372 	 * @return false if it is known the uri was not opened, true otherwise. */
    373 	public boolean openURI (String URI);
    374 }
    375