96 Create page for testing filytypes#26
Conversation
Add ci workflow for github actions.
* build: configure pom.xml with needed plugin/tools. Setup Java 25 environment with JUnit 5, Mockito, JaCoCo, Pitest, and Spotless * fix: add missing test scope for awaitility
* Dockerfile that builds an image in a docker container then runs in another docker container Current implementation uses Temporary App.class reference before relevant file is created to start server. * Fixed unverified commit * Set up non-root user and updated Dockerfile to use user. Fixed file path to use /app/ instead of /app/org/example to prevent unnessary nesting of packages.
* added parser class for headers * refactoring * refactoring * refactoring, added getHeadersMap * refactoring * refactoring code, adding debug boolean * added unit tests for HttpParser.java class * refactoring and all green tests for class * refactoring the code * refactoring the bufferedReader * refactoring with coderabbit feedback for header put to merge * refactoring with coderabbit feedback for header put to merge, changed headersmap * refactoring from reviewer input * refactoring for code rabbit comments
* Add HttpResponseBuilder and its tests Signed-off-by: JohanHiths <johan.hietala@iths.se> * Implement minimal HTTP response builder Signed-off-by: JohanHiths <johan.hietala@iths.se> * update coderabbit * more coderabbit fixes Signed-off-by: JohanHiths <johan.hietala@iths.se> * Bytte från httptest till http efter rekommendationer från Xeutos * code rabbit fix * fixed more code rabbit problems --------- Signed-off-by: JohanHiths <johan.hietala@iths.se>
* added parser class for headers * refactoring * refactoring * refactoring, added getHeadersMap * refactoring * adding class for parsing requestLine (method, path, version). Has getters/setters for the three. * refactoring code, private setters * added tests for throwing error * refactoring the bufferedReader * refactoring, adding check for requestLineArray.length() is less or equals to two with added unit test * refactoring, adding check for requestLineArray.length() is less or equals to two with added unit test * refactoring, adding test for null value of input stream * refactoring from coderabbit input * refactoring test class. * refactoring, adding debug boolean flag for logger lines * refactoring and testing buffered reader stream * refactoring, changed class HttpParser.java to extend HttpParseRequestLine.java and making them share the same buffered reader. Added method to set the reader and then methods to call the HttpParser * refactoring, changed class HttpParser.java to extend HttpParseRequestLine.java and making them share the same buffered reader. Added method to set the reader and then methods to call the HttpParser
* Add Bucket4j dependency in pom file * Extract Bucket4j version into a property and update version in dependency for consistency
* Add support for serving static files - Introduced `StaticFileHandler` to serve static files from the `www` directory. - Enhanced `HttpResponseBuilder` to support byte array bodies. - Made `setReader` method public in `HttpParser` to improve flexibility. - Code tested via Insomnia by coding a temporary method for multithreads in TcpServer.java, this is now removed before future implementations of ConnectionHandler Co-authored-by: Daniel Fahlén xsz300@gmail.com * Fix typo in `HttpResponseBuilder` (contentLength) and refine body handling logic Co-authored-by: Daniel Fahlén xsz300@gmail.com * Add basic HTML structure to `index.html` in `www` directory * Make `handleGetRequest` method private in `StaticFileHandler` to encapsulate functionality
* Updates pom.xml, with jackson-dependencies, for config file * Updates pom.xml, removes jackson-annotations:2.20, because it was apparently unnecessary.
* * Move HTTP handling logic from TcpServer to a dedicated ConnectionTask class * Implement virtual thread execution for better scalability * Add regex-based URI routing to support clean URLs and default to index.html * Ensure sockets are properly closed Co-authored-by: Caroline Nordbrandt <caroline_nordbradt@hotmail.com> * change thrown exception to runtime instead with appropiet message in tcpServer. --------- Co-authored-by: Caroline Nordbrandt <caroline_nordbradt@hotmail.com>
* Added basic YAML config-file. * Added class ConfigLoader with static classes for encapsulation * Added static metod loadOnce and step one of static method load * Added static method createMapperFor that checks for YAML or JSON-files before creating an ObjectMapper object. * implement ConfigLoader refs #13 * Added AppConfig.java record for config after coderabbit feedback * Updated ConfigLoader to use AppConfig record and jackson 3 * Added tests for ConfigLoader and reset cached method in ConfigLoader to ensure test isolation with static cache * Removed unused dependency. Minor readability tweaks in AppConfig. * Added check for illegal port numbers to withDefaultsApplied-method. * Added test for illegal port numbers.
* Add 404 error handling to `StaticFileHandler` with fallback page * Add test coverage for `StaticFileHandler` and improve constructor flexibility - Introduced a new constructor in `StaticFileHandler` to support custom web root paths, improving testability. - Added `StaticFileHandlerTest` to validate static file serving and error handling logic. * Add test for 404 handling in `StaticFileHandler` - Added a test to ensure nonexistent files return a 404 response. - Utilized a temporary directory and fallback file for improved test isolation. * Verify `Content-Type` header in `StaticFileHandlerTest` after running Pittest, mutations survived where setHeaders could be removed without test failure. * Remove unused `.btn` styles from `pageNotFound.html` * Improve 404 handling in `StaticFileHandler`: add fallback to plain text response if `pageNotFound.html` is missing, and fix typo in `pageNotFound.html`, after comments from CodeRabbit.
* Implements configuration loading and ensures that ConfigLoader is invoked during application startup (App.main). * Minor formating.
* initial commit, added interfaces Filter and FilterChain * Added HttpRequest class, groups together all information about a request that the server needs and easier to handle by future filters * added interfaces Filter and FilterChain with Java Servlet Filter architecture. * added FilterChainImpl * Corrected imports from JDKS HttpRequest, to projects HttpRequest class * Changed, params for FilterChain * Updated HttpRequest with attributes, * Revert "Updated HttpRequest with attributes," This reverts commit 0fd490e.
* Added MIME detector class and test class * Added logic for Mime detector class * Added Unit tests * Added logic in HttpResponseBuilder and tests to try it out * Solves duplicate header issue * Removed a file for another issue * Changed hashmap to Treemap per code rabbits suggestion * Corrected logic error that was failing tests as per P2P review * Added more reason phrases and unit testing, also applied code rabbits suggestions! * Added changes to Responsebuilder to make merging easier * Changed back to earlier commit to hande byte corruption new PR * Added StaticFileHandler from main * Added staticFileHandler with binary-safe writing * Fix: Normalize Content-Type charset to uppercase UTF-8 Changed 'charset=utf-8' to 'charset=UTF-8' in StaticFileHandlerTest to match MimeTypeDetector output and align with HTTP RFC standard. Uppercase UTF-8 is the correct format per RFC 2616/7231.
* Update Dockerfile Dockerfiles now copies www folder aswell * Added building and copying of dependency jar files * Fix dependency path in Dockerfile and update classpath in ENTRYPOINT configuration. * Fixed typo in Entrypoint configuration * Expose port 8080 in Dockerfile and changed appuser to come before ENTRYPOINT configuration. * Adjust Dockerfile paths for classes and dependencies, update `COPY` targets accordingly.
* Added comprehensive README.MD * Added formatting recommendations, clearer info
* Prevent path traversal and sanitize URI in StaticFileHandler. * Add test for path traversal protection and support 403 responses. * Add tests for URI sanitization and handling of encoded/special URLs. * Add test for null byte injection prevention in StaticFileHandler * Improve StaticFileHandler path traversal handling and test coverage * Improve URI sanitization and add test for 404 response handling in StaticFileHandler
* Resolve port: CLI > config > default * Wire port resolution to AppConfig/ConfigLoader and update docs/tests * Update PortConfigurationGuide.md * Update PortConfigurationGuide.md * Remove ServerPortResolver; use ConfigLoader for port * Update PortConfigurationGuide.md * Update PortConfigurationGuide.md * may be done
* refactor: add predefined HTTP status code constants to HttpResponseBuilder * refactor: use status code constants in StaticFileHandler * test: refactor StaticFileHandlerTest to use status code constants * test: refactor HttpResponseBuilderTest to use status code constants and explicit assertations
* Fix path in Dockerfile for `www` directory copy operation * Correct relative path for `www` directory in Dockerfile copy operation
* Add IpFilter and corresponding test skeleton Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Extend IpFilter with blocklist mode and add unit tests Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Enhance IpFilter to return 403 for blocked IPs and add corresponding test case Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Extend IpFilter with allowlist mode and add corresponding unit tests Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Refactor IpFilter to support both allowlist and blocklist modes, update logic, and add unit tests for allowlist mode Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Handle missing client IP in IpFilter, return 400 response, and add corresponding test case Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Refactor tests in `IpFilterTest` to use `assertAll` for improved assertion grouping and readability Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Refactor `IpFilter` to use `HttpResponse` instead of `HttpResponseBuilder` and update tests accordingly Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Add unit tests for edge cases in `IpFilter` allowlist and blocklist modes Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Refactor `IpFilter` and tests to use `HttpResponseBuilder` instead of `HttpResponse` Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Handle empty client IP in `IpFilter`, return 400 response, and add corresponding test case Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Add comments to `IpFilter` empty methods, clarifying no action is required Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Fix typos in comments within `IpFilterTest` Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Add Javadoc comments to `IpFilter` and `IpFilterTest` for improved clarity and documentation * Refactor `IpFilter` to use thread-safe collections and normalize IP addresses * Make `mode` field in `IpFilter` volatile to ensure thread safety * Ensure UTF-8 encoding for response string in `IpFilterTest` and add attribute management to `HttpRequest` * Ensure UTF-8 encoding for response string in `IpFilterTest` and add attribute management to `HttpRequest` Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Integrate IP filtering into `ConnectionHandler` and update configuration to support filter settings Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Refactor IP filter check in `ConnectionHandler` to use `Boolean.TRUE.equals` for improved null safety Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * Validate null inputs for allowed/blocked IPs in `IpFilter`, enhance test coverage, and fix typographical error in comments Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> * refactor: extract applyFilters() method using FilterChainImpl Co-authored-by: Andreas Kaiberger <andreas.kaiberger@gmail.com> * refactor: cache filter list at construction time Co-authored-by: Andreas Kaiberger <andreas.kaiberger@gmail.com> * refactor: cache filter list at construction time Co-authored-by: Andreas Kaiberger <andreas.kaiberger@gmail.com> * test: verify GPG signing * Replace hardcoded status codes in `IpFilter` and `ConnectionHandler` with constants from `HttpResponseBuilder` for better maintainability Co-authored-by: Rickard Ankar <rickard.ankar@iths.se> --------- Co-authored-by: Rickard Ankar <rickard.ankar@iths.se>
* Re-commit LocaleFilter + tests to clean branch for PR * Update LocaleFilter to handle quality weights and improve javadoc * Fix: rename test method to reflect actual headers scenario * Fix: ensure resolveLocale never returns empty string; strip quality weights
* Add LoggFilter and update HttpResponseBuilder with method getStatusCode() in order to use it in logging * Refactor code * Change magic number to constans in httpresponsebuilder * Add LoggFilter and update HttpResponseBuilder with method getStatusCode() in order to use it in logging * Refactor code * Added tests -> LoggingFilterTest * Trigger rebuild * Git is hallucinating. Trying to fix problem * Final version (hopefully)
* Add error handling for when client request fail -> return internal server error 500 * Create ConnectionFactory in order to be able to test the TcpServer. Implement factory into TcpServer and App. * Create test to check whether handleClient throws internal server error when there is an exception * Modify test * Update logic -> seperate handleClient and processRequest in order to have open socket when handling internal server error * Exchange Printwriter to Outputstream in handleInternalServerError * Add error handling for when client request fail -> return internal server error 500 * Create ConnectionFactory in order to be able to test the TcpServer. Implement factory into TcpServer and App. * Create test to check whether handleClient throws internal server error when there is an exception * Modify test * Update logic -> seperate handleClient and processRequest in order to have open socket when handling internal server error * Exchange Printwriter to Outputstream in handleInternalServerError * Rebase main onto bransch. Update App -> add Connectionhandler::new Also update handleInternalServerError
* Re-commit LocaleFilterWithCookie + tests to clean branch for PR * Fix: make header lookups case-insensitive to avoid incorrect default locale fallback.
* Remove .html concat to support all files * Add test for jpg handling in ConnectionHandler (TDD:RED), related to #69 * Make ConnectionHandler testable with webroot parameter * Fix: Strip leading slash from URI to prevent absolute path (coderabbit)
… (#56) * ensure global detection for empty route patterns * larify global vs route-specific registrations * add support for exact and /prefix/* matching * add coverage for global, route-specific, ordering and short-circuit * configurable global and route-specific filters with ordering * changed package * removed from branch * Add missing tests for configurable filter pipeline * Refactor filter pipeline: sort FilterRegistration directly by order * Fix RoutePattern wildcard to match base path (/api/* matches /api) * Restore App entry point and basic tests from main * Bump org.apache.maven.plugins:maven-dependency-plugin (#6) (#55) * Bump org.apache.maven.plugins:maven-dependency-plugin (#6) Bumps the maven-deps group with 1 update: [org.apache.maven.plugins:maven-dependency-plugin](https://github.com/apache/maven-dependency-plugin). Updates `org.apache.maven.plugins:maven-dependency-plugin` from 3.9.0 to 3.10.0 - [Release notes](https://github.com/apache/maven-dependency-plugin/releases) - [Commits](apache/maven-dependency-plugin@maven-dependency-plugin-3.9.0...maven-dependency-plugin-3.10.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-dependency-plugin dependency-version: 3.10.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: maven-deps ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump org.junit.jupiter:junit-jupiter in the maven-deps group (#13) Bumps the maven-deps group with 1 update: [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit-framework). Updates `org.junit.jupiter:junit-jupiter` from 6.0.2 to 6.0.3 - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](junit-team/junit-framework@r6.0.2...r6.0.3) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter dependency-version: 6.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: maven-deps ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add short-circuit tests for configurable filter pipeline * Add tests for response-phase and global-vs-route ordering * pom fix - no changes * Align server filter pipeline with main FilterChainImpl and HttpResponseBuilder * Align filter pipeline with main filter chain and harden immutability --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Viktor Lindell <v.lindell@hotmail.com> Co-authored-by: viktorlindell12 <viktor.lindell@iths.se> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add CompressionFilter skeleton with basic structure * Add Accept-Encoding header detection for gzip * Add Accept-Encoding header detection for gzip * Implement gzip compression for response bodies * Add Content-Encoding * Added test file * Add content-type filtering to skip non-compressible formats * Add Javadoc * coderabbit fixes * added getter for HttpResponseBuilder and rewrote code that used reflection * fixed IOException
* Create RequestTimeOutFilter and RequestTimeOutFilterTest Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Revert "Create RequestTimeOutFilter and RequestTimeOutFilterTest" This reverts commit efc883d. * Create RequestTimeOutFilter and RequestTimeOutFilterTest Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Add test for exception in RequestTimeOutFilterTest Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Add a test for exception in RequestTimeOutFilterTest Changes by ebbaandersson * Add javadocs for RequestTimeOutFilter Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Changes made after CodeRabbit Review Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Change ExecutorService, add rejectedExecutionException, add method handleInternalError Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Changes tests to assert the new code in RequestTimeOutFilter * Create RequestTimeOutFilter and RequestTimeOutFilterTest Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Add test for exception in RequestTimeOutFilterTest Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Add a test for exception in RequestTimeOutFilterTest Changes by ebbaandersson * Add javadocs for RequestTimeOutFilter Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Changes made after CodeRabbit Review Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Change ExecutorService, add rejectedExecutionException, add method handleInternalError Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Changes tests to assert the new code in RequestTimeOutFilter * add a future.cancel to stop the worker task. add defensive copying and unmodifiable views of setter and getter in HttpResponseBuilder Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Removes "static" from ExecutorService. Adds a test which checks that the timeout-time is bigger than zero Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> * Adds chain-execution verification to happy-path-test. * Implementing a transfer from existing respons to shadowResponse in the beginning to make sure we don't lose information Co-authored-by: Ebba Andersson <eeebbaandersson@gmail.com> --------- Co-authored-by: Fredrik Mohlen <fredrikmohlen@gmail.com>
* Added new methods loadFromClassPath, loadOnceWithClasspathFallback and createMapperForName. Modified createMapperFor-method to work with createMapperForName * Updated main to use new method loadOnceWithClasspathFallback * Added new test: fallback_to_classpath_when_external_file_missing() * reworked loadOnceWithCLasspathFallback to adress external file deleted between Files.exists and load() silently bypasses the classpath fallback. Removed unused code from main. * Replaced new YAMLFactory() with YAMLFactory.builder().build() after feedback from coderabbit. * Uppdated main to run both loadOnceWithClasspathFallback and cli. * Added null preconditions after feedback from coderabbit and removed unused import.
- Made the JavaScript safer and easier to read - Added comments and docstrings to the JavaScript - Added test files, the soundbite is taken from a royalty-free music library and was combined with the GIF version of the logo to create the video files
Merging changes to main branch to solve potential merge issues before pull request
📝 WalkthroughWalkthroughA comprehensive Java HTTP web server implementation is introduced with configuration management, a filter pipeline architecture, static file serving capabilities, HTTP parsing/response building infrastructure, Docker containerization, and CI/CD automation. The addition spans core server components, filter implementations, configuration classes, extensive test coverage, and static resources. Changes
Sequence DiagramsequenceDiagram
participant Client
participant TcpServer
participant ConnectionHandler
participant HttpParser
participant FilterChain as Filter Pipeline
participant StaticFileHandler
participant HttpResponseBuilder
Client->>TcpServer: Connect on port 8080
TcpServer->>ConnectionHandler: Create per connection
ConnectionHandler->>HttpParser: Parse HTTP request
HttpParser-->>ConnectionHandler: HttpRequest object
ConnectionHandler->>FilterChain: Apply filters (IP, Compression, Logging, etc.)
FilterChain->>FilterChain: Execute filters in sequence
FilterChain-->>ConnectionHandler: Filtered HttpResponseBuilder
ConnectionHandler->>StaticFileHandler: Resolve & serve requested file
StaticFileHandler->>HttpResponseBuilder: Build response (200/404/403)
HttpResponseBuilder-->>StaticFileHandler: Assembled HTTP bytes
StaticFileHandler-->>ConnectionHandler: Response ready
ConnectionHandler-->>TcpServer: Send response bytes
TcpServer-->>Client: HTTP response (200/404/etc)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (11)
PortConfigurationGuide.md-26-29 (1)
26-29:⚠️ Potential issue | 🟡 MinorFix YAML indentation in the example.
The
portkey must be indented underserver:to be valid YAML. The current example would create a top-levelportkey instead ofserver.port.📝 Proposed fix
```yaml server: -port: 9090 + port: 9090</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@PortConfigurationGuide.mdaround lines 26 - 29, The YAML example has
incorrect indentation soportis defined at top-level instead of under
server; update the example so theportkey is indented two spaces beneath
server(i.e., makeserver:the parent andport:a child) so the documented
configuration reflectsserver.portcorrectly; verify the block showsserver:
on one line andport: 9090indented under it.</details> </blockquote></details> <details> <summary>.github/workflows/release.yml-13-13 (1)</summary><blockquote> `13-13`: _⚠️ Potential issue_ | _🟡 Minor_ **Update `actions/checkout` to a valid version.** `actions/checkout@v6.0.2` does not exist. The latest release is `v6.0.1`. Use either `v6` for automatic patch updates or pin to `v6.0.1`. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.github/workflows/release.yml at line 13, Replace the invalid
actions/checkout@v6.0.2 reference in the workflow with a valid tag; update the
checkout step that currently uses "actions/checkout@v6.0.2" to either the
floating major tag "actions/checkout@v6" for automatic patch updates or pin it
to the known release "actions/checkout@v6.0.1" so the workflow uses a valid,
published version.</details> </blockquote></details> <details> <summary>www/file-test.html-320-326 (1)</summary><blockquote> `320-326`: _⚠️ Potential issue_ | _🟡 Minor_ **Add missing-file handling for PDF/video/audio previews.** Image/text paths show a clear “file not found” fallback, but PDF/video/audio do not. Missing assets currently degrade to broken players/embeds without consistent feedback. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@www/file-test.htmlaround lines 320 - 326, The PDF/video/audio branches
(category === 'pdf', 'video', 'audio' that set contentArea.innerHTML with
,</details> </blockquote></details> <details> <summary>README.md-2-2 (1)</summary><blockquote> `2-2`: _⚠️ Potential issue_ | _🟡 Minor_ **Resolve markdownlint findings in this README block.** The current content still has lint-visible structure issues (heading increment, extra heading spacing, and fenced blocks missing language tags), which will keep docs quality checks noisy. Also applies to: 37-37, 39-39, 80-80, 87-87, 134-134, 234-234, 283-283, 340-340 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@README.mdat line 2, Fix the markdownlint issues around the README heading
"### Class JUV25G" by normalizing heading levels (ensure proper incremental
heading hierarchy, e.g., use "##" or "####" to match surrounding sections),
remove extra blank lines after headings (no double spacing), and add language
tags to all fenced code blocks (e.g.,json,bash, etc.); apply the same
adjustments to the other occurrences referenced (the other blocks containing the
same heading pattern or fenced blocks) so the document conforms to markdownlint
rules.</details> </blockquote></details> <details> <summary>README.md-48-49 (1)</summary><blockquote> `48-49`: _⚠️ Potential issue_ | _🟡 Minor_ **Fix Quick Start commands (`git clone` typo + directory mismatch).** At Line 48, command is duplicated (`git clone git clone ...`). At Line 49, the directory name should match the actual cloned repo folder. <details> <summary>Diff suggestion</summary> ```diff -git clone git clone https://github.com/ithsjava25/project-webserver-juv25g.git -cd project-webserver +git clone https://github.com/ithsjava25/project-webserver-juv25g.git +cd project-webserver-juv25g ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 48 - 49, Fix the Quick Start commands by removing the duplicated word in the clone command and making the cd target match the cloned repository folder; replace the line containing "git clone git clone https://github.com/ithsjava25/project-webserver-juv25g.git" with a single "git clone ..." and update the following "cd project-webserver" to "cd project-webserver-juv25g" so the commands correctly clone and enter the cloned repo directory. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/ConnectionHandlerTest.java-31-35 (1)</summary><blockquote> `31-35`: _⚠️ Potential issue_ | _🟡 Minor_ **Reset global `ConfigLoader` state after this test class.** This class mutates global cached config in setup but never clears it, which can make later tests order-dependent. <details> <summary>💡 Suggested fix</summary> ```diff -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; @@ `@BeforeAll` static void setupConfig() { ConfigLoader.resetForTests(); ConfigLoader.loadOnce(Path.of("nonexistent-test-config.yml")); } + + `@AfterAll` + static void tearDownConfig() { + ConfigLoader.resetForTests(); + } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/ConnectionHandlerTest.java` around lines 31 - 35, The setupConfig method mutates the global cached config and doesn't clear it afterwards; add an `@AfterAll` static teardown method in ConnectionHandlerTest (e.g., tearDownConfig or resetConfig) that calls ConfigLoader.resetForTests() to restore global state after the test class, ensuring ConfigLoader.resetForTests() is invoked following setupConfig's ConfigLoader.loadOnce(...) to avoid order-dependent tests. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/LoggingFilter.java-38-41 (1)</summary><blockquote> `38-41`: _⚠️ Potential issue_ | _🟡 Minor_ **Copy-paste error in comment.** The comment says "No initialization needed" but this is the `destroy()` method. <details> <summary>📝 Suggested fix</summary> ```diff `@Override` public void destroy() { - //No initialization needed + //No cleanup needed } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/LoggingFilter.java` around lines 38 - 41, Update the incorrect copy-paste comment inside the LoggingFilter.destroy() method: replace "//No initialization needed" with a correct remark such as "//No cleanup needed" or "//No resources to release" (or remove the comment entirely) so the comment accurately describes tear-down behavior in the destroy() method of class LoggingFilter. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/filter/CompressionFilterTest.java-161-161 (1)</summary><blockquote> `161-161`: _⚠️ Potential issue_ | _🟡 Minor_ **Test uses malformed JSON.** The JSON string `"{\"data\": " + "\"value\",".repeat(200) + "}"` produces invalid JSON with a trailing comma before the closing brace. While this doesn't affect the compression test's validity, using valid JSON would be more realistic. <details> <summary>📝 Suggested fix for valid JSON</summary> ```diff - String jsonData = "{\"data\": " + "\"value\",".repeat(200) + "}"; + String jsonData = "{\"data\": [" + "\"value\",".repeat(199) + "\"value\"]}"; ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/filter/CompressionFilterTest.java` at line 161, The test in CompressionFilterTest constructs malformed JSON via the jsonData variable ("{\"data\": " + "\"value\",".repeat(200) + "}") which leaves a trailing comma; update jsonData to produce valid JSON (e.g., create an array or join repeated values without a trailing comma) so the test uses well-formed JSON while preserving the same payload size for compression assertions; locate the jsonData construction in CompressionFilterTest and replace the string building with a valid JSON creation approach (for example build a JSON array or use String.join on repeated elements) so the compression behavior remains unchanged. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/TcpServer.java-7-7 (1)</summary><blockquote> `7-7`: _⚠️ Potential issue_ | _🟡 Minor_ **Unused import.** `PrintWriter` is imported but not used in this file. <details> <summary>🧹 Remove unused import</summary> ```diff import java.io.IOException; import java.io.OutputStream; -import java.io.PrintWriter; import java.net.ServerSocket; ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/TcpServer.java` at line 7, Remove the unused import of PrintWriter from the TcpServer source: open the TcpServer class and delete the line importing java.io.PrintWriter since no methods or fields in TcpServer reference PrintWriter (this cleans up imports and avoids compiler warnings). ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/http/HttpResponseBuilder.java-84-87 (1)</summary><blockquote> `84-87`: _⚠️ Potential issue_ | _🟡 Minor_ **Handle `null` in `setHeaders` safely.** `setHeaders(null)` currently throws. A null-safe branch makes this API more robust for callers. <details> <summary>💡 Proposed fix</summary> ```diff public void setHeaders(Map<String, String> headers) { this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - this.headers.putAll(headers); + if (headers != null) { + this.headers.putAll(headers); + } } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/http/HttpResponseBuilder.java` around lines 84 - 87, The setHeaders method in HttpResponseBuilder throws when called with null; update setHeaders(Map<String, String> headers) to handle null safely by initializing this.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER) and only calling putAll when headers != null (or else leave it empty), ensuring the headers field is always a case-insensitive TreeMap even when the input is null. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/StaticFileHandler.java-26-33 (1)</summary><blockquote> `26-33`: _⚠️ Potential issue_ | _🟡 Minor_ **Guard null/blank URI before sanitization.** Line 28 dereferences `uri` immediately. A null URI will throw and abort the response path. <details> <summary>💡 Proposed fix</summary> ```diff private void handleGetRequest(String uri) throws IOException { + if (uri == null || uri.isBlank()) { + uri = "/"; + } // Sanitize URI int q = uri.indexOf('?'); ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/StaticFileHandler.java` around lines 26 - 33, handleGetRequest currently dereferences uri immediately; add a null/blank guard at the start of handleGetRequest to avoid NPEs by validating if (uri == null || uri.trim().isEmpty()) and then fail-fast: either throw an IOException with a clear message (e.g. "empty or null URI") or return an appropriate error response before performing any substring/replace operations on uri; update callers if necessary so the response path remains consistent. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (21)</summary><blockquote> <details> <summary>Dockerfile (1)</summary><blockquote> `1-6`: **Consider combining Maven RUN commands to reduce image layers.** The two separate `RUN mvn` commands create unnecessary intermediate layers. Combining them reduces the final build stage size. <details> <summary>♻️ Proposed optimization</summary> ```diff FROM maven:3-eclipse-temurin-25-alpine AS build WORKDIR /build COPY src/ src/ COPY pom.xml pom.xml -RUN mvn compile -RUN mvn dependency:copy-dependencies -DincludeScope=compile +RUN mvn compile dependency:copy-dependencies -DincludeScope=compile ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@Dockerfile` around lines 1 - 6, The Dockerfile has two separate RUN layers for Maven ("RUN mvn compile" and "RUN mvn dependency:copy-dependencies -DincludeScope=compile"); combine these into a single RUN so both commands execute in one layer (e.g., use && to chain "mvn compile" and "mvn dependency:copy-dependencies -DincludeScope=compile") to reduce image layers and final image size while keeping the same build steps. ``` </details> </blockquote></details> <details> <summary>.github/workflows/ci.yml (1)</summary><blockquote> `16-19`: **Note: This step relies on pre-installed Maven.** The `mvn help:evaluate` command runs before `setup-java`, relying on Ubuntu's pre-installed Maven/Java. This works on `ubuntu-latest` but creates an implicit dependency. Consider adding a comment or documenting this assumption. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 16 - 19, The CI step named "Get Java Version" uses the mvn help:evaluate command before setup-java, which implicitly relies on a pre-installed Maven/Java; update the workflow to either run setup-java (or install Maven) before this step or add a clear comment documenting the implicit dependency so future maintainers know mvn help:evaluate requires pre-installed Maven/Java; reference the step name "Get Java Version", the command "mvn help:evaluate", and the "setup-java" step when making this change. ``` </details> </blockquote></details> <details> <summary>www/file-test.html (1)</summary><blockquote> `298-298`: **Prefer DOM/text APIs over `innerHTML` for file path rendering.** At Line 298, `innerHTML` is unnecessary and makes future unsafe interpolation easier to introduce. Use `textContent` and a created `<span>` node instead. <details> <summary>Diff suggestion</summary> ```diff - filePathDisplay.innerHTML = `<span>${path}</span>`; + filePathDisplay.textContent = ''; + const pathSpan = document.createElement('span'); + pathSpan.textContent = path; + filePathDisplay.appendChild(pathSpan); ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@www/file-test.html` at line 298, Replace the unsafe innerHTML assignment to filePathDisplay.innerHTML with DOM/text APIs: create a span via document.createElement('span'), set its textContent to the path variable, clear or remove existing children of filePathDisplay, and append the new span node; this ensures you use filePathDisplay and path but avoid innerHTML to prevent accidental HTML injection and make rendering safe. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/httpparser/HttpParseRequestLineTest.java (1)</summary><blockquote> `24-24`: **Use explicit UTF-8 in test input encoding.** These `getBytes()` calls are platform-default dependent; use `StandardCharsets.UTF_8` for deterministic tests. Also applies to: 41-41, 53-53, 64-64 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/httpparser/HttpParseRequestLineTest.java` at line 24, Replace platform-default byte encoding usages in HttpParseRequestLineTest by calling getBytes(StandardCharsets.UTF_8) on testString to make tests deterministic; update every occurrence like the one inside the test class (e.g., the InputStream construction in HttpParseRequestLineTest where you currently call testString.getBytes()) to use StandardCharsets.UTF_8. Ensure you import java.nio.charset.StandardCharsets if not already present and apply the same change to the other occurrences mentioned (lines analogous to 41, 53, 64). ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/httpparser/HttpParserTest.java (1)</summary><blockquote> `16-22`: **Align header parsing test with parser contract.** At Line 17, this header test includes the request line and passes because non-header lines are skipped. Consider parsing request line first (or using headers-only input) so the test asserts header parsing behavior explicitly. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/httpparser/HttpParserTest.java` around lines 16 - 22, The test TestHttpParserForHeaders currently feeds a full HTTP request (including the request line) to httpParser.parseHttp which lets the parser skip non-header lines and masks header-only behavior; update the test to either (1) feed headers-only input (start with "Host: ..." and end with "\r\n") before calling httpParser.setReader and httpParser.parseHttp so assertions verify header parsing explicitly, or (2) first invoke the parser method that consumes the request line (or call a dedicated parseRequestLine method) on the request-line input and then call parseHttp with the remaining headers-only InputStream; adjust assertions accordingly in HttpParserTest and keep references to TestHttpParserForHeaders, httpParser.setReader, and httpParser.parseHttp to locate the change. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/config/ConfigLoaderTest.java (2)</summary><blockquote> `142-152`: **Clean up test formatting.** Minor formatting improvements: add space after comma on line 145 and remove excess blank lines at end of method. <details> <summary>🧹 Proposed cleanup</summary> ```diff `@Test` `@DisplayName`("missing external file should fallback to classpath") - void fallback_to_classpath_when_external_file_missing(){ - AppConfig appConfig = ConfigLoader.loadOnceWithClasspathFallback(tempDir.resolve("missing.yml"),"application.yml"); + void fallback_to_classpath_when_external_file_missing() { + AppConfig appConfig = ConfigLoader.loadOnceWithClasspathFallback(tempDir.resolve("missing.yml"), "application.yml"); assertThat(appConfig.server().port()).isEqualTo(3030); - - - - } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/config/ConfigLoaderTest.java` around lines 142 - 152, In the test method fallback_to_classpath_when_external_file_missing, fix formatting by adding a space after the comma in the call to ConfigLoader.loadOnceWithClasspathFallback (i.e. tempDir.resolve("missing.yml"), "application.yml") and remove the extra blank lines at the end of the method so the closing brace follows the assertThat assertion directly; keep AppConfig and assertThat usage unchanged. ``` </details> --- `130-130`: **Fix method name formatting.** The method name `invalid_port_should_Throw_Exception ()` has extraneous spaces before the parentheses. <details> <summary>🧹 Proposed fix</summary> ```diff - void invalid_port_should_Throw_Exception () throws Exception { + void invalid_port_should_Throw_Exception() throws Exception { ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/config/ConfigLoaderTest.java` at line 130, The test method declaration invalid_port_should_Throw_Exception () contains extra spaces before the parentheses; locate the method in ConfigLoaderTest (method name invalid_port_should_Throw_Exception) and remove the trailing spaces so the signature reads invalid_port_should_Throw_Exception() (keeping the same name casing) to correct the formatting. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/http/MimeTypeDetectorTest.java (1)</summary><blockquote> `145-145`: **Translate comment to English.** Line 145 contains a Swedish comment: "Parametriserad test för många filtyper på en gång" (Parameterized test for many file types at once). <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/http/MimeTypeDetectorTest.java` at line 145, Replace the Swedish comment "Parametriserad test för många filtyper på en gång" in MimeTypeDetectorTest (around the parameterized test declaration) with its English translation "Parameterized test for many file types at once" so the comment is in English and clearly documents the parameterized test. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/config/ConfigLoader.java (1)</summary><blockquote> `117-119`: **Consider adding synchronization to `resetForTests()`.** While `cached` is volatile, setting it to `null` without synchronization could theoretically race with `loadOnce` calls. For test reliability, consider synchronizing: <details> <summary>🔧 Proposed fix</summary> ```diff public static void resetForTests() { + synchronized (ConfigLoader.class) { cached = null; + } } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/config/ConfigLoader.java` around lines 117 - 119, The resetForTests() method sets the volatile field cached to null without synchronization and can race with loadOnce; update resetForTests() to perform the null assignment inside the same synchronization used by loadOnce (e.g., synchronize on the ConfigLoader class or the specific lock object that loadOnce uses) so both methods use the same monitor when touching cached. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/http/HttpResponseBuilderTest.java (1)</summary><blockquote> `42-42`: **Translate comments to English for consistency.** Several comments in this file are in Swedish (e.g., "UTF-8 content length för olika strängar", "för auto-append behavior", "Parametriserad test för många filtyper på en gång"). Consider translating them to English for international accessibility. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/http/HttpResponseBuilderTest.java` at line 42, Translate all Swedish comments in HttpResponseBuilderTest to English for consistency; locate comment strings like "UTF-8 content length för olika strängar", "för auto-append behavior", and "Parametriserad test för många filtyper på en gång" inside the HttpResponseBuilderTest class and replace them with clear English equivalents (e.g., "UTF-8 content length for various strings", "for auto-append behavior", "Parameterized test for many file types at once") while preserving the original meaning and punctuation. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/config/AppConfig.java (1)</summary><blockquote> `23-24`: **Remove development comments before merging.** Lines 23-24 contain Swedish comments ("← LÄGG TILL", "← UPPDATERA DENNA RAD") that appear to be development notes and should be removed. <details> <summary>🧹 Proposed cleanup</summary> ```diff - IpFilterConfig ipFilterConfig = (ipFilter == null ? IpFilterConfig.defaults() : ipFilter.withDefaultsApplied()); // ← LÄGG TILL - return new AppConfig(serverConfig, loggingConfig, ipFilterConfig); // ← UPPDATERA DENNA RAD + IpFilterConfig ipFilterConfig = (ipFilter == null ? IpFilterConfig.defaults() : ipFilter.withDefaultsApplied()); + return new AppConfig(serverConfig, loggingConfig, ipFilterConfig); ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/config/AppConfig.java` around lines 23 - 24, Remove the inline Swedish development comments on the two modified lines so the code reads cleanly: keep the IpFilterConfig creation using (ipFilter == null ? IpFilterConfig.defaults() : ipFilter.withDefaultsApplied()) and the return new AppConfig(serverConfig, loggingConfig, ipFilterConfig) but delete the trailing comments "← LÄGG TILL" and "← UPPDATERA DENNA RAD"; ensure identifiers IpFilterConfig, ipFilter, withDefaultsApplied, AppConfig, serverConfig, and loggingConfig remain unchanged. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/filter/RequestTimeOutFilterTest.java (1)</summary><blockquote> `49-52`: **Consider reducing slow-path sleep duration to speed up test suite.** A shorter delay still above the timeout threshold validates the same behavior while cutting test runtime. <details> <summary>⏱️ Suggested tweak</summary> ```diff FilterChain slowChain = (request, response) -> { try { - Thread.sleep(600); + Thread.sleep(250); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }; ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/filter/RequestTimeOutFilterTest.java` around lines 49 - 52, In RequestTimeOutFilterTest update the slow-path sleep in the slowChain lambda (the Thread.sleep(...) inside the FilterChain slowChain) to a much smaller value that is still above the configured timeout (e.g., timeout + 10ms) so the test still triggers the timeout behavior but runs faster; locate the slowChain lambda in RequestTimeOutFilterTest and replace the 600ms sleep with a minimal margin above the test's timeout value. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/LocaleFilter.java (1)</summary><blockquote> `67-70`: **Null check for headers is unnecessary.** Based on `HttpRequest.getHeaders()` implementation (see `src/main/java/org/example/httpparser/HttpRequest.java` lines 27-28), it always returns a non-null map (either `Map.copyOf(headers)` or `Collections.emptyMap()`). The null check on line 68 can be simplified. <details> <summary>♻️ Suggested simplification</summary> ```diff Map<String, String> headers = request.getHeaders(); - if (headers == null || headers.isEmpty()) { + if (headers.isEmpty()) { return DEFAULT_LOCALE; } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/LocaleFilter.java` around lines 67 - 70, In LocaleFilter (method using request.getHeaders()), remove the redundant null check because HttpRequest.getHeaders() always returns a non-null Map; replace the conditional that currently checks "headers == null || headers.isEmpty()" with a single "headers.isEmpty()" check (or directly rely on headers.isEmpty() to return DEFAULT_LOCALE) to simplify the logic while keeping the existing DEFAULT_LOCALE fallback. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/filter/CompressionFilterTest.java (1)</summary><blockquote> `113-131`: **Reflection-based body extraction is fragile but acceptable.** Using reflection to access private fields (`bytebody`, `body`) is brittle and will break if field names change. Consider using `HttpResponseBuilder.getBodyBytes()` or `getByteBody()` public methods instead. <details> <summary>♻️ Use public API instead of reflection</summary> ```diff private byte[] getBodyFromResponse(HttpResponseBuilder response) { - try { - var field = response.getClass().getDeclaredField("bytebody"); - field.setAccessible(true); - byte[] bytebody = (byte[]) field.get(response); - - if (bytebody != null) { - return bytebody; - } - - var bodyField = response.getClass().getDeclaredField("body"); - bodyField.setAccessible(true); - String body = (String) bodyField.get(response); - return body.getBytes(StandardCharsets.UTF_8); - - } catch (Exception e) { - throw new RuntimeException("Failed to get body", e); - } + byte[] byteBody = response.getByteBody(); + if (byteBody != null) { + return byteBody; + } + return response.getBody().getBytes(StandardCharsets.UTF_8); } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/filter/CompressionFilterTest.java` around lines 113 - 131, The test's getBodyFromResponse uses fragile reflection to read private fields "bytebody" and "body"; replace this with public API calls on HttpResponseBuilder (e.g., getBodyBytes(), getByteBody(), or getBody()) instead: call the available public method that returns the byte[] first, return it if non-null, otherwise call the String-returning getter and convert to UTF-8 bytes, and keep the same exception behavior; update the method to reference the HttpResponseBuilder getters instead of response.getClass().getDeclaredField(...) ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/Filter.java (1)</summary><blockquote> `7-14`: **Consider adding default implementations for lifecycle methods.** Most filter implementations in this PR have empty `init()` and `destroy()` methods. Adding default no-op implementations would reduce boilerplate. <details> <summary>♻️ Suggested refactor</summary> ```diff public interface Filter { - void init(); + default void init() {} void doFilter(HttpRequest request, HttpResponseBuilder response, FilterChain chain); - void destroy(); + default void destroy() {} } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/Filter.java` around lines 7 - 14, Add no-op default implementations for the lifecycle methods in the Filter interface: change init() and destroy() to default methods that do nothing while keeping doFilter(HttpRequest, HttpResponseBuilder, FilterChain) abstract; this reduces boilerplate in existing Filter implementations (classes implementing Filter can keep or remove their empty overrides). Ensure you update the interface method signatures for init and destroy to use the default keyword (Java 8+), leaving doFilter and the types HttpRequest, HttpResponseBuilder, FilterChain unchanged. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/FilterChainImpl.java (1)</summary><blockquote> `21-25`: **Consider defensive copy of the filters list.** The constructor stores the `filters` list by reference. If the caller modifies the list after construction, it could cause unexpected behavior. A defensive copy would be safer. <details> <summary>♻️ Suggested defensive copy</summary> ```diff public FilterChainImpl(List<Filter> filters, BiConsumer<HttpRequest, HttpResponseBuilder> terminalHandler) { - this.filters = filters; + this.filters = List.copyOf(filters); this.terminalHandler = terminalHandler; } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/FilterChainImpl.java` around lines 21 - 25, The constructor FilterChainImpl(List<Filter> filters, BiConsumer<HttpRequest, HttpResponseBuilder> terminalHandler) stores the incoming filters list by reference which allows external mutation; make a defensive copy when assigning to the filters field (e.g., create a new ArrayList from the provided list or Collections.unmodifiableList copy) so subsequent external changes don't affect FilterChainImpl, and preserve/null-check behavior as needed for the terminalHandler and filters parameters. ``` </details> </blockquote></details> <details> <summary>src/test/java/org/example/filter/LoggingFilterTest.java (1)</summary><blockquote> `28-28`: **Consider creating a fresh filter instance per test.** The `filter` field is instantiated once at class level. While `LoggingFilter` appears stateless, it's a best practice in unit tests to create fresh instances in `@BeforeEach` to prevent accidental state sharing between tests. <details> <summary>♻️ Suggested refactor</summary> ```diff - LoggingFilter filter = new LoggingFilter(); + LoggingFilter filter; Logger logger; `@BeforeEach` void setup(){ + filter = new LoggingFilter(); logger = Logger.getLogger(LoggingFilter.class.getName()); ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/test/java/org/example/filter/LoggingFilterTest.java` at line 28, The test currently reuses a single LoggingFilter instance declared at class level; change the setup to create a fresh instance before each test by removing the class-level instantiation and initializing a new LoggingFilter in a `@BeforeEach` method (referencing the LoggingFilter class and the LoggingFilterTest test class) so each test gets its own filter instance to avoid accidental shared state. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/TcpServer.java (1)</summary><blockquote> `37-43`: **Exception handling could be simplified.** The `handleClient` method wraps any exception from `try(client)` in a `RuntimeException`, but this complicates debugging. Since `processRequest` already handles errors internally, the re-thrown exception here would typically only occur on socket close failure. <details> <summary>♻️ Suggested simplification</summary> ```diff protected void handleClient(Socket client) { - try(client){ + try (client) { processRequest(client); } catch (Exception e) { - throw new RuntimeException("Failed to close socket", e); + System.err.println("Error handling client: " + e.getMessage()); } } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/TcpServer.java` around lines 37 - 43, The catch in handleClient is unnecessary and hides socket-close failures by wrapping them in a RuntimeException; remove the catch block so the try-with-resources around the Socket client simply calls processRequest(client) and lets any close exceptions surface or be handled elsewhere, or alternatively replace the catch with a simple log (e.g., logger.warn("Socket close failed", e)) instead of throwing a RuntimeException; update the handleClient method (referencing method name handleClient, parameter Socket client, and call to processRequest) accordingly. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/server/ConfigurableFilterPipeline.java (1)</summary><blockquote> `30-55`: **Consider precomputing ordered registrations once in constructor.** Global/route splitting and sorting are repeated per request even though `registrations` is immutable. Precomputing stable ordered structures can reduce request-path overhead. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/server/ConfigurableFilterPipeline.java` around lines 30 - 55, Move the global/route split and sort out of the per-request path and into the class constructor so we do not repeat work on every request: in ConfigurableFilterPipeline add final fields (e.g., precomputedGlobalFilters: List<Filter> and precomputedRouteRegistrations: List<FilterRegistration>), populate them once in the constructor by iterating over registrations, separating reg.isGlobal() into precomputedGlobalFilters (store reg.filter()) and non-global into precomputedRouteRegistrations (store the registrations), sort both using Comparator.comparingInt(FilterRegistration::order) (or sort filters by the same order), and then in the request handling code replace the per-request global/route building with using precomputedGlobalFilters and iterating precomputedRouteRegistrations and calling matchesAny(reg.routePatterns(), request.getPath()) to append reg.filter() for matching route registrations. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/CompressionFilter.java (1)</summary><blockquote> `99-101`: **Prefer structured logger over `System.err` for compression failures.** Using a logger here keeps diagnostics consistent with the rest of server-side error handling and operational tooling. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/CompressionFilter.java` around lines 99 - 101, Replace the System.err.println in the CompressionFilter catch block with the class logger: ensure CompressionFilter has a logger (e.g., private static final Logger logger = LoggerFactory.getLogger(CompressionFilter.class)) and change the catch(IOException e) body to logger.error("CompressionFilter: gzip compression failed", e) so the exception and stack trace are captured by the structured logging system; if your project uses a different logging facade, use that logger type and the logger.error(message, throwable) signature accordingly. ``` </details> </blockquote></details> <details> <summary>src/main/java/org/example/filter/LocaleFilterWithCookie.java (1)</summary><blockquote> `77-81`: **Optional: remove dead null checks for request headers.** With `src/main/java/org/example/httpparser/HttpRequest.java` (constructor + `getHeaders()`), headers are always non-null (`Collections.emptyMap()` fallback), so these branches are unreachable. <details> <summary>💡 Proposed cleanup</summary> ```diff private String extractLocaleFromCookie(HttpRequest request) { Map<String, String> headers = request.getHeaders(); - if (headers == null) { - return null; - } @@ private String extractLocaleFromHeader(HttpRequest request) { Map<String, String> headers = request.getHeaders(); - if (headers == null) { - return null; - } ``` </details> Also applies to: 115-118 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/LocaleFilterWithCookie.java` around lines 77 - 81, The null-check branches in LocaleFilterWithCookie.extractLocaleFromCookie are dead because HttpRequest's constructor and getHeaders() always return a non-null Map (Collections.emptyMap fallback); remove the headers==null guard and any early returns that assume headers can be null, and simplify the method to operate directly on request.getHeaders(); update any other occurrences in LocaleFilterWithCookie (lines referenced around 115-118) that perform the same redundant null checks. Ensure you keep references to HttpRequest.getHeaders() and the extractLocaleFromCookie method name when making the change so reviewers can find the edit. ``` </details> </blockquote></details> </blockquote></details> --- <details> <summary>ℹ️ Review info</summary> **Configuration used**: Organization UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 5f18f918876b7d42570e93cc228d7d811caa0591 and 088e9261f008fbb7bfb59af52b012c2d24286057. </details> <details> <summary>⛔ Files ignored due to path filters (12)</summary> * `src/main/resources/test.jpg` is excluded by `!**/*.jpg` * `www/test-files/test.gif` is excluded by `!**/*.gif` * `www/test-files/test.jpeg` is excluded by `!**/*.jpeg` * `www/test-files/test.jpg` is excluded by `!**/*.jpg` * `www/test-files/test.mp3` is excluded by `!**/*.mp3` * `www/test-files/test.mp4` is excluded by `!**/*.mp4` * `www/test-files/test.pdf` is excluded by `!**/*.pdf` * `www/test-files/test.png` is excluded by `!**/*.png` * `www/test-files/test.svg` is excluded by `!**/*.svg` * `www/test-files/test.wav` is excluded by `!**/*.wav` * `www/test-files/test.webm` is excluded by `!**/*.webm` * `www/test.jpg` is excluded by `!**/*.jpg` </details> <details> <summary>📒 Files selected for processing (53)</summary> * `.github/workflows/ci.yml` * `.github/workflows/release.yml` * `Dockerfile` * `PortConfigurationGuide.md` * `README.md` * `pom.xml` * `src/main/java/org/example/App.java` * `src/main/java/org/example/ConnectionFactory.java` * `src/main/java/org/example/ConnectionHandler.java` * `src/main/java/org/example/StaticFileHandler.java` * `src/main/java/org/example/TcpServer.java` * `src/main/java/org/example/config/AppConfig.java` * `src/main/java/org/example/config/ConfigLoader.java` * `src/main/java/org/example/filter/CompressionFilter.java` * `src/main/java/org/example/filter/Filter.java` * `src/main/java/org/example/filter/FilterChain.java` * `src/main/java/org/example/filter/FilterChainImpl.java` * `src/main/java/org/example/filter/IpFilter.java` * `src/main/java/org/example/filter/LocaleFilter.java` * `src/main/java/org/example/filter/LocaleFilterWithCookie.java` * `src/main/java/org/example/filter/LoggingFilter.java` * `src/main/java/org/example/filter/RequestTimeOutFilter.java` * `src/main/java/org/example/http/HttpResponseBuilder.java` * `src/main/java/org/example/http/MimeTypeDetector.java` * `src/main/java/org/example/httpparser/HttpParseRequestLine.java` * `src/main/java/org/example/httpparser/HttpParser.java` * `src/main/java/org/example/httpparser/HttpRequest.java` * `src/main/java/org/example/server/ConfigurableFilterPipeline.java` * `src/main/java/org/example/server/FilterRegistration.java` * `src/main/java/org/example/server/RoutePattern.java` * `src/main/resources/application.yml` * `src/test/java/org/example/AppPortResolutionTest.java` * `src/test/java/org/example/ConnectionHandlerTest.java` * `src/test/java/org/example/StaticFileHandlerTest.java` * `src/test/java/org/example/TcpServerTest.java` * `src/test/java/org/example/config/ConfigLoaderTest.java` * `src/test/java/org/example/filter/CompressionFilterTest.java` * `src/test/java/org/example/filter/IpFilterTest.java` * `src/test/java/org/example/filter/LocaleFilterTest.java` * `src/test/java/org/example/filter/LocaleFilterWithCookieTest.java` * `src/test/java/org/example/filter/LoggingFilterTest.java` * `src/test/java/org/example/filter/RequestTimeOutFilterTest.java` * `src/test/java/org/example/http/HttpResponseBuilderTest.java` * `src/test/java/org/example/http/MimeTypeDetectorTest.java` * `src/test/java/org/example/httpparser/HttpParseRequestLineTest.java` * `src/test/java/org/example/httpparser/HttpParserTest.java` * `src/test/java/org/example/server/ConfigurableFilterPipelineTest.java` * `src/test/resources/application.yml` * `www/file-test.html` * `www/index.html` * `www/pageNotFound.html` * `www/test-files/test.txt` * `www/test-files/test.webp` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
|
Det verkar som att jag begick ett misstag i att jag gjorde en merge på förändringarna i main in i 96-create-page-for-testing-filytypes branch innan jag pushade. De enda filerna pull-requesten syftar på är www/file-test.html samt www/test-files/ med alla filer där inuti. Borde pull requesten göras om eller ändras? |
|
Pull requested verkar vara gjord i ett separat repository. Nu stängd. |
Summary by CodeRabbit
Release Notes
New Features
Documentation
Deployment