Skip to content

Commit 052d32c

Browse files
authored
Merge branch 'main' into test/HttpResponse
2 parents 5a0fead + 831901b commit 052d32c

22 files changed

+653
-53
lines changed

build.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build.commit=1c8d31d
2+
build.version=1.0-SNAPSHOT
3+
build.time=2026-02-20T22:14:43Z

pom.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@
88
<artifactId>JavaHttpServer</artifactId>
99
<version>1.0-SNAPSHOT</version>
1010

11+
<scm>
12+
<connection>scm:git:https://github.com/ithsjava25/project-webserver-juv25d.git</connection>
13+
<developerConnection>scm:git:https://github.com/ithsjava25/project-webserver-juv25d.git</developerConnection>
14+
<url>https://github.com/ithsjava25/project-webserver-juv25d</url>
15+
<tag>HEAD</tag>
16+
</scm>
17+
1118
<properties>
1219
<maven.compiler.release>25</maven.compiler.release>
1320
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1421
<junit.jupiter.version>6.0.2</junit.jupiter.version>
1522
<assertj.core.version>3.27.7</assertj.core.version>
1623
<mockito.version>5.21.0</mockito.version>
24+
<build.time>${maven.build.timestamp}</build.time>
1725
<argLine/>
1826
</properties>
1927
<dependencies>
@@ -176,6 +184,24 @@
176184
</targetTests>
177185
</configuration>
178186
</plugin>
187+
<plugin>
188+
<groupId>org.codehaus.mojo</groupId>
189+
<artifactId>buildnumber-maven-plugin</artifactId>
190+
<version>3.2.0</version>
191+
<executions>
192+
<execution>
193+
<phase>validate</phase>
194+
<goals>
195+
<goal>create</goal>
196+
</goals>
197+
</execution>
198+
</executions>
199+
<configuration>
200+
<doCheck>false</doCheck>
201+
<doUpdate>false</doUpdate>
202+
<shortRevisionLength>7</shortRevisionLength>
203+
</configuration>
204+
</plugin>
179205
<plugin>
180206
<groupId>org.apache.maven.plugins</groupId>
181207
<artifactId>maven-shade-plugin</artifactId>
@@ -200,5 +226,32 @@
200226
</executions>
201227
</plugin>
202228
</plugins>
229+
<pluginManagement>
230+
<plugins>
231+
<plugin>
232+
<groupId>org.codehaus.mojo</groupId>
233+
<artifactId>buildnumber-maven-plugin</artifactId>
234+
<version>3.2.0</version>
235+
<executions>
236+
<execution>
237+
<phase>validate</phase>
238+
<goals>
239+
<goal>create</goal>
240+
</goals>
241+
</execution>
242+
</executions>
243+
</plugin>
244+
</plugins>
245+
</pluginManagement>
246+
<resources>
247+
<resource>
248+
<directory>src/main/resources</directory>
249+
<filtering>false</filtering>
250+
</resource>
251+
<resource>
252+
<directory>src/main/resources-filtered</directory>
253+
<filtering>true</filtering>
254+
</resource>
255+
</resources>
203256
</build>
204257
</project>

src/main/java/org/juv25d/App.java

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package org.juv25d;
22

3-
import org.juv25d.filter.IpFilter;
4-
import org.juv25d.filter.LoggingFilter;
5-
import org.juv25d.filter.RateLimitingFilter;
3+
import org.juv25d.filter.*;
64
import org.juv25d.logging.ServerLogging;
75
import org.juv25d.http.HttpParser;
6+
import org.juv25d.plugin.HealthCheckPlugin;
7+
import org.juv25d.plugin.MetricPlugin;
88
import org.juv25d.plugin.NotFoundPlugin; // New import
99
import org.juv25d.plugin.StaticFilesPlugin;
10-
import org.juv25d.router.SimpleRouter; // New import
10+
import org.juv25d.router.SimpleRouter;
1111
import org.juv25d.util.ConfigLoader;
12-
import org.juv25d.filter.RedirectFilter;
13-
import org.juv25d.filter.RedirectRule;
12+
1413
import java.util.List;
1514

