Pull request #1005: home: imp large req handling

Merge in DNS/adguard-home from 2675-larger-requests to master

Updates #2675.

Squashed commit of the following:

commit 2b45c9bfdc817980204b11de768b425fb72a6488
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Feb 15 13:38:44 2021 +0300

    home: imp names

commit dad39ae7ee35346ea91f15665acc93ba0b5653df
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Feb 15 13:31:53 2021 +0300

    home: imp large req handling
This commit is contained in:
Ainar Garipov 2021-02-15 13:56:41 +03:00
parent 8a0bc5468b
commit 7d1ca48ae4
3 changed files with 34 additions and 15 deletions

View File

@ -23,8 +23,8 @@ and this project adheres to
longer prevent the DHCP server from starting ([#2667]). longer prevent the DHCP server from starting ([#2667]).
- The server name sent by clients of TLS APIs is not only checked when - The server name sent by clients of TLS APIs is not only checked when
`strict_sni_check` is enabled ([#2664]). `strict_sni_check` is enabled ([#2664]).
- HTTP API request body size limit for the `POST /control/access/set` HTTP API - HTTP API request body size limit for the `POST /control/access/set` and `POST
is increased ([#2666]). /control/filtering/set_rules` HTTP APIs is increased ([#2666], [#2675]).
### Fixed ### Fixed
@ -45,6 +45,7 @@ and this project adheres to
[#2664]: https://github.com/AdguardTeam/AdGuardHome/issues/2664 [#2664]: https://github.com/AdguardTeam/AdGuardHome/issues/2664
[#2666]: https://github.com/AdguardTeam/AdGuardHome/issues/2666 [#2666]: https://github.com/AdguardTeam/AdGuardHome/issues/2666
[#2667]: https://github.com/AdguardTeam/AdGuardHome/issues/2667 [#2667]: https://github.com/AdguardTeam/AdGuardHome/issues/2667
[#2675]: https://github.com/AdguardTeam/AdGuardHome/issues/2675
[#2678]: https://github.com/AdguardTeam/AdGuardHome/issues/2678 [#2678]: https://github.com/AdguardTeam/AdGuardHome/issues/2678

View File

@ -22,8 +22,30 @@ func withMiddlewares(h http.Handler, middlewares ...middleware) (wrapped http.Ha
return wrapped return wrapped
} }
// RequestBodySizeLimit is maximum request body length in bytes. // defaultReqBodySzLim is the default maximum request body size.
const RequestBodySizeLimit = 64 * 1024 const defaultReqBodySzLim = 64 * 1024
// largerReqBodySzLim is the maximum request body size for APIs expecting larger
// requests.
const largerReqBodySzLim = 4 * 1024 * 1024
// expectsLargerRequests shows if this request should use a larger body size
// limit. These are exceptions for poorly designed current APIs as well as APIs
// that are designed to expect large files and requests. Remove once the new,
// better APIs are up.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2666 and
// https://github.com/AdguardTeam/AdGuardHome/issues/2675.
func expectsLargerRequests(r *http.Request) (ok bool) {
m := r.Method
if m != http.MethodPost {
return false
}
p := r.URL.Path
return p == "/control/access/set" ||
p == "/control/filtering/set_rules"
}
// limitRequestBody wraps underlying handler h, making it's request's body Read // limitRequestBody wraps underlying handler h, making it's request's body Read
// method limited. // method limited.
@ -31,16 +53,12 @@ func limitRequestBody(h http.Handler) (limited http.Handler) {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error var err error
var bodySizeLimit int64 = RequestBodySizeLimit var szLim int64 = defaultReqBodySzLim
if u := r.URL; u.Path == "/control/access/set" { if expectsLargerRequests(r) {
// An exception for a poorly designed API. Remove once szLim = largerReqBodySzLim
// the new, better API is up.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2666.
bodySizeLimit *= 4
} }
r.Body, err = aghio.LimitReadCloser(r.Body, bodySizeLimit) r.Body, err = aghio.LimitReadCloser(r.Body, szLim)
if err != nil { if err != nil {
log.Error("limitRequestBody: %s", err) log.Error("limitRequestBody: %s", err)

View File

@ -14,7 +14,7 @@ import (
func TestLimitRequestBody(t *testing.T) { func TestLimitRequestBody(t *testing.T) {
errReqLimitReached := &aghio.LimitReachedError{ errReqLimitReached := &aghio.LimitReachedError{
Limit: RequestBodySizeLimit, Limit: defaultReqBodySzLim,
} }
testCases := []struct { testCases := []struct {
@ -29,8 +29,8 @@ func TestLimitRequestBody(t *testing.T) {
wantErr: nil, wantErr: nil,
}, { }, {
name: "so_big", name: "so_big",
body: string(make([]byte, RequestBodySizeLimit+1)), body: string(make([]byte, defaultReqBodySzLim+1)),
want: make([]byte, RequestBodySizeLimit), want: make([]byte, defaultReqBodySzLim),
wantErr: errReqLimitReached, wantErr: errReqLimitReached,
}, { }, {
name: "empty", name: "empty",