Skip to content

Commit 0f8ff11

Browse files
authored
Merge pull request #17 from probitas-test/echo-http-response-header
Add /response-header endpoint for testing HTTP client header handling
2 parents 61c6b43 + 01ad1e8 commit 0f8ff11

4 files changed

Lines changed: 175 additions & 0 deletions

File tree

echo-http/docs/api.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,46 @@ curl http://localhost:80/headers \
148148
}
149149
```
150150

151+
### GET /response-header
152+
153+
Set response headers based on query parameters. Each query parameter key-value
154+
pair is set as a response header. Useful for testing HTTP client header processing.
155+
156+
**Request:**
157+
158+
```bash
159+
curl -i "http://localhost:80/response-header?X-Custom-Header=custom-value&Cache-Control=no-cache"
160+
```
161+
162+
**Response:**
163+
164+
```
165+
HTTP/1.1 200 OK
166+
Cache-Control: no-cache
167+
Content-Type: application/json
168+
X-Custom-Header: custom-value
169+
170+
{
171+
"headers": {
172+
"X-Custom-Header": "custom-value",
173+
"Cache-Control": "no-cache"
174+
}
175+
}
176+
```
177+
178+
**Examples:**
179+
180+
```bash
181+
# Set custom response headers
182+
curl -i "http://localhost:80/response-header?X-Request-Id=12345&X-Correlation-Id=abc-xyz"
183+
184+
# Test cache control headers
185+
curl -i "http://localhost:80/response-header?Cache-Control=max-age=3600&Expires=Wed,%2021%20Oct%202025%2007:28:00%20GMT"
186+
187+
# Set content language
188+
curl -i "http://localhost:80/response-header?Content-Language=en-US"
189+
```
190+
151191
### GET /status/{code}
152192

153193
Return the specified HTTP status code.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package handlers
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
)
7+
8+
type ResponseHeaderResponse struct {
9+
Headers map[string]string `json:"headers"`
10+
}
11+
12+
// ResponseHeaderHandler sets response headers based on query parameters.
13+
// Each query parameter key-value pair is set as a response header.
14+
// Example: GET /response-header?X-Custom-Header=value&Content-Language=en
15+
func ResponseHeaderHandler(w http.ResponseWriter, r *http.Request) {
16+
response := ResponseHeaderResponse{
17+
Headers: make(map[string]string),
18+
}
19+
20+
// Set each query parameter as a response header
21+
for key, values := range r.URL.Query() {
22+
if len(values) > 0 {
23+
w.Header().Set(key, values[0])
24+
response.Headers[key] = values[0]
25+
}
26+
}
27+
28+
w.Header().Set("Content-Type", "application/json")
29+
_ = json.NewEncoder(w).Encode(response)
30+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package handlers
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
)
9+
10+
func TestResponseHeaderHandler(t *testing.T) {
11+
t.Run("sets response headers from query parameters", func(t *testing.T) {
12+
req := httptest.NewRequest(http.MethodGet, "/response-header?X-Custom-Header=custom-value&X-Request-Id=12345", nil)
13+
rec := httptest.NewRecorder()
14+
15+
ResponseHeaderHandler(rec, req)
16+
17+
if rec.Code != http.StatusOK {
18+
t.Errorf("expected status 200, got %d", rec.Code)
19+
}
20+
21+
contentType := rec.Header().Get("Content-Type")
22+
if contentType != "application/json" {
23+
t.Errorf("expected Content-Type application/json, got %s", contentType)
24+
}
25+
26+
// Check response headers
27+
if rec.Header().Get("X-Custom-Header") != "custom-value" {
28+
t.Errorf("expected X-Custom-Header=custom-value, got %s", rec.Header().Get("X-Custom-Header"))
29+
}
30+
31+
if rec.Header().Get("X-Request-Id") != "12345" {
32+
t.Errorf("expected X-Request-Id=12345, got %s", rec.Header().Get("X-Request-Id"))
33+
}
34+
35+
// Check response body
36+
var resp ResponseHeaderResponse
37+
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
38+
t.Fatalf("failed to decode response: %v", err)
39+
}
40+
41+
if resp.Headers["X-Custom-Header"] != "custom-value" {
42+
t.Errorf("expected body X-Custom-Header=custom-value, got %s", resp.Headers["X-Custom-Header"])
43+
}
44+
45+
if resp.Headers["X-Request-Id"] != "12345" {
46+
t.Errorf("expected body X-Request-Id=12345, got %s", resp.Headers["X-Request-Id"])
47+
}
48+
})
49+
50+
t.Run("handles standard HTTP headers", func(t *testing.T) {
51+
req := httptest.NewRequest(http.MethodGet, "/response-header?Cache-Control=no-cache&Content-Language=en-US", nil)
52+
rec := httptest.NewRecorder()
53+
54+
ResponseHeaderHandler(rec, req)
55+
56+
if rec.Code != http.StatusOK {
57+
t.Errorf("expected status 200, got %d", rec.Code)
58+
}
59+
60+
if rec.Header().Get("Cache-Control") != "no-cache" {
61+
t.Errorf("expected Cache-Control=no-cache, got %s", rec.Header().Get("Cache-Control"))
62+
}
63+
64+
if rec.Header().Get("Content-Language") != "en-US" {
65+
t.Errorf("expected Content-Language=en-US, got %s", rec.Header().Get("Content-Language"))
66+
}
67+
})
68+
69+
t.Run("handles empty query parameters", func(t *testing.T) {
70+
req := httptest.NewRequest(http.MethodGet, "/response-header", nil)
71+
rec := httptest.NewRecorder()
72+
73+
ResponseHeaderHandler(rec, req)
74+
75+
if rec.Code != http.StatusOK {
76+
t.Errorf("expected status 200, got %d", rec.Code)
77+
}
78+
79+
var resp ResponseHeaderResponse
80+
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
81+
t.Fatalf("failed to decode response: %v", err)
82+
}
83+
84+
if len(resp.Headers) != 0 {
85+
t.Errorf("expected empty headers map, got %d headers", len(resp.Headers))
86+
}
87+
})
88+
89+
t.Run("uses first value when multiple values exist", func(t *testing.T) {
90+
req := httptest.NewRequest(http.MethodGet, "/response-header?X-Multi=first&X-Multi=second", nil)
91+
rec := httptest.NewRecorder()
92+
93+
ResponseHeaderHandler(rec, req)
94+
95+
if rec.Code != http.StatusOK {
96+
t.Errorf("expected status 200, got %d", rec.Code)
97+
}
98+
99+
headerValue := rec.Header().Get("X-Multi")
100+
if headerValue != "first" {
101+
t.Errorf("expected X-Multi=first, got %s", headerValue)
102+
}
103+
})
104+
}

echo-http/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func main() {
3030

3131
// Utility endpoints
3232
r.Get("/headers", handlers.HeadersHandler)
33+
r.Get("/response-header", handlers.ResponseHeaderHandler)
3334
r.Get("/ip", handlers.IPHandler)
3435
r.Get("/user-agent", handlers.UserAgentHandler)
3536

0 commit comments

Comments
 (0)