Skip to content

Commit 48bc5f8

Browse files
Merge remote-tracking branch 'origin/main' into URL-Redirect-Filter
2 parents f40e141 + 86f2ba7 commit 48bc5f8

7 files changed

Lines changed: 187 additions & 32 deletions

File tree

PortConfigurationGuide.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Konfiguration: port (CLI → config-fil → default)
2+
3+
Det här projektet väljer vilken port servern ska starta på enligt följande prioritet:
4+
5+
1. **CLI-argument** (`--port <port>`) – högst prioritet
6+
2. **Config-fil** (`application.yml`: `server.port`)
7+
3. **Default** (`8080`) – används om port saknas i config eller om config-filen saknas
8+
9+
---
10+
11+
## 1) Default-värde
12+
13+
Om varken CLI eller config anger port används:
14+
15+
- **8080** (default för `server.port` i `AppConfig`)
16+
17+
---
18+
19+
## 2) Config-fil: `application.yml`
20+
21+
### Var ska filen ligga?
22+
Standard:
23+
- `src/main/resources/application.yml`
24+
25+
### Exempel
26+
```yaml
27+
server:
28+
port: 9090
29+
```
30+
31+
---
32+
33+
## 3) CLI-argument
34+
35+
CLI kan användas för att override:a config:
36+
37+
```bash
38+
java -cp target/classes org.example.App --port 8000
39+
```
40+
41+
---
42+
43+
## 4) Sammanfattning
44+
45+
Prioritet:
46+
47+
1. CLI (`--port`)
48+
2. `application.yml` (`server.port`)
49+
3. Default (`8080`)

src/main/java/org/example/App.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,50 @@
66
import java.nio.file.Path;
77

88
public class App {
9+
10+
private static final String PORT_FLAG = "--port";
11+
912
public static void main(String[] args) {
1013
Path configPath = Path.of("src/main/resources/application.yml");
1114

1215
AppConfig appConfig = ConfigLoader.loadOnce(configPath);
13-
int port = appConfig.server().port();
16+
17+
int port = resolvePort(args, appConfig.server().port());
18+
1419
new TcpServer(port).start();
1520
}
21+
22+
static int resolvePort(String[] args, int configPort) {
23+
Integer cliPort = parsePortFromCli(args);
24+
if (cliPort != null) {
25+
return validatePort(cliPort, "CLI argument " + PORT_FLAG);
26+
}
27+
return validatePort(configPort, "configuration server.port");
28+
}
29+
30+
static Integer parsePortFromCli(String[] args) {
31+
if (args == null) return null;
32+
33+
for (int i = 0; i < args.length; i++) {
34+
if (PORT_FLAG.equals(args[i])) {
35+
int valueIndex = i + 1;
36+
if (valueIndex >= args.length) {
37+
throw new IllegalArgumentException("Missing value after " + PORT_FLAG);
38+
}
39+
try {
40+
return Integer.parseInt(args[valueIndex]);
41+
} catch (NumberFormatException e) {
42+
throw new IllegalArgumentException("Invalid port value after " + PORT_FLAG + ": " + args[valueIndex], e);
43+
}
44+
}
45+
}
46+
return null;
47+
}
48+
49+
static int validatePort(int port, String source) {
50+
if (port < 1 || port > 65535) {
51+
throw new IllegalArgumentException("Port out of range (1-65535) from " + source + ": " + port);
52+
}
53+
return port;
54+
}
1655
}

src/main/java/org/example/StaticFileHandler.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.example;
22

33
import org.example.http.HttpResponseBuilder;
4+
import static org.example.http.HttpResponseBuilder.*;
45

