Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/di java #23

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions 01_web/http-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
<groupId>ru.netology</groupId>
<artifactId>http-server</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>

</dependencies>

<properties>
<maven.compiler.source>11</maven.compiler.source>
Expand Down
7 changes: 7 additions & 0 deletions 01_web/http-server/src/main/java/ru/netology/Handler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.netology;

import java.io.BufferedOutputStream;

public interface Handler {
void handle (Request request, BufferedOutputStream out);
}
104 changes: 33 additions & 71 deletions 01_web/http-server/src/main/java/ru/netology/Main.java
Original file line number Diff line number Diff line change
@@ -1,83 +1,45 @@
package ru.netology;

import java.io.*;
import java.net.ServerSocket;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.List;

public class Main {
public static void main(String[] args) {
final var validPaths = List.of("/index.html", "/spring.svg", "/spring.png", "/resources.html", "/styles.css", "/app.js", "/links.html", "/forms.html", "/classic.html", "/events.html", "/events.js");

try (final var serverSocket = new ServerSocket(9999)) {
while (true) {
try (
final var socket = serverSocket.accept();
final var in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
final var out = new BufferedOutputStream(socket.getOutputStream());
) {
// read only request line for simplicity
// must be in form GET /path HTTP/1.1
final var requestLine = in.readLine();
final var parts = requestLine.split(" ");

if (parts.length != 3) {
// just close socket
continue;
}

final var path = parts[1];
if (!validPaths.contains(path)) {
out.write((
"HTTP/1.1 404 Not Found\r\n" +
"Content-Length: 0\r\n" +
"Connection: close\r\n" +
"\r\n"
).getBytes());
out.flush();
continue;
}

final var filePath = Path.of(".", "public", path);
final var mimeType = Files.probeContentType(filePath);
final var server = new Server(64);
server.addHandler("GET", "/index.html", (request, out) -> {
try {
Path filePath = Path.of(".", "01_web", "http-server", "public", request.path());
String mimeType = Files.probeContentType(filePath);
long sizeFile = Files.size(filePath);
outResponse(mimeType, sizeFile, out, filePath);
} catch (IOException e) {
e.printStackTrace();
}
});
server.addHandler("POST", "/messages", (request, out) -> {
try {
Path filePath = Path.of(".", "01_web", "http-server", "public", request.path());
String mimeType = Files.probeContentType(filePath);
long sizeFile = Files.size(filePath);
outResponse(mimeType, sizeFile, out, filePath);
} catch (IOException e) {
e.printStackTrace();
}
});
server.startedServer(9998);
}

// special case for classic
if (path.equals("/classic.html")) {
final var template = Files.readString(filePath);
final var content = template.replace(
"{time}",
LocalDateTime.now().toString()
).getBytes();
out.write((
"HTTP/1.1 200 OK\r\n" +
public static void outResponse(String mimeType, long size, BufferedOutputStream bufferedOutputStream, Path path) throws IOException {
bufferedOutputStream.write((
"HTTP/1.1 200 OK\r\n" +
"Content-Type: " + mimeType + "\r\n" +
"Content-Length: " + content.length + "\r\n" +
"Content-Length: " + size + "\r\n" +
"Connection: close\r\n" +
"\r\n"
).getBytes());
out.write(content);
out.flush();
continue;
}

final var length = Files.size(filePath);
out.write((
"HTTP/1.1 200 OK\r\n" +
"Content-Type: " + mimeType + "\r\n" +
"Content-Length: " + length + "\r\n" +
"Connection: close\r\n" +
"\r\n"
).getBytes());
Files.copy(filePath, out);
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
).getBytes());
Files.copy(path, bufferedOutputStream);
bufferedOutputStream.flush();
}
}


}
108 changes: 108 additions & 0 deletions 01_web/http-server/src/main/java/ru/netology/Request.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package ru.netology;

import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.net.URLEncodedUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;

public record Request(String method, InputStream body, String path, List<String> headers,
Map<String, List<String>> post, Map<String, List<String>> query) {
private final static int LIMIT = 4096;

public static Request parsingHttpRequest(InputStream inputStream) throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
bufferedInputStream.mark(LIMIT);
byte[] buffer = new byte[LIMIT];
int read = bufferedInputStream.read(buffer);
byte[] requestLineDelimiter = new byte[]{'\r', '\n'};
int requestStartedLineEnd = indexOf(buffer, requestLineDelimiter, 0, read);
if (requestStartedLineEnd == -1) {
return null;
}
String[] requestStartedLine = new String(Arrays.copyOf(buffer, requestStartedLineEnd)).split(" ");
if (requestStartedLine.length != 3) {
return null;
}
String method = requestStartedLine[0];
if (!method.equals("GET") && !method.equals("POST")) {
return null;
}
String pathAndQuery = requestStartedLine[1];
if (!pathAndQuery.startsWith("/")) {
return null;
}
String path;
Map<String, List<String>> query;
if (pathAndQuery.contains("?")) {
String[] urlPathAndQuery = pathAndQuery.split("/?");
path = urlPathAndQuery[0];
String pathQuery = urlPathAndQuery[1];
query = getQueryParams(pathQuery);
} else {
path = pathAndQuery;
query = null;
}
byte[] headersDelimiter = new byte[]{'\r', '\n', '\r', '\n'};
int headersStarted = requestStartedLineEnd + requestLineDelimiter.length;
int headersEnd = indexOf(buffer, headersDelimiter, headersStarted, read);
if (headersEnd == -1) {
return null;
}
bufferedInputStream.reset();
bufferedInputStream.skip(headersStarted);
byte[] headersBytes = bufferedInputStream.readNBytes(headersEnd - headersStarted);
List<String> headers = Arrays.asList(new String(headersBytes).split("\r\n"));
Map<String, List<String>> post = null;
if (!method.equals("GET")) {
bufferedInputStream.skip(headersDelimiter.length);
Optional<String> contentLength = extractHeader(headers, "Content-Length");
if (contentLength.isPresent()) {
int length = Integer.parseInt(contentLength.get());
byte[] bodyBytes = bufferedInputStream.readNBytes(length);
String body = new String(bodyBytes);
if (body.contains("=")) {
post = getQueryParams(body);
}
}
}
return new Request(method, inputStream, path, headers, post, query);
}

public static Map<String, List<String>> getQueryParams(String url) {
Map<String, List<String>> queryParams = new HashMap<>();
List<NameValuePair> params = URLEncodedUtils.parse(url, Charset.defaultCharset(), '&');
for (NameValuePair param : params) {
if (queryParams.containsKey(param.getName())) {
queryParams.get(param.getName()).add(param.getValue());
} else {
List<String> values = new ArrayList<>();
values.add(param.getValue());
queryParams.put(param.getName(), values);
}
}
return queryParams;
}

private static Optional<String> extractHeader(List<String> headers, String header) {
return headers.stream()
.filter(o -> o.startsWith(header))
.map(o -> o.substring(o.indexOf(" ")))
.map(String::trim)
.findFirst();
}

private static int indexOf(byte[] array, byte[] target, int start, int max) {
outer:
for (int i = start; i < max - target.length + 1; i++) {
for (int j = 0; j < target.length; j++) {
if (array[j + i] != target[j]) {
continue outer;
}
}
return i;
}
return -1;
}
}
70 changes: 70 additions & 0 deletions 01_web/http-server/src/main/java/ru/netology/Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package ru.netology;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
private final ExecutorService executorService;
private final Map<String, Map<String, Handler>> mapRequest = new ConcurrentHashMap<>();
private final Handler errorHttpRequest = ((request, out) -> {
try {
out.write((
"HTTP/1.1 404 Not Found\r\n" +
"Content-Length: 0\r\n" +
"Connection: close\r\n" +
"\r\n"
).getBytes());
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
});

public Server(int sizeThread) {
this.executorService = Executors.newFixedThreadPool(sizeThread);
}

public void startedServer(int port) {
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
Socket socket = serverSocket.accept();
executorService.submit(() -> {
connection(socket);
});
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void addHandler (String method, String path, Handler handler){
if (mapRequest.get(method) == null){
mapRequest.put(method, new ConcurrentHashMap<>());
}
mapRequest.get(method).put(path,handler);
}

private void connection(Socket socket) {
try (InputStream inputStream = socket.getInputStream();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream())) {
Request requestLine = Request.parsingHttpRequest(inputStream);
Map<String, Handler> path = mapRequest.get(requestLine != null ? requestLine.method() : null);
if (path == null) {
errorHttpRequest.handle(requestLine, bufferedOutputStream);
return;
}
Handler handler = path.get(requestLine != null ? requestLine.path() : null);
if (handler == null){
errorHttpRequest.handle(requestLine, bufferedOutputStream);
return;
}
handler.handle(requestLine, bufferedOutputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Loading