Skip to content

Commit ba03b55

Browse files
En förbättrad implementation efter AI-feedbacken.
1 parent 08cce87 commit ba03b55

4 files changed

Lines changed: 77 additions & 47 deletions

File tree

src/main/java/com/example/HelloFX.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ public class HelloFX extends Application {
1414

1515
@Override
1616
public void start(Stage stage) throws IOException {
17-
// Skapa en enda NtfyConnection-instans
17+
1818
connection = new NtfyConnectionImpl();
1919

20-
// Starta ImageServer på separat daemon-tråd
2120
Thread serverThread = new Thread(() -> {
2221
try {
2322
imageServer = new ImageServer(8081);
@@ -28,19 +27,16 @@ public void start(Stage stage) throws IOException {
2827
serverThread.setDaemon(true);
2928
serverThread.start();
3029

31-
// Ladda FXML
3230
FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml"));
3331
Scene scene = new Scene(fxmlLoader.load(), 600, 400);
3432

35-
// Hämta controller och injicera connection
3633
HelloController controller = fxmlLoader.getController();
3734
controller.setConnection(connection);
3835

3936
stage.setTitle("HelloFX Chat");
4037
stage.setScene(scene);
4138
stage.show();
4239

43-
// Säkerställ att connection och server stoppas vid stängning
4440
stage.setOnCloseRequest(event -> {
4541
System.out.println("🛑 Application closing...");
4642

@@ -62,7 +58,6 @@ public void start(Stage stage) throws IOException {
6258
e.printStackTrace();
6359
}
6460

65-
// Ingen need att joina daemon-tråden; den avslutas automatiskt
6661
});
6762
}
6863

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.example;
22

33
import com.sun.net.httpserver.HttpServer;
4+
import com.sun.net.httpserver.HttpExchange;
5+
46
import java.io.IOException;
5-
import java.nio.file.*;
7+
import java.io.OutputStream;
68
import java.net.InetSocketAddress;
9+
import java.nio.file.*;
710
import java.util.UUID;
811

912
public class ImageServer {
@@ -14,57 +17,92 @@ public class ImageServer {
1417

1518
public ImageServer(int port) throws IOException {
1619
this.port = port;
17-
this.imageDir = Paths.get("uploaded-images");
18-
if (!Files.exists(imageDir)) Files.createDirectory(imageDir);
20+
this.imageDir = Paths.get("uploaded-images").toAbsolutePath().normalize();
21+
22+
if (!Files.exists(imageDir)) {
23+
Files.createDirectories(imageDir);
24+
}
25+
1926
startServer();
2027
}
2128

2229
private void startServer() throws IOException {
2330
server = HttpServer.create(new InetSocketAddress(port), 0);
2431

25-
// Hantera bilduppladdning
32+
// -------------------------------------------------------
33+
// UPLOAD HANDLER
34+
// -------------------------------------------------------
2635
server.createContext("/upload", exchange -> {
2736
try {
28-
if ("POST".equals(exchange.getRequestMethod())) {
29-
String filename = UUID.randomUUID() + ".jpg";
30-
Path filePath = imageDir.resolve(filename);
31-
32-
try {
33-
Files.copy(exchange.getRequestBody(), filePath, StandardCopyOption.REPLACE_EXISTING);
34-
} catch (IOException e) {
35-
System.err.println("❌ Failed to save uploaded file: " + e.getMessage());
36-
exchange.sendResponseHeaders(500, -1);
37-
return;
38-
}
39-
40-
String imageUrl = "http://localhost:" + port + "/images/" + filename;
41-
byte[] response = imageUrl.getBytes();
42-
try {
43-
exchange.sendResponseHeaders(200, response.length);
44-
exchange.getResponseBody().write(response);
45-
} catch (IOException e) {
46-
System.err.println("❌ Failed to write response: " + e.getMessage());
47-
}
37+
if (!"POST".equals(exchange.getRequestMethod())) {
38+
exchange.sendResponseHeaders(405, -1);
39+
return;
4840
}
41+
42+
String filename = UUID.randomUUID() + ".jpg";
43+
Path filePath = imageDir.resolve(filename).normalize();
44+
45+
// Extra säkerhet: kontrollera att filen ligger inne i imageDir
46+
if (!filePath.startsWith(imageDir)) {
47+
exchange.sendResponseHeaders(403, -1);
48+
return;
49+
}
50+
51+
try {
52+
Files.copy(exchange.getRequestBody(), filePath, StandardCopyOption.REPLACE_EXISTING);
53+
} catch (IOException e) {
54+
System.err.println("❌ Failed to save uploaded file: " + e.getMessage());
55+
exchange.sendResponseHeaders(500, -1);
56+
return;
57+
}
58+
59+
String imageUrl = "http://localhost:" + port + "/images/" + filename;
60+
byte[] response = imageUrl.getBytes();
61+
62+
try (OutputStream os = exchange.getResponseBody()) {
63+
exchange.sendResponseHeaders(200, response.length);
64+
os.write(response);
65+
}
66+
4967
} finally {
5068
exchange.close();
5169
}
5270
});
5371

54-
// Visa uppladdade bilder
72+
// -------------------------------------------------------
73+
// IMAGE FETCH HANDLER /images/xxx
74+
// -------------------------------------------------------
5575
server.createContext("/images", exchange -> {
5676
try {
57-
Path filePath = imageDir.resolve(exchange.getRequestURI().getPath().replace("/images/", ""));
58-
if (Files.exists(filePath)) {
59-
exchange.sendResponseHeaders(200, Files.size(filePath));
60-
try {
61-
Files.copy(filePath, exchange.getResponseBody());
62-
} catch (IOException e) {
63-
System.err.println("❌ Failed to send image: " + e.getMessage());
64-
}
65-
} else {
77+
String rawPath = exchange.getRequestURI().getPath().replace("/images/", "");
78+
if (rawPath.isBlank()) {
79+
exchange.sendResponseHeaders(400, -1);
80+
return;
81+
}
82+
83+
Path requested = imageDir.resolve(rawPath).normalize();
84+
85+
if (!requested.startsWith(imageDir)) {
86+
exchange.sendResponseHeaders(403, -1);
87+
return;
88+
}
89+
90+
if (!Files.exists(requested)) {
6691
exchange.sendResponseHeaders(404, -1);
92+
return;
93+
}
94+
95+
String contentType = Files.probeContentType(requested);
96+
if (contentType == null) contentType = "application/octet-stream";
97+
exchange.getResponseHeaders().add("Content-Type", contentType);
98+
99+
long size = Files.size(requested);
100+
101+
exchange.sendResponseHeaders(200, size);
102+
try (OutputStream os = exchange.getResponseBody()) {
103+
Files.copy(requested, os);
67104
}
105+
68106
} finally {
69107
exchange.close();
70108
}
@@ -78,6 +116,7 @@ private void startServer() throws IOException {
78116
public void stop() {
79117
if (server != null) {
80118
server.stop(0);
119+
System.out.println("🛑 Image server stopped");
81120
}
82121
}
83122
}

src/main/java/com/example/NtfyConnectionImpl.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ public boolean sendImage(File imageFile, String clientId) {
5858
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
5959
conn.setRequestProperty("X-Client-Id", clientId);
6060

61-
// JSON-del
6261
var json = mapper.writeValueAsString(
6362
new java.util.LinkedHashMap<String,Object>() {{
6463
put("clientId", clientId);
@@ -75,7 +74,6 @@ public boolean sendImage(File imageFile, String clientId) {
7574
writer.append(json).append("\r\n");
7675
writer.flush();
7776

78-
// Bildfil
7977
String contentType = Files.probeContentType(imageFile.toPath());
8078
if (contentType == null) contentType = "application/octet-stream";
8179

@@ -116,12 +114,10 @@ public void receive(Consumer<NtfyMessageDto> messageHandler) {
116114
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
117115
String body = response.body();
118116

119-
// Dela på nya rader (SSE)
120117
for (String line : body.split("\\R")) {
121118
line = line.trim();
122119
if (line.isEmpty()) continue;
123120

124-
// Ta bort "data:" prefix om det finns
125121
if (line.startsWith("data:")) {
126122
line = line.substring(5).trim();
127123
}

src/test/java/com/example/NtfyConnectionSpy.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import java.util.function.Consumer;
55

66
/**
7-
* Test-dubbel för HelloModel.
8-
* Tar emot och skickar meddelanden utan riktig HTTP.
7+
* Test-double for HelloModel.
8+
* Sends and receive messages without actual HTTP.
99
*/
1010
public class NtfyConnectionSpy implements NtfyConnection {
1111

@@ -38,7 +38,7 @@ public void receive(Consumer<NtfyMessageDto> messageHandler) {
3838
public void stopReceiving() { }
3939

4040
/**
41-
* Simulerar ett inkommande JSON-meddelande.
41+
* Simulates an incoming JSON-message.
4242
*/
4343
public void simulateIncomingMessage(String json) {
4444
if (messageHandler != null) {

0 commit comments

Comments
 (0)