56
import java.io.File;
67
import java.io.IOException;
@@ -36,22 +37,22 @@ private void handleGetRequest(String uri) throws IOException {
3637
File file = new File(root, uri).getCanonicalFile();
3738
if (!file.toPath().startsWith(root.toPath())) {
3839
fileBytes = "403 Forbidden".getBytes(java.nio.charset.StandardCharsets.UTF_8);
39-
statusCode = 403;
40+
statusCode = SC_FORBIDDEN;
4041
return;
4142
}
4243

4344
// Read file
4445
if (file.isFile()) {
4546
fileBytes = Files.readAllBytes(file.toPath());
46-
statusCode = 200;
47+
statusCode = SC_OK;
4748
} else {
4849
File errorFile = new File(WEB_ROOT, "pageNotFound.html");
4950
if (errorFile.isFile()) {
5051
fileBytes = Files.readAllBytes(errorFile.toPath());
5152
} else {
5253
fileBytes = "404 Not Found".getBytes(java.nio.charset.StandardCharsets.UTF_8);
5354
}
54-
statusCode = 404;
55+
statusCode = SC_NOT_FOUND;
5556
}
5657
}
5758

@@ -65,4 +66,4 @@ public void sendGetRequest(OutputStream outputStream, String uri) throws IOExcep
6566
outputStream.write(response.build());
6667
outputStream.flush();
6768
}
68-
}
69+
}

src/main/java/org/example/http/HttpResponseBuilder.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,59 @@
66

77
public class HttpResponseBuilder {
88

9+
// SUCCESS
10+
public static final int SC_OK = 200;
11+
public static final int SC_CREATED = 201;
12+
public static final int SC_NO_CONTENT = 204;
13+
14+
// REDIRECTION
15+
public static final int SC_MOVED_PERMANENTLY = 301;
16+
public static final int SC_FOUND = 302;
17+
public static final int SC_SEE_OTHER = 303;
18+
public static final int SC_NOT_MODIFIED = 304;
19+
public static final int SC_TEMPORARY_REDIRECT = 307;
20+
public static final int SC_PERMANENT_REDIRECT = 308;
21+
22+
// CLIENT ERROR
23+
public static final int SC_BAD_REQUEST = 400;
24+
public static final int SC_UNAUTHORIZED = 401;
25+
public static final int SC_FORBIDDEN = 403;
26+
public static final int SC_NOT_FOUND = 404;
27+
28+
// SERVER ERROR
29+
public static final int SC_INTERNAL_SERVER_ERROR = 500;
30+
public static final int SC_BAD_GATEWAY = 502;
31+
public static final int SC_SERVICE_UNAVAILABLE = 503;
32+
public static final int SC_GATEWAY_TIMEOUT = 504;
33+
34+
35+
936
private static final String PROTOCOL = "HTTP/1.1";
10-
private int statusCode = 200;
37+
private int statusCode = SC_OK;
1138
private String body = "";
1239
private byte[] bytebody;
1340
private Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
1441

1542
private static final String CRLF = "\r\n";
1643

1744
private static final Map<Integer, String> REASON_PHRASES = Map.ofEntries(
18-
Map.entry(200, "OK"),
19-
Map.entry(201, "Created"),
20-
Map.entry(204, "No Content"),
21-
Map.entry(301, "Moved Permanently"),
22-
Map.entry(302, "Found"),
23-
Map.entry(303, "See Other"),
24-
Map.entry(304, "Not Modified"),
25-
Map.entry(307, "Temporary Redirect"),
26-
Map.entry(308, "Permanent Redirect"),
27-
Map.entry(400, "Bad Request"),
28-
Map.entry(401, "Unauthorized"),
29-
Map.entry(403, "Forbidden"),
30-
Map.entry(404, "Not Found"),
31-
Map.entry(500, "Internal Server Error"),
32-
Map.entry(502, "Bad Gateway"),
33-
Map.entry(503, "Service Unavailable")
45+
Map.entry(SC_OK, "OK"),
46+
Map.entry(SC_CREATED, "Created"),
47+
Map.entry(SC_NO_CONTENT, "No Content"),
48+
Map.entry(SC_MOVED_PERMANENTLY, "Moved Permanently"),
49+
Map.entry(SC_FOUND, "Found"),
50+
Map.entry(SC_SEE_OTHER, "See Other"),
51+
Map.entry(SC_NOT_MODIFIED, "Not Modified"),
52+
Map.entry(SC_TEMPORARY_REDIRECT, "Temporary Redirect"),
53+
Map.entry(SC_PERMANENT_REDIRECT, "Permanent Redirect"),
54+
Map.entry(SC_BAD_REQUEST, "Bad Request"),
55+
Map.entry(SC_UNAUTHORIZED, "Unauthorized"),
56+
Map.entry(SC_FORBIDDEN, "Forbidden"),
57+
Map.entry(SC_NOT_FOUND, "Not Found"),
58+
Map.entry(SC_INTERNAL_SERVER_ERROR, "Internal Server Error"),
59+
Map.entry(SC_BAD_GATEWAY, "Bad Gateway"),
60+
Map.entry(SC_SERVICE_UNAVAILABLE, "Service Unavailable"),
61+
Map.entry(SC_GATEWAY_TIMEOUT, "Gateway Timeout")
3462
);
3563

3664
public void setStatusCode(int statusCode) {
@@ -106,4 +134,4 @@ public byte[] build() {
106134

107135
return response;
108136
}
109-
}
137+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.example;
2+
3+
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class AppPortResolutionTest {
9+
10+
@Test
11+
void cli_port_wins_over_config() {
12+
int port = App.resolvePort(new String[]{"--port", "8000"}, 9090);
13+
assertThat(port).isEqualTo(8000);
14+
}
15+
16+
@Test
17+
void config_port_used_when_no_cli_arg() {
18+
int port = App.resolvePort(new String[]{}, 9090);
19+
assertThat(port).isEqualTo(9090);
20+
}
21+
}

src/test/java/org/example/StaticFileHandlerTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.nio.file.Files;
1111
import java.nio.file.Path;
1212
import static org.junit.jupiter.api.Assertions.*;
13+
import static org.example.http.HttpResponseBuilder.*;
1314

1415
/**
1516
* Unit test class for verifying the behavior of the StaticFileHandler class.
@@ -48,7 +49,7 @@ void test_file_that_exists_should_return_200() throws IOException {
4849
//Assert
4950
String response = fakeOutput.toString();//Converts the captured byte stream into a String for verification
5051

51-
assertTrue(response.contains("HTTP/1.1 200 OK")); // Assert the status
52+
assertTrue(response.contains("HTTP/1.1 " + SC_OK + " OK")); // Assert the status
5253
assertTrue(response.contains("Hello Test")); //Assert the content in the file
5354

5455
assertTrue(response.contains("Content-Type: text/html; charset=UTF-8")); // Verify the correct Content-type header
@@ -74,7 +75,7 @@ void test_file_that_does_not_exists_should_return_404() throws IOException {
7475
//Assert
7576
String response = fakeOutput.toString();//Converts the captured byte stream into a String for verification
7677

77-
assertTrue(response.contains("HTTP/1.1 404 Not Found")); // Assert the status
78+
assertTrue(response.contains("HTTP/1.1 " + SC_NOT_FOUND + " Not Found")); // Assert the status
7879

7980
}
8081

@@ -94,7 +95,7 @@ void test_path_traversal_should_return_403() throws IOException {
9495
// Assert
9596
String response = fakeOutput.toString();
9697
assertFalse(response.contains("TOP SECRET"));
97-
assertTrue(response.contains("HTTP/1.1 403 Forbidden"));
98+
assertTrue(response.contains("HTTP/1.1 " + SC_FORBIDDEN + " Forbidden"));
9899
}
99100

100101
@ParameterizedTest
@@ -115,7 +116,7 @@ void sanitized_uris_should_return_200(String uri) throws IOException {
115116
handler.sendGetRequest(out, uri);
116117

117118
// Assert
118-
assertTrue(out.toString().contains("HTTP/1.1 200 OK"));
119+
assertTrue(out.toString().contains("HTTP/1.1 " + SC_OK + " OK"));
119120
}
120121

121122
@Test
@@ -131,7 +132,7 @@ void null_byte_injection_should_not_return_200() throws IOException {
131132

132133
// Assert
133134
String response = out.toString();
134-
assertFalse(response.contains("HTTP/1.1 200 OK"));
135-
assertTrue(response.contains("HTTP/1.1 404 Not Found"));
135+
assertFalse(response.contains("HTTP/1.1 " + SC_OK + " OK"));
136+
assertTrue(response.contains("HTTP/1.1 " + SC_NOT_FOUND + " Not Found"));
136137
}
137138
}

0 commit comments

Comments
 (0)