|
| 1 | +# ADR-001: Static File Serving Architecture |
| 2 | + |
| 3 | +**Date:** 2026-02-11 |
| 4 | +**Status:** Proposed |
| 5 | +**Deciders:** Team juv25d |
| 6 | +**Technical Story:** Issue #18 - GET handling for static files |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## Context |
| 11 | + |
| 12 | +Our HTTP server needs the ability to serve static files (HTML, CSS, JavaScript, images, etc.) to support building complete web applications. Currently, our server can parse HTTP requests and send responses, but has no mechanism to serve files from the filesystem. |
| 13 | + |
| 14 | +### Problem Statement |
| 15 | + |
| 16 | +We need to implement a static file serving mechanism that: |
| 17 | +- Serves files from a designated directory structure |
| 18 | +- Maps URLs to filesystem paths safely |
| 19 | +- Handles different file types with appropriate Content-Type headers |
| 20 | +- Provides reasonable error handling (404, 500, etc.) |
| 21 | +- Follows familiar conventions for ease of use |
| 22 | + |
| 23 | +### Assumptions |
| 24 | + |
| 25 | +- Static files will be bundled with the application at build time |
| 26 | +- Files will be served from the classpath/resources directory |
| 27 | +- We're building a development/learning server (not production-grade like Nginx) |
| 28 | +- Performance requirements are moderate (not handling thousands of requests/second) |
| 29 | + |
| 30 | +### Constraints |
| 31 | + |
| 32 | +- Must work with our existing `HttpParser`, `HttpResponse`, and `HttpResponseWriter` classes |
| 33 | +- Should integrate cleanly with the `SocketServer` connection handling |
| 34 | +- Must run inside a Docker container with resources directory available |
| 35 | +- Team is learning HTTP and web server concepts - architecture should be educational |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## Decision |
| 40 | + |
| 41 | +We will implement a **SpringBoot-style static file serving architecture** with the following design: |
| 42 | + |
| 43 | +### Chosen Solution |
| 44 | + |
| 45 | +**1. Directory Structure:** |
| 46 | +``` |
| 47 | +src/main/resources/ |
| 48 | +└── static/ |
| 49 | + ├── index.html |
| 50 | + ├── css/ |
| 51 | + │ └── styles.css |
| 52 | + ├── js/ |
| 53 | + │ └── app.js |
| 54 | + └── images/ |
| 55 | + └── logo.png |
| 56 | +``` |
| 57 | + |
| 58 | +**2. URL Mapping:** |
| 59 | +- Files in `/resources/static/` are served at the root path |
| 60 | +- Example: `/resources/static/css/styles.css` → `GET /css/styles.css` |
| 61 | +- Root path `/` automatically serves `index.html` if it exists |
| 62 | + |
| 63 | +**3. Core Components:** |
| 64 | + |
| 65 | +``` |
| 66 | +StaticFileHandler |
| 67 | +├── Validates request path (security) |
| 68 | +├── Maps URL to resource path |
| 69 | +├── Reads file from classpath |
| 70 | +├── Determines MIME type |
| 71 | +└── Creates HttpResponse with proper headers |
| 72 | +
|
| 73 | +MimeTypeResolver |
| 74 | +└── Maps file extensions to Content-Type headers |
| 75 | +
|
| 76 | +Security validator |
| 77 | +└── Prevents directory traversal attacks |
| 78 | +``` |
| 79 | + |
| 80 | +**4. Security Measures:** |
| 81 | +- Path normalization to prevent `../` attacks |
| 82 | +- Whitelist only files within `/static/` directory |
| 83 | +- Reject paths containing `..`, absolute paths, or suspicious patterns |
| 84 | +- Return 403 Forbidden for security violations |
| 85 | + |
| 86 | +**5. Error Handling:** |
| 87 | +- 404 Not Found: File doesn't exist |
| 88 | +- 403 Forbidden: Security violation detected |
| 89 | +- 500 Internal Server Error: I/O errors |
| 90 | + |
| 91 | +**6. MIME Type Handling:** |
| 92 | +- Simple extension-based mapping (.html → text/html, .css → text/css, etc.) |
| 93 | +- Default to `application/octet-stream` for unknown types |
| 94 | +- Support common web file types (HTML, CSS, JS, PNG, JPG, SVG, etc.) |
| 95 | + |
| 96 | +### Why This Solution? |
| 97 | + |
| 98 | +1. **Familiar to developers:** SpringBoot convention is widely known and documented |
| 99 | +2. **Simple mental model:** Root path maps to `/static/` - easy to understand |
| 100 | +3. **Classpath-based:** Works well with JAR packaging and Docker containers |
| 101 | +4. **Educational:** Clear separation of concerns teaches good architecture |
| 102 | +5. **Extensible:** Easy to add features later (caching, compression, etc.) |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +## Consequences |
| 107 | + |
| 108 | +### Positive Consequences |
| 109 | + |
| 110 | +- **Developer Experience:** Developers familiar with SpringBoot will immediately understand the structure |
| 111 | +- **Security by Design:** Explicit security validation prevents common vulnerabilities |
| 112 | +- **Clean URLs:** No `/static/` prefix in URLs keeps them clean |
| 113 | +- **Easy Testing:** Classpath resources are easy to test with JUnit |
| 114 | +- **Docker-Friendly:** Resources directory is included in the container image |
| 115 | +- **Clear Responsibility:** `StaticFileHandler` has a single, well-defined purpose |
| 116 | + |
| 117 | +### Negative Consequences / Trade-offs |
| 118 | + |
| 119 | +- **No Dynamic Content:** This approach only handles static files (but that's the requirement) |
| 120 | +- **No Caching:** Every request reads from disk (acceptable for learning project) |
| 121 | +- **Limited Performance:** Not optimized for high-traffic scenarios |
| 122 | +- **Memory Usage:** Entire files loaded into memory before sending |
| 123 | +- **No Range Requests:** Cannot handle partial content requests (HTTP 206) |
| 124 | + |
| 125 | +### Risks |
| 126 | + |
| 127 | +- **Large Files:** Loading very large files into memory could cause issues |
| 128 | + - *Mitigation:* Document file size limitations, implement streaming later if needed |
| 129 | + |
| 130 | +- **MIME Type Accuracy:** Simple extension mapping might not always be correct |
| 131 | + - *Mitigation:* Cover most common web file types, extend mapping as needed |
| 132 | + |
| 133 | +- **Classpath Resources:** Files must be in classpath at runtime |
| 134 | + - *Mitigation:* Clear documentation about where to place files |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## Alternatives Considered |
| 139 | + |
| 140 | +### Alternative 1: Filesystem-based serving (outside classpath) |
| 141 | + |
| 142 | +**Description:** Serve files from a configurable filesystem directory outside the application. |
| 143 | + |
| 144 | +**Pros:** |
| 145 | +- Files can be updated without rebuilding |
| 146 | +- More flexible for deployment |
| 147 | +- Easier to handle very large files |
| 148 | + |
| 149 | +**Cons:** |
| 150 | +- More complex configuration |
| 151 | +- Path handling is platform-dependent |
| 152 | +- Docker volume mounting adds complexity |
| 153 | +- Harder to test (need actual filesystem) |
| 154 | + |
| 155 | +**Why not chosen:** Adds unnecessary complexity for a learning project. Classpath resources are simpler and work well in Docker. |
| 156 | + |
| 157 | +### Alternative 2: Embedded file map (all files in memory) |
| 158 | + |
| 159 | +**Description:** Load all static files into a HashMap at startup. |
| 160 | + |
| 161 | +**Pros:** |
| 162 | +- Fastest possible serving (no I/O) |
| 163 | +- Very simple lookup logic |
| 164 | +- Predictable memory usage |
| 165 | + |
| 166 | +**Cons:** |
| 167 | +- Cannot add files without restart |
| 168 | +- High memory usage for many/large files |
| 169 | +- Startup time increases |
| 170 | +- Not representative of real web servers |
| 171 | + |
| 172 | +**Why not chosen:** Not scalable and doesn't teach realistic server behavior. Reading from resources is fast enough. |
| 173 | + |
| 174 | +### Alternative 3: Show /static/ in URLs |
| 175 | + |
| 176 | +**Description:** Map `/static/file.html` → `/resources/static/file.html` |
| 177 | + |
| 178 | +**Pros:** |
| 179 | +- More explicit about what's being served |
| 180 | +- Easier to implement (direct path mapping) |
| 181 | +- Clear separation from dynamic routes |
| 182 | + |
| 183 | +**Cons:** |
| 184 | +- Less clean URLs |
| 185 | +- Not how SpringBoot or most frameworks work |
| 186 | +- Exposing internal structure in URLs |
| 187 | + |
| 188 | +**Why not chosen:** Doesn't follow common web conventions. Clean URLs are expected behavior. |
| 189 | + |
| 190 | +--- |
| 191 | + |
| 192 | +## Implementation Notes |
| 193 | + |
| 194 | +### Phase 1: Core Implementation |
| 195 | +1. Create `StaticFileHandler` class |
| 196 | +2. Implement path validation and security checks |
| 197 | +3. Create `MimeTypeResolver` utility |
| 198 | +4. Integrate with existing `SocketServer` / connection handling |
| 199 | +5. Add unit tests for all components |
| 200 | + |
| 201 | +### Phase 2: Integration |
| 202 | +6. Create example static files in `/resources/static/` |
| 203 | +7. Update `SocketServer` to use `StaticFileHandler` for GET requests |
| 204 | +8. Test with browser |
| 205 | +9. Document usage in README |
| 206 | + |
| 207 | +### Phase 3: Polish |
| 208 | +10. Add logging for security violations |
| 209 | +11. Create custom 404 error page |
| 210 | +12. Add metrics/logging for file serving |
| 211 | + |
| 212 | +### Example Usage (Future): |
| 213 | + |
| 214 | +```java |
| 215 | +// In connection handler: |
| 216 | +if (request.method().equals("GET")) { |
| 217 | + HttpResponse response = StaticFileHandler.handleRequest(request); |
| 218 | + HttpResponseWriter.write(outputStream, response); |
| 219 | +} |
| 220 | +``` |
| 221 | + |
| 222 | +### File Structure After Implementation: |
| 223 | + |
| 224 | +``` |
| 225 | +src/main/resources/static/ |
| 226 | +├── index.html (served at GET /) |
| 227 | +├── about.html (served at GET /about.html) |
| 228 | +├── css/ |
| 229 | +│ └── styles.css (served at GET /css/styles.css) |
| 230 | +└── js/ |
| 231 | + └── app.js (served at GET /js/app.js) |
| 232 | +``` |
| 233 | + |
| 234 | +--- |
| 235 | + |
| 236 | +## References |
| 237 | + |
| 238 | +- [Issue #18: GET handling for static files](https://github.com/your-repo/issues/18) |
| 239 | +- [SpringBoot Static Content Documentation](https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet.spring-mvc.static-content) |
| 240 | +- [OWASP Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal) |
| 241 | +- [MDN HTTP Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) |
| 242 | +- [Common MIME Types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) |
| 243 | + |
| 244 | +--- |
| 245 | + |
| 246 | +## Related ADRs |
| 247 | + |
| 248 | +- ADR-002: (Future) Caching Strategy for Static Files |
| 249 | +- ADR-003: (Future) Routing Architecture for Dynamic Handlers |
0 commit comments