Skip to content

Commit

Permalink
feat: Add Drop method to DefaultCtx for silent connection termination (
Browse files Browse the repository at this point in the history
…#3257)

* Add Drop method to DefaultCtx and remove redundant checks

Introduced a Drop method in DefaultCtx for closing connections, enabling easier resource management. Removed unnecessary nil-checks for headers in manager_msgp to simplify code logic. Added a unit test to ensure the new Drop method behaves as expected.

* Add `Drop` method to Fiber context API documentation

The `Drop` method allows silently terminating client connections without sending HTTP headers or a response body. This is useful for scenarios like mitigating DDoS attacks or blocking unauthorized access to sensitive endpoints. Example usage and function signature are included in the updated documentation.

* Remove extraneous blank line in documentation.

Eliminated an unnecessary blank line in the API context documentation for improved readability and formatting consistency. No functional changes were made to the content.

* Update API documentation example to return "Hello World!"

Revised the example code in the API documentation to return a generic "Hello World!" string instead of a dynamic response. This improves consistency and simplifies the example for easier understanding.

* Refactor Drop method and extend test coverage.

Simplified the Drop method by inlining the connection close call. Added new test cases to ensure proper handling of no-response scenarios and improved overall test coverage.

* fix golangci-lint issue

* Add test for Ctx.Drop with middleware interaction

This test ensures the correct behavior of the Ctx.Drop method when used with middleware, including response handling and error scenarios. It verifies that the middleware and handler properly handle the Drop call and its resulting effects.

* Add Drop method to DefaultCtx for closing connections

The Drop method allows closing connections without sending a response, improving control over connection handling. Also updated a test assertion to use StatusOK for improved readability and consistency.

* Refine Drop method comments to clarify error handling.

Explain the rationale for not wrapping errors in the Drop method. Emphasize that the returned error is solely for logging and not for further propagation or processing.

* Update Drop method documentation for clarity

Clarified the `Drop` method's behavior, specifying that it closes the connection without sending headers or a body. Added examples of use cases, such as DDoS mitigation and blocking sensitive endpoints.

* Refactor response header setting in middleware.

Replaced the direct header setting with the `Set` method for consistency and improved clarity. Removed a test case checking for a panic on closed response body as it is no longer applicable.
  • Loading branch information
ryanbekhen authored Dec 23, 2024
1 parent 1c9b6ce commit 58677d5
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
8 changes: 8 additions & 0 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -1978,3 +1978,11 @@ func (c *DefaultCtx) setMatched(matched bool) {
func (c *DefaultCtx) setRoute(route *Route) {
c.route = route
}

// Drop closes the underlying connection without sending any response headers or body.
// This can be useful for silently terminating client connections, such as in DDoS mitigation
// or when blocking access to sensitive endpoints.
func (c *DefaultCtx) Drop() error {
//nolint:wrapcheck // error wrapping is avoided to keep the operation lightweight and focused on connection closure.
return c.RequestCtx().Conn().Close()
}
1 change: 1 addition & 0 deletions ctx_interface_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5847,6 +5847,59 @@ func Test_GenericParseTypeBoolean(t *testing.T) {
}
}

// go test -run Test_Ctx_Drop -v
func Test_Ctx_Drop(t *testing.T) {
t.Parallel()

app := New()

// Handler that calls Drop
app.Get("/block-me", func(c Ctx) error {
return c.Drop()
})

// Additional handler that just calls return
app.Get("/no-response", func(_ Ctx) error {
return nil
})

// Test the Drop method
resp, err := app.Test(httptest.NewRequest(MethodGet, "/block-me", nil))
require.Error(t, err)
require.Nil(t, resp)

// Test the no-response handler
resp, err = app.Test(httptest.NewRequest(MethodGet, "/no-response", nil))
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, StatusOK, resp.StatusCode)
require.Equal(t, "0", resp.Header.Get("Content-Length"))
}

// go test -run Test_Ctx_DropWithMiddleware -v
func Test_Ctx_DropWithMiddleware(t *testing.T) {
t.Parallel()

app := New()

// Middleware that calls Drop
app.Use(func(c Ctx) error {
err := c.Next()
c.Set("X-Test", "test")
return err
})

// Handler that calls Drop
app.Get("/block-me", func(c Ctx) error {
return c.Drop()
})

// Test the Drop method
resp, err := app.Test(httptest.NewRequest(MethodGet, "/block-me", nil))
require.Error(t, err)
require.Nil(t, resp)
}

// go test -run Test_GenericParseTypeString
func Test_GenericParseTypeString(t *testing.T) {
t.Parallel()
Expand Down
21 changes: 21 additions & 0 deletions docs/api/ctx.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,27 @@ app.Get("/", func(c fiber.Ctx) error {
})
```

## Drop

Terminates the client connection silently without sending any HTTP headers or response body.

This can be used for scenarios where you want to block certain requests without notifying the client, such as mitigating
DDoS attacks or protecting sensitive endpoints from unauthorized access.

```go title="Signature"
func (c fiber.Ctx) Drop() error
```

```go title="Example"
app.Get("/", func(c fiber.Ctx) error {
if c.IP() == "192.168.1.1" {
return c.Drop()
}

return c.SendString("Hello World!")
})
```

## Format

Performs content-negotiation on the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) HTTP header. It uses [Accepts](ctx.md#accepts) to select a proper format from the supplied offers. A default handler can be provided by setting the `MediaType` to `"default"`. If no offers match and no default is provided, a 406 (Not Acceptable) response is sent. The Content-Type is automatically set when a handler is selected.
Expand Down
6 changes: 0 additions & 6 deletions middleware/cache/manager_msgp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 comment on commit 58677d5

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 58677d5 Previous: 47be681 Ratio
Benchmark_Utils_GetOffer/1_parameter 206.7 ns/op 0 B/op 0 allocs/op 131.7 ns/op 0 B/op 0 allocs/op 1.57
Benchmark_Utils_GetOffer/1_parameter - ns/op 206.7 ns/op 131.7 ns/op 1.57
Benchmark_Middleware_BasicAuth - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_Middleware_BasicAuth_Upper - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth_Upper - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_CORS_NewHandler - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandler - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflight - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflight - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_Middleware_CSRF_GenerateToken - B/op 518 B/op 332 B/op 1.56
Benchmark_Middleware_CSRF_GenerateToken - allocs/op 10 allocs/op 6 allocs/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.