refactor(line): hoist body size const, add boundary tests
- Move maxWebhookBodySize to package-level const - Add TestWebhookAcceptsMaxBodySize (exact limit → 403, not 413) - Add TestWebhookRejectsOversizedBodyBeforeSignatureCheck - Use const in test instead of magic number Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
58595330f4
commit
73a656b919
2 changed files with 35 additions and 5 deletions
|
|
@ -32,6 +32,10 @@ const (
|
||||||
lineBotInfoEndpoint = lineAPIBase + "/info"
|
lineBotInfoEndpoint = lineAPIBase + "/info"
|
||||||
lineLoadingEndpoint = lineAPIBase + "/chat/loading/start"
|
lineLoadingEndpoint = lineAPIBase + "/chat/loading/start"
|
||||||
lineReplyTokenMaxAge = 25 * time.Second
|
lineReplyTokenMaxAge = 25 * time.Second
|
||||||
|
|
||||||
|
// Limit request body to prevent memory exhaustion (DoS).
|
||||||
|
// LINE webhook payloads are typically a few KB; 1 MiB is generous.
|
||||||
|
maxWebhookBodySize = 1 << 20 // 1 MiB
|
||||||
)
|
)
|
||||||
|
|
||||||
type replyTokenEntry struct {
|
type replyTokenEntry struct {
|
||||||
|
|
@ -166,9 +170,6 @@ func (c *LINEChannel) webhookHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit request body to prevent memory exhaustion (DoS).
|
|
||||||
// LINE webhook payloads are typically a few KB; 1 MB is generous.
|
|
||||||
const maxWebhookBodySize = 1 << 20 // 1 MB
|
|
||||||
body, err := io.ReadAll(io.LimitReader(r.Body, maxWebhookBodySize+1))
|
body, err := io.ReadAll(io.LimitReader(r.Body, maxWebhookBodySize+1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.ErrorCF("line", "Failed to read request body", map[string]any{
|
logger.ErrorCF("line", "Failed to read request body", map[string]any{
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,7 @@ import (
|
||||||
func TestWebhookRejectsOversizedBody(t *testing.T) {
|
func TestWebhookRejectsOversizedBody(t *testing.T) {
|
||||||
ch := &LINEChannel{}
|
ch := &LINEChannel{}
|
||||||
|
|
||||||
// Create a body larger than maxWebhookBodySize (1 MB)
|
oversized := bytes.Repeat([]byte("A"), maxWebhookBodySize+1)
|
||||||
oversized := bytes.Repeat([]byte("A"), (1<<20)+1)
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(oversized))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(oversized))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
|
@ -23,6 +22,36 @@ func TestWebhookRejectsOversizedBody(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWebhookAcceptsMaxBodySize(t *testing.T) {
|
||||||
|
ch := &LINEChannel{}
|
||||||
|
|
||||||
|
body := bytes.Repeat([]byte("A"), maxWebhookBodySize)
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
ch.webhookHandler(rec, req)
|
||||||
|
|
||||||
|
// Missing signature should be rejected, but the body size should not trigger 413.
|
||||||
|
if rec.Code != http.StatusForbidden {
|
||||||
|
t.Errorf("expected status %d, got %d", http.StatusForbidden, rec.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWebhookRejectsOversizedBodyBeforeSignatureCheck(t *testing.T) {
|
||||||
|
ch := &LINEChannel{}
|
||||||
|
|
||||||
|
oversized := bytes.Repeat([]byte("A"), maxWebhookBodySize+1)
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(oversized))
|
||||||
|
req.Header.Set("X-Line-Signature", "invalidsignature")
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
ch.webhookHandler(rec, req)
|
||||||
|
|
||||||
|
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||||
|
t.Errorf("expected status %d, got %d", http.StatusRequestEntityTooLarge, rec.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWebhookRejectsNonPostMethod(t *testing.T) {
|
func TestWebhookRejectsNonPostMethod(t *testing.T) {
|
||||||
ch := &LINEChannel{}
|
ch := &LINEChannel{}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue