basic http server

~3h work
This commit is contained in:
Benedikt Galbavy 2023-12-23 23:58:19 +01:00
parent 19a2d9bbb2
commit 765af93728
8 changed files with 178 additions and 0 deletions

30
.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
.idea/

11
mtcg.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

12
src/Main.java Normal file
View File

@ -0,0 +1,12 @@
import at.nanopenguin.mtcg.http.Router;
import at.nanopenguin.mtcg.http.Server;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
System.out.println("Hello world!");
Server server = new Server(10001, 10, new Router());
server.start();
}
}

View File

@ -0,0 +1,23 @@
package at.nanopenguin.mtcg.http;
public enum HttpStatus {
OK(200, "OK"),
CREATED(201, "Created"),
NO_CONTENT(204, "No Content"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
CONFLICT(409, "Conflict"),
TEAPOT(418, "I'm a teapot"),
INTERNAL(500, "Internal Server Error"),
NOT_IMPLEMENTED(501, "Not Implemented");
public final int statusCode;
public final String statusMessage;
HttpStatus(int code, String message) {
this.statusCode = code;
this.statusMessage = message;
}
}

View File

@ -0,0 +1,31 @@
package at.nanopenguin.mtcg.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class RequestHandler implements Runnable {
private final Socket serviceSocket;
private final Router router;
private BufferedReader br;
private OutputStream out;
public RequestHandler(Socket serviceSocket, Router router) {
this.serviceSocket = serviceSocket;
this.router = router;
}
@Override
public void run() {
try {
Response response = new Response(HttpStatus.OK, "application/json", "[]");
this.out = this.serviceSocket.getOutputStream();
out.write(response.get().getBytes());
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,31 @@
package at.nanopenguin.mtcg.http;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Response {
private final HttpStatus httpStatus;
private final String contentType;
private final String content;
public Response(HttpStatus httpStatus, String contentType, String content) {
this.httpStatus = httpStatus;
this.contentType = contentType;
this.content = content;
}
public String get() {
String localDatetime = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneId.of("UTC")));
return "HTTP/1.1 " + this.httpStatus.statusCode + " " + this.httpStatus.statusMessage + "\r\n" +
"Cache-Control: max-age=0\r\n" +
"Connection: close\r\n" +
"Date: " + localDatetime + "\r\n" +
"Expires: " + localDatetime + "\r\n" +
"Content-Type: " + this.contentType + "\r\n" +
"Content-Length: " + this.content.length() + "\r\n" +
"\r\n" +
this.content;
}
}

View File

@ -0,0 +1,4 @@
package at.nanopenguin.mtcg.http;
public class Router {
}

View File

@ -0,0 +1,36 @@
package at.nanopenguin.mtcg.http;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
private final int port; // 16-bit unsigned, not enforced
private final int threads;
private final Router router;
public Server(int port, int threads, Router router) {
this.port = port;
this.threads = threads;
this.router = router;
}
public void start() throws IOException {
try (ServerSocket listener = new ServerSocket(this.port)) {
ExecutorService executorService = Executors.newFixedThreadPool(this.threads);
System.out.println("HTTP server running on http://localhost:" + this.port);
while (true) {
final Socket serviceSocket = listener.accept();
final RequestHandler requestHandler = new RequestHandler(serviceSocket, this.router);
executorService.submit(requestHandler);
}
}
}
}