security: add HTTP server timeouts to prevent slowloris attacks
Configure HTTP server with sensible timeouts: - ReadTimeout: 30s (time to read entire request) - WriteTimeout: 30s (time to write response) - IdleTimeout: 120s (keep-alive connection timeout) - ReadHeaderTimeout: 10s (time to read request headers) For SSE connections, use http.ResponseController to extend write deadlines before each write, preventing timeout on long-lived streams while still protecting against slow clients. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -481,6 +481,82 @@ func TestHTTPTransportOptionsRequest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPTransportDefaultConfig(t *testing.T) {
|
||||
server := NewServer(nil, log.New(io.Discard, "", 0))
|
||||
transport := NewHTTPTransport(server, HTTPConfig{})
|
||||
|
||||
// Verify defaults are applied
|
||||
if transport.config.Address != "127.0.0.1:8080" {
|
||||
t.Errorf("Expected default address 127.0.0.1:8080, got %s", transport.config.Address)
|
||||
}
|
||||
if transport.config.Endpoint != "/mcp" {
|
||||
t.Errorf("Expected default endpoint /mcp, got %s", transport.config.Endpoint)
|
||||
}
|
||||
if transport.config.SessionTTL != 30*time.Minute {
|
||||
t.Errorf("Expected default session TTL 30m, got %v", transport.config.SessionTTL)
|
||||
}
|
||||
if transport.config.MaxRequestSize != DefaultMaxRequestSize {
|
||||
t.Errorf("Expected default max request size %d, got %d", DefaultMaxRequestSize, transport.config.MaxRequestSize)
|
||||
}
|
||||
if transport.config.ReadTimeout != DefaultReadTimeout {
|
||||
t.Errorf("Expected default read timeout %v, got %v", DefaultReadTimeout, transport.config.ReadTimeout)
|
||||
}
|
||||
if transport.config.WriteTimeout != DefaultWriteTimeout {
|
||||
t.Errorf("Expected default write timeout %v, got %v", DefaultWriteTimeout, transport.config.WriteTimeout)
|
||||
}
|
||||
if transport.config.IdleTimeout != DefaultIdleTimeout {
|
||||
t.Errorf("Expected default idle timeout %v, got %v", DefaultIdleTimeout, transport.config.IdleTimeout)
|
||||
}
|
||||
if transport.config.ReadHeaderTimeout != DefaultReadHeaderTimeout {
|
||||
t.Errorf("Expected default read header timeout %v, got %v", DefaultReadHeaderTimeout, transport.config.ReadHeaderTimeout)
|
||||
}
|
||||
|
||||
transport.sessions.Stop()
|
||||
}
|
||||
|
||||
func TestHTTPTransportCustomConfig(t *testing.T) {
|
||||
server := NewServer(nil, log.New(io.Discard, "", 0))
|
||||
config := HTTPConfig{
|
||||
Address: "0.0.0.0:9090",
|
||||
Endpoint: "/api/mcp",
|
||||
SessionTTL: 1 * time.Hour,
|
||||
MaxRequestSize: 5 << 20, // 5MB
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
IdleTimeout: 300 * time.Second,
|
||||
ReadHeaderTimeout: 20 * time.Second,
|
||||
}
|
||||
transport := NewHTTPTransport(server, config)
|
||||
|
||||
// Verify custom values are preserved
|
||||
if transport.config.Address != "0.0.0.0:9090" {
|
||||
t.Errorf("Expected custom address, got %s", transport.config.Address)
|
||||
}
|
||||
if transport.config.Endpoint != "/api/mcp" {
|
||||
t.Errorf("Expected custom endpoint, got %s", transport.config.Endpoint)
|
||||
}
|
||||
if transport.config.SessionTTL != 1*time.Hour {
|
||||
t.Errorf("Expected custom session TTL, got %v", transport.config.SessionTTL)
|
||||
}
|
||||
if transport.config.MaxRequestSize != 5<<20 {
|
||||
t.Errorf("Expected custom max request size, got %d", transport.config.MaxRequestSize)
|
||||
}
|
||||
if transport.config.ReadTimeout != 60*time.Second {
|
||||
t.Errorf("Expected custom read timeout, got %v", transport.config.ReadTimeout)
|
||||
}
|
||||
if transport.config.WriteTimeout != 60*time.Second {
|
||||
t.Errorf("Expected custom write timeout, got %v", transport.config.WriteTimeout)
|
||||
}
|
||||
if transport.config.IdleTimeout != 300*time.Second {
|
||||
t.Errorf("Expected custom idle timeout, got %v", transport.config.IdleTimeout)
|
||||
}
|
||||
if transport.config.ReadHeaderTimeout != 20*time.Second {
|
||||
t.Errorf("Expected custom read header timeout, got %v", transport.config.ReadHeaderTimeout)
|
||||
}
|
||||
|
||||
transport.sessions.Stop()
|
||||
}
|
||||
|
||||
func TestHTTPTransportRequestBodyTooLarge(t *testing.T) {
|
||||
_, ts := testHTTPTransport(t, HTTPConfig{
|
||||
MaxRequestSize: 100, // Very small limit for testing
|
||||
|
||||
Reference in New Issue
Block a user