Skip to content

Commit c1e3a16

Browse files
Introduce ADR structure and first ADR - Add ADR README explaining the ADR process for the team
- Add TEMPLATE for writing future ADRs - Add ADR-001 documenting static file serving architecture Closes #16
1 parent 019e4c4 commit c1e3a16

File tree

3 files changed

+422
-0
lines changed

3 files changed

+422
-0
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
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

docs/adr/README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Architectural Decision Records (ADR)
2+
3+
This directory contains all Architectural Decision Records for the JavaHttpServer project.
4+
5+
## What is an ADR?
6+
7+
An ADR is a document that captures an important architectural decision made along with its context and consequences. This helps the team:
8+
9+
- Understand why certain design choices were made
10+
- Onboard new team members faster
11+
- Avoid repeating past discussions
12+
- Track the evolution of the system
13+
14+
## ADR Format
15+
16+
We use the format described in [Joel Parker Henderson's ADR repository](https://github.com/joelparkerhenderson/architecture-decision-record).
17+
18+
Each ADR includes:
19+
- **Context:** Why the decision is needed
20+
- **Decision:** What choice was made
21+
- **Consequences:** Trade-offs, pros, and cons
22+
23+
## Creating a New ADR
24+
25+
1. Copy `TEMPLATE.md` to a new file named `ADR-XXX-brief-title.md` (e.g., `ADR-001-use-maven-for-build.md`)
26+
2. Fill in all sections of the template
27+
3. Discuss with the team before marking as "Accepted"
28+
4. Commit the ADR to the repository
29+
30+
## Naming Convention
31+
32+
- Files are named: `ADR-XXX-descriptive-kebab-case-title.md`
33+
- XXX is a zero-padded sequential number (001, 002, etc.)
34+
- Titles should be brief but descriptive
35+
36+
## ADR Status
37+
38+
An ADR can have one of the following statuses:
39+
40+
- **Proposed:** Under discussion
41+
- **Accepted:** Decision has been made and is active
42+
- **Deprecated:** No longer relevant but kept for historical context
43+
- **Superseded:** Replaced by another ADR (reference the new ADR)
44+
45+
## Index of ADRs
46+
47+
| ADR | Title | Status | Date |
48+
|-----|-------|--------|------|
49+
| [001](ADR-001-static-file-serving-architecture.md) | Static File Serving Architecture | Accepted | 2026-02-11 |
50+
51+
---
52+
53+
## Best Practices
54+
55+
### When to Create an ADR
56+
57+
Create an ADR when:
58+
- Making a significant architectural choice
59+
- Choosing between multiple viable technical solutions
60+
- Making a decision that will be hard to reverse
61+
- Implementing a pattern that the whole team should follow
62+
- Resolving a technical dispute
63+
64+
### When NOT to Create an ADR
65+
66+
Don't create ADRs for:
67+
- Minor code style preferences (use linting/formatting tools)
68+
- Trivial implementation details
69+
- Temporary workarounds
70+
- Decisions that are easily reversible
71+
72+
### Writing Good ADRs
73+
74+
**DO:**
75+
- Be specific and concrete
76+
- Include timestamps for time-sensitive information
77+
- Explain the "why" clearly
78+
- Consider alternatives thoroughly
79+
- Keep it focused on one decision
80+
81+
**DON'T:**
82+
- Change existing ADRs (amend or create new ones instead)
83+
- Make them too long (aim for 1-2 pages)
84+
- Skip the "Consequences" section
85+
- Leave out the context
86+
87+
---
88+
89+
## Resources
90+
91+
- [ADR GitHub Organization](https://adr.github.io/)
92+
- [Joel Parker Henderson's ADR repo](https://github.com/joelparkerhenderson/architecture-decision-record)
93+
- [Documenting Architecture Decisions by Michael Nygard](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)

0 commit comments

Comments
 (0)