1615
import java.util.Set;
@@ -21,40 +20,34 @@ public static void main(String[] args) {
2120
ConfigLoader config = ConfigLoader.getInstance();
2221
Logger logger = ServerLogging.getLogger();
2322
HttpParser httpParser = new HttpParser();
24-
2523
Pipeline pipeline = new Pipeline();
26-
// Configure redirect rules
24+
25+
pipeline.addGlobalFilter(new SecurityHeadersFilter(), 0);
26+
27+
pipeline.addGlobalFilter(new LoggingFilter(), 1);
28+
29+
pipeline.addGlobalFilter(new IpFilter(Set.of(), Set.of()), 2);
30+
31+
if (config.isRateLimitingEnabled()) {pipeline.addGlobalFilter(new RateLimitingFilter(
32+
config.getRequestsPerMinute(), config.getBurstCapacity()), 3);}
33+
2734
List<RedirectRule> redirectRules = List.of(
2835
new RedirectRule("/old-page", "/new-page", 301),
2936
new RedirectRule("/temp", "https://example.com/temporary", 302),
3037
new RedirectRule("/docs/*", "/documentation/", 301)
3138
);
32-
pipeline.addGlobalFilter(new RedirectFilter(redirectRules), 0);
33-
3439

35-
// IP filter is enabled but configured with open access during development
36-
// White/blacklist can be tightened when specific IP restrictions are decided
37-
pipeline.addGlobalFilter(new IpFilter(
38-
Set.of(),
39-
Set.of()
40-
), 0);
40+
pipeline.addGlobalFilter(new RedirectFilter(redirectRules), 4);
4141

42-
pipeline.addGlobalFilter(new LoggingFilter(), 0);
4342

44-
if (config.isRateLimitingEnabled()) {
45-
pipeline.addGlobalFilter(new RateLimitingFilter(
46-
config.getRequestsPerMinute(),
47-
config.getBurstCapacity()
48-
), 0);
49-
}
50-
51-
// Initialize and configure SimpleRouter
5243
SimpleRouter router = new SimpleRouter();
44+
router.registerPlugin("/metric", new MetricPlugin()); //Register MetricPlugin for a specified path
45+
router.registerPlugin("/health", new HealthCheckPlugin()); //Register HealthCheckPlugin for a specified path
5346
router.registerPlugin("/", new StaticFilesPlugin()); // Register StaticFilesPlugin for the root path
5447
router.registerPlugin("/*", new StaticFilesPlugin()); // Register StaticFilesPlugin for all paths
5548
router.registerPlugin("/notfound", new NotFoundPlugin()); // Example: Register NotFoundPlugin for a specific path
5649

57-
pipeline.setRouter(router); // Set the router in the pipeline
50+
pipeline.setRouter(router);
5851

5952
DefaultConnectionHandlerFactory handlerFactory =
6053
new DefaultConnectionHandlerFactory(httpParser, logger, pipeline);
@@ -65,7 +58,6 @@ public static void main(String[] args) {
6558
handlerFactory,
6659
pipeline
6760
);
68-
6961
server.start();
7062
}
7163
}

src/main/java/org/juv25d/filter/IpFilter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package org.juv25d.filter;
22

3+
import org.juv25d.filter.annotation.Global;
34
import org.juv25d.http.HttpRequest;
45
import org.juv25d.http.HttpResponse;
56

67
import java.io.IOException;
78
import java.nio.charset.StandardCharsets;
89
import java.util.Set;
910

