@@ -7,15 +7,42 @@ import (
77 "net/http"
88)
99
10+ // DefaultMaxBodySize is the default maximum request body size
11+ // (10 MB) used by the size-limited body reading functions.
12+ // This prevents denial-of-service attacks via excessively
13+ // large request bodies that could exhaust server memory.
14+ const DefaultMaxBodySize int64 = 10 << 20 // 10 MB
15+
1016// Bytes reads the entire request body and returns it as a byte slice.
1117// The request body is consumed after this call and cannot be read again.
18+ //
19+ // WARNING: This function reads the body without any size limit.
20+ // Prefer [LimitedBytes] or apply [http.MaxBytesReader] in a
21+ // middleware to prevent memory exhaustion from oversized requests.
1222func Bytes (r * http.Request ) ([]byte , error ) {
1323 return io .ReadAll (r .Body )
1424}
1525
26+ // LimitedBytes reads the request body up to maxSize bytes and
27+ // returns it as a byte slice. If the body exceeds maxSize, an
28+ // error is returned. This prevents denial-of-service attacks via
29+ // excessively large request bodies. Pass -1 to use
30+ // [DefaultMaxBodySize].
31+ func LimitedBytes (r * http.Request , maxSize int64 ) ([]byte , error ) {
32+ if maxSize < 0 {
33+ maxSize = DefaultMaxBodySize
34+ }
35+
36+ return io .ReadAll (io .LimitReader (r .Body , maxSize + 1 ))
37+ }
38+
1639// String reads the request body and returns it as a string.
1740// It uses [Bytes] internally. The request body is consumed
1841// after this call and cannot be read again.
42+ //
43+ // WARNING: This function reads the body without any size limit.
44+ // Prefer [LimitedString] or apply [http.MaxBytesReader] in a
45+ // middleware to prevent memory exhaustion from oversized requests.
1946func String (r * http.Request ) (string , error ) {
2047 b , err := Bytes (r )
2148
@@ -26,9 +53,26 @@ func String(r *http.Request) (string, error) {
2653 return string (b ), nil
2754}
2855
56+ // LimitedString reads the request body up to maxSize bytes and
57+ // returns it as a string. If the body exceeds maxSize, the result
58+ // is truncated. Pass -1 to use [DefaultMaxBodySize].
59+ func LimitedString (r * http.Request , maxSize int64 ) (string , error ) {
60+ b , err := LimitedBytes (r , maxSize )
61+
62+ if err != nil {
63+ return "" , err
64+ }
65+
66+ return string (b ), nil
67+ }
68+
2969// JSON decodes JSON data from the request body into a value of type T.
3070// It uses a streaming decoder for memory efficiency. The type parameter
3171// T should match the expected JSON structure.
72+ //
73+ // WARNING: This function decodes without any body size limit.
74+ // Prefer [LimitedJSON] or apply [http.MaxBytesReader] in a
75+ // middleware to prevent memory exhaustion from oversized requests.
3276func JSON [T any ](r * http.Request ) (value T , err error ) {
3377 if err := json .NewDecoder (r .Body ).Decode (& value ); err != nil {
3478 return value , err
@@ -37,13 +81,53 @@ func JSON[T any](r *http.Request) (value T, err error) {
3781 return value , nil
3882}
3983
84+ // LimitedJSON decodes JSON data from the request body into a value
85+ // of type T, reading at most maxSize bytes. This prevents
86+ // denial-of-service attacks via oversized JSON payloads. Pass -1
87+ // to use [DefaultMaxBodySize].
88+ func LimitedJSON [T any ](r * http.Request , maxSize int64 ) (value T , err error ) {
89+ if maxSize < 0 {
90+ maxSize = DefaultMaxBodySize
91+ }
92+
93+ limited := io .LimitReader (r .Body , maxSize + 1 )
94+
95+ if err := json .NewDecoder (limited ).Decode (& value ); err != nil {
96+ return value , err
97+ }
98+
99+ return value , nil
100+ }
101+
40102// XML decodes XML data from the request body into a value of type T.
41103// It uses a streaming decoder for memory efficiency. The type parameter
42104// T should have appropriate xml struct tags or implement [xml.Unmarshaler].
105+ //
106+ // WARNING: This function decodes without any body size limit.
107+ // Prefer [LimitedXML] or apply [http.MaxBytesReader] in a
108+ // middleware to prevent memory exhaustion from oversized requests.
43109func XML [T any ](r * http.Request ) (value T , err error ) {
44110 if err := xml .NewDecoder (r .Body ).Decode (& value ); err != nil {
45111 return value , err
46112 }
47113
48114 return value , nil
49115}
116+
117+ // LimitedXML decodes XML data from the request body into a value
118+ // of type T, reading at most maxSize bytes. This prevents
119+ // denial-of-service attacks via oversized XML payloads. Pass -1
120+ // to use [DefaultMaxBodySize].
121+ func LimitedXML [T any ](r * http.Request , maxSize int64 ) (value T , err error ) {
122+ if maxSize < 0 {
123+ maxSize = DefaultMaxBodySize
124+ }
125+
126+ limited := io .LimitReader (r .Body , maxSize + 1 )
127+
128+ if err := xml .NewDecoder (limited ).Decode (& value ); err != nil {
129+ return value , err
130+ }
131+
132+ return value , nil
133+ }
0 commit comments