Files
Holocore/src/services/admin/http/HttpServer.java
2015-08-24 17:27:45 -05:00

197 lines
4.8 KiB
Java

package services.admin.http;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import resources.server_info.Log;
import services.admin.http.HttpSocket.HttpRequest;
import utilities.ThreadUtilities;
public class HttpServer {
private static final String TAG = "HttpServer";
private final InetAddress addr;
private final int port;
private ExecutorService executor;
private ServerSocket serverSocket;
private AtomicInteger currentConnections;
private HttpServerCallback callback;
private int maxConnections;
private boolean secure;
protected HttpServer(InetAddress addr, int port, boolean secure) {
this.addr = addr;
this.port = port;
this.currentConnections = new AtomicInteger(0);
this.callback = null;
this.maxConnections = 2;
this.secure = secure;
}
public HttpServer(InetAddress addr, int port) {
this(addr, port, false);
}
public void start() {
executor = Executors.newCachedThreadPool(ThreadUtilities.newThreadFactory(getThreadFactoryName()));
try {
serverSocket = createSocket();
startAcceptThread(serverSocket, secure);
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (executor != null) {
executor.shutdownNow();
try {
executor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setServerCallback(HttpServerCallback callback) {
this.callback = callback;
}
public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
}
public final InetAddress getBindAddress() {
return addr;
}
public final int getBindPort() {
return port;
}
protected String getThreadFactoryName() {
return "HttpServer-%d";
}
protected ServerSocket createSocket() throws IOException {
return new ServerSocket(port, 0, addr);
}
private void startAcceptThread(ServerSocket serverSocket, boolean secure) {
executor.submit(() -> {
try {
acceptThread(serverSocket, secure);
} catch (Throwable t) {
t.printStackTrace();
}
});
}
private void startSocketThread(HttpSocket socket) {
executor.submit(() -> {
try {
socketThread(socket);
} catch (Throwable t) {
t.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
synchronized (currentConnections) {
currentConnections.decrementAndGet();
}
});
}
private void acceptThread(ServerSocket serverSocket, boolean secure) {
Log.i(TAG, "Now listening over HTTP%s. Address: %s:%d", secure?"S":"", serverSocket.getInetAddress(), serverSocket.getLocalPort());
while (serverSocket.isBound() && !serverSocket.isClosed()) {
try {
Socket socket = serverSocket.accept();
HttpSocket httpSocket = new HttpSocket(socket, secure);
if (!httpSocket.isOpened()) {
httpSocket.close();
continue;
}
if (currentConnections.get() >= maxConnections) {
httpSocket.send(HttpStatusCode.SERVICE_UNAVAILABLE, "The server has reached it's maximum connection limit: " + maxConnections);
socket.close();
} else {
if (currentConnections.incrementAndGet() > maxConnections) {
socket.close();
currentConnections.decrementAndGet();
} else {
startSocketThread(httpSocket);
}
}
} catch (SocketException e) {
if (serverSocket.isClosed())
break;
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
}
Log.i(TAG, "No longer listening over HTTP%s!", secure?"S":"");
}
private void socketThread(HttpSocket socket) throws IOException {
onSocketCreated(socket);
HttpRequest request;
while (socket.isOpened() && !socket.isClosed()) {
request = socket.waitForRequest();
if (request == null)
break;
if (request.getType() == null || request.getURI() == null || request.getHttpVersion() == null) {
socket.send(HttpStatusCode.BAD_REQUEST);
continue;
}
onRequestReceived(socket, request);
}
}
private void onSocketCreated(HttpSocket socket) {
if (callback == null)
return;
try {
callback.onSocketCreated(socket);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void onRequestReceived(HttpSocket socket, HttpRequest request) {
if (callback == null)
return;
try {
callback.onRequestReceived(socket, request);
} catch (Throwable t) {
t.printStackTrace();
}
}
public interface HttpServerCallback {
void onSocketCreated(HttpSocket socket);
void onRequestReceived(HttpSocket socket, HttpRequest request);
}
}