11+
@Global(order = 2)
1012
public class IpFilter implements Filter {
1113

1214
private final Set<String> whitelist;

src/main/java/org/juv25d/filter/LoggingFilter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package org.juv25d.filter;
22

3+
import org.juv25d.filter.annotation.Global;
34
import org.juv25d.http.HttpRequest;
45
import org.juv25d.http.HttpResponse;
56

67
import java.io.IOException;
78

9+
@Global(order = 1)
810
public class LoggingFilter implements Filter {
911

1012
@Override

src/main/java/org/juv25d/filter/RateLimitingFilter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.github.bucket4j.Bandwidth;
44
import io.github.bucket4j.Bucket;
55
import io.github.bucket4j.Refill;
6+
import org.juv25d.filter.annotation.Global;
67
import org.juv25d.http.HttpRequest;
78
import org.juv25d.http.HttpResponse;
89
import org.juv25d.logging.ServerLogging;
@@ -18,6 +19,7 @@
1819
* A filter that implements rate limiting for incoming HTTP requests.
1920
* It uses a token bucket algorithm via Bucket4J to limit the number of requests per client IP.
2021
*/
22+
@Global(order = 3)
2123
public class RateLimitingFilter implements Filter {
2224

2325
private static final Logger logger = ServerLogging.getLogger();

src/main/java/org/juv25d/filter/RedirectFilter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.juv25d.filter;
22

3+
import org.juv25d.filter.annotation.Global;
34
import org.juv25d.http.HttpRequest;
45
import org.juv25d.http.HttpResponse;
56

@@ -27,6 +28,8 @@
2728
* pipeline.addFilter(new RedirectFilter(rules));
2829
* </pre>
2930
*/
31+
32+
@Global(order = 4)
3033
public class RedirectFilter implements Filter {
3134
private final List<RedirectRule> rules;
3235
private final Logger logger;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
package org.juv25d.filter;
3+
4+
import org.juv25d.filter.annotation.Global;
5+
import org.juv25d.http.HttpRequest;
6+
import org.juv25d.http.HttpResponse;
7+
import java.io.IOException;
8+
9+
/**
10+
* Filter that adds security headers to every HTTP response.
11+
* This helps protect against attacks such as Clickjacking and MIME sniffing.
12+
*/
13+
@Global(order = 0)
14+
public class SecurityHeadersFilter implements Filter {
15+
16+
@Override
17+
public void doFilter(HttpRequest req, HttpResponse res, FilterChain chain) throws IOException {
18+
try {
19+
chain.doFilter(req, res);
20+
} finally {
21+
22+
res.setHeader("X-Content-Type-Options", "nosniff");
23+
res.setHeader("X-Frame-Options", "DENY");
24+
res.setHeader("X-XSS-Protection", "0");
25+
res.setHeader("Referrer-Policy", "no-referrer");
26+
27+
}
28+
}
29+
}
30+
31+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.juv25d.filter;
2+
3+
import org.juv25d.http.HttpRequest;
4+
import org.juv25d.http.HttpResponse;
5+
import org.juv25d.logging.ServerLogging;
6+
7+
import java.io.IOException;
8+
import java.util.logging.Logger;
9+
10+
public class TimingFilter implements Filter {
11+
12+
private static final Logger logger = ServerLogging.getLogger();
13+
14+
@Override
15+
public void doFilter(HttpRequest req, HttpResponse res, FilterChain chain) throws IOException {
16+
long start = System.nanoTime();
17+
18+
chain.doFilter(req, res);
19+
20+
long durationMs = (System.nanoTime() - start) / 1_000_000;
21+
logger.info(req.method() + " " + req.path() + " took " + durationMs + " ms");
22+
23+
}
24+
}

src/main/java/org/juv25d/http/HttpRequest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,10 @@ public record HttpRequest(
99
String httpVersion,
1010
Map<String, String> headers,
1111
byte[] body,
12-
String remoteIp
13-
) {}
12+
String remoteIp,
13+
long creationTimeNanos
14+
) {
15+
public HttpRequest(String method, String path, String queryString, String httpVersion, Map<String, String> headers, byte[] body, String remoteIp) {
16+
this(method, path, queryString, httpVersion, headers, body, remoteIp, System.nanoTime());
17+
}
18+
}

0 commit comments

Comments
 (0)