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
17package com.badlogic.gdx;
18
19import java.io.InputStream;
20import java.io.OutputStream;
21import java.util.HashMap;
22import java.util.List;
23import java.util.Map;
24
25import com.badlogic.gdx.Application.ApplicationType;
26import com.badlogic.gdx.net.HttpRequestHeader;
27import com.badlogic.gdx.net.HttpResponseHeader;
28import com.badlogic.gdx.net.HttpStatus;
29import com.badlogic.gdx.net.ServerSocket;
30import com.badlogic.gdx.net.ServerSocketHints;
31import com.badlogic.gdx.net.Socket;
32import com.badlogic.gdx.net.SocketHints;
33import com.badlogic.gdx.utils.GdxRuntimeException;
34import 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 */
55public 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