max_request_body_bytes_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package apiserver
  14. import (
  15. "context"
  16. "fmt"
  17. "strings"
  18. "testing"
  19. v1 "k8s.io/api/core/v1"
  20. apierrors "k8s.io/apimachinery/pkg/api/errors"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/kubernetes/test/integration/framework"
  24. )
  25. // Tests that the apiserver limits the resource size in write operations.
  26. func TestMaxResourceSize(t *testing.T) {
  27. stopCh := make(chan struct{})
  28. defer close(stopCh)
  29. clientSet, _ := framework.StartTestServer(t, stopCh, framework.TestServerSetup{})
  30. hugeData := []byte(strings.Repeat("x", 3*1024*1024+1))
  31. rest := clientSet.Discovery().RESTClient()
  32. c := clientSet.CoreV1().RESTClient()
  33. t.Run("Create should limit the request body size", func(t *testing.T) {
  34. err := c.Post().AbsPath(fmt.Sprintf("/api/v1/namespaces/default/pods")).
  35. Body(hugeData).Do(context.TODO()).Error()
  36. if err == nil {
  37. t.Fatalf("unexpected no error")
  38. }
  39. if !apierrors.IsRequestEntityTooLargeError(err) {
  40. t.Errorf("expected requested entity too large err, got %v", err)
  41. }
  42. })
  43. // Create a secret so we can update/patch/delete it.
  44. secret := &v1.Secret{
  45. ObjectMeta: metav1.ObjectMeta{
  46. Name: "test",
  47. },
  48. }
  49. _, err := clientSet.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{})
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. t.Run("Update should limit the request body size", func(t *testing.T) {
  54. err = c.Put().AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  55. Body(hugeData).Do(context.TODO()).Error()
  56. if err == nil {
  57. t.Fatalf("unexpected no error")
  58. }
  59. if !apierrors.IsRequestEntityTooLargeError(err) {
  60. t.Errorf("expected requested entity too large err, got %v", err)
  61. }
  62. })
  63. t.Run("Patch should limit the request body size", func(t *testing.T) {
  64. err = c.Patch(types.JSONPatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  65. Body(hugeData).Do(context.TODO()).Error()
  66. if err == nil {
  67. t.Fatalf("unexpected no error")
  68. }
  69. if !apierrors.IsRequestEntityTooLargeError(err) {
  70. t.Errorf("expected requested entity too large err, got %v", err)
  71. }
  72. })
  73. t.Run("JSONPatchType should handle a patch just under the max limit", func(t *testing.T) {
  74. patchBody := []byte(`[{"op":"add","path":"/foo","value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}]`)
  75. err = rest.Patch(types.JSONPatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  76. Body(patchBody).Do(context.TODO()).Error()
  77. if err != nil && !apierrors.IsBadRequest(err) {
  78. t.Errorf("expected success or bad request err, got %v", err)
  79. }
  80. })
  81. t.Run("JSONPatchType should handle a valid patch just under the max limit", func(t *testing.T) {
  82. patchBody := []byte(`[{"op":"add","path":"/foo","value":0` + strings.Repeat(" ", 3*1024*1024-100) + `}]`)
  83. err = rest.Patch(types.JSONPatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  84. Body(patchBody).Do(context.TODO()).Error()
  85. if err != nil {
  86. t.Errorf("unexpected error: %v", err)
  87. }
  88. })
  89. t.Run("MergePatchType should handle a patch just under the max limit", func(t *testing.T) {
  90. patchBody := []byte(`{"value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}`)
  91. err = rest.Patch(types.MergePatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  92. Body(patchBody).Do(context.TODO()).Error()
  93. if err != nil && !apierrors.IsBadRequest(err) {
  94. t.Errorf("expected success or bad request err, got %v", err)
  95. }
  96. })
  97. t.Run("MergePatchType should handle a valid patch just under the max limit", func(t *testing.T) {
  98. patchBody := []byte(`{"value":0` + strings.Repeat(" ", 3*1024*1024-100) + `}`)
  99. err = rest.Patch(types.MergePatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  100. Body(patchBody).Do(context.TODO()).Error()
  101. if err != nil {
  102. t.Errorf("unexpected error: %v", err)
  103. }
  104. })
  105. t.Run("StrategicMergePatchType should handle a patch just under the max limit", func(t *testing.T) {
  106. patchBody := []byte(`{"value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}`)
  107. err = rest.Patch(types.StrategicMergePatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  108. Body(patchBody).Do(context.TODO()).Error()
  109. if err != nil && !apierrors.IsBadRequest(err) {
  110. t.Errorf("expected success or bad request err, got %v", err)
  111. }
  112. })
  113. t.Run("StrategicMergePatchType should handle a valid patch just under the max limit", func(t *testing.T) {
  114. patchBody := []byte(`{"value":0` + strings.Repeat(" ", 3*1024*1024-100) + `}`)
  115. err = rest.Patch(types.StrategicMergePatchType).AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  116. Body(patchBody).Do(context.TODO()).Error()
  117. if err != nil {
  118. t.Errorf("unexpected error: %v", err)
  119. }
  120. })
  121. t.Run("ApplyPatchType should handle a patch just under the max limit", func(t *testing.T) {
  122. patchBody := []byte(`{"value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}`)
  123. err = rest.Patch(types.ApplyPatchType).Param("fieldManager", "test").AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  124. Body(patchBody).Do(context.TODO()).Error()
  125. if err != nil && !apierrors.IsBadRequest(err) {
  126. t.Errorf("expected success or bad request err, got %#v", err)
  127. }
  128. })
  129. t.Run("ApplyPatchType should handle a valid patch just under the max limit", func(t *testing.T) {
  130. patchBody := []byte(`{"apiVersion":"v1","kind":"Secret"` + strings.Repeat(" ", 3*1024*1024-100) + `}`)
  131. err = rest.Patch(types.ApplyPatchType).Param("fieldManager", "test").AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  132. Body(patchBody).Do(context.TODO()).Error()
  133. if err != nil {
  134. t.Errorf("unexpected error: %v", err)
  135. }
  136. })
  137. t.Run("Delete should limit the request body size", func(t *testing.T) {
  138. err = c.Delete().AbsPath(fmt.Sprintf("/api/v1/namespaces/default/secrets/test")).
  139. Body(hugeData).Do(context.TODO()).Error()
  140. if err == nil {
  141. t.Fatalf("unexpected no error")
  142. }
  143. if !apierrors.IsRequestEntityTooLargeError(err) {
  144. t.Errorf("expected requested entity too large err, got %v", err)
  145. }
  146. })
  147. // Create YAML over 3MB limit
  148. t.Run("create should limit yaml parsing", func(t *testing.T) {
  149. yamlBody := []byte(`
  150. apiVersion: v1
  151. kind: ConfigMap
  152. metadata:
  153. name: mytest
  154. values: ` + strings.Repeat("[", 3*1024*1024))
  155. _, err := rest.Post().
  156. SetHeader("Accept", "application/yaml").
  157. SetHeader("Content-Type", "application/yaml").
  158. AbsPath("/api/v1/namespaces/default/configmaps").
  159. Body(yamlBody).
  160. DoRaw(context.TODO())
  161. if !apierrors.IsRequestEntityTooLargeError(err) {
  162. t.Errorf("expected too large error, got %v", err)
  163. }
  164. })
  165. // Create YAML just under 3MB limit, nested
  166. t.Run("create should handle a yaml document just under the maximum size with correct nesting", func(t *testing.T) {
  167. yamlBody := []byte(`
  168. apiVersion: v1
  169. kind: ConfigMap
  170. metadata:
  171. name: mytest
  172. values: ` + strings.Repeat("[", 3*1024*1024/2-500) + strings.Repeat("]", 3*1024*1024/2-500))
  173. _, err := rest.Post().
  174. SetHeader("Accept", "application/yaml").
  175. SetHeader("Content-Type", "application/yaml").
  176. AbsPath("/api/v1/namespaces/default/configmaps").
  177. Body(yamlBody).
  178. DoRaw(context.TODO())
  179. if !apierrors.IsBadRequest(err) {
  180. t.Errorf("expected bad request, got %v", err)
  181. }
  182. })
  183. // Create YAML just under 3MB limit, not nested
  184. t.Run("create should handle a yaml document just under the maximum size with unbalanced nesting", func(t *testing.T) {
  185. yamlBody := []byte(`
  186. apiVersion: v1
  187. kind: ConfigMap
  188. metadata:
  189. name: mytest
  190. values: ` + strings.Repeat("[", 3*1024*1024-1000))
  191. _, err := rest.Post().
  192. SetHeader("Accept", "application/yaml").
  193. SetHeader("Content-Type", "application/yaml").
  194. AbsPath("/api/v1/namespaces/default/configmaps").
  195. Body(yamlBody).
  196. DoRaw(context.TODO())
  197. if !apierrors.IsBadRequest(err) {
  198. t.Errorf("expected bad request, got %v", err)
  199. }
  200. })
  201. // Create JSON over 3MB limit
  202. t.Run("create should limit json parsing", func(t *testing.T) {
  203. jsonBody := []byte(`{
  204. "apiVersion": "v1",
  205. "kind": "ConfigMap",
  206. "metadata": {
  207. "name": "mytest"
  208. },
  209. "values": ` + strings.Repeat("[", 3*1024*1024/2) + strings.Repeat("]", 3*1024*1024/2) + "}")
  210. _, err := rest.Post().
  211. SetHeader("Accept", "application/json").
  212. SetHeader("Content-Type", "application/json").
  213. AbsPath("/api/v1/namespaces/default/configmaps").
  214. Body(jsonBody).
  215. DoRaw(context.TODO())
  216. if !apierrors.IsRequestEntityTooLargeError(err) {
  217. t.Errorf("expected too large error, got %v", err)
  218. }
  219. })
  220. // Create JSON just under 3MB limit, nested
  221. t.Run("create should handle a json document just under the maximum size with correct nesting", func(t *testing.T) {
  222. jsonBody := []byte(`{
  223. "apiVersion": "v1",
  224. "kind": "ConfigMap",
  225. "metadata": {
  226. "name": "mytest"
  227. },
  228. "values": ` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + "}")
  229. _, err := rest.Post().
  230. SetHeader("Accept", "application/json").
  231. SetHeader("Content-Type", "application/json").
  232. AbsPath("/api/v1/namespaces/default/configmaps").
  233. Body(jsonBody).
  234. DoRaw(context.TODO())
  235. // TODO(liggitt): expect bad request on deep nesting, rather than success on dropped unknown field data
  236. if err != nil && !apierrors.IsBadRequest(err) {
  237. t.Errorf("expected bad request, got %v", err)
  238. }
  239. })
  240. // Create JSON just under 3MB limit, not nested
  241. t.Run("create should handle a json document just under the maximum size with unbalanced nesting", func(t *testing.T) {
  242. jsonBody := []byte(`{
  243. "apiVersion": "v1",
  244. "kind": "ConfigMap",
  245. "metadata": {
  246. "name": "mytest"
  247. },
  248. "values": ` + strings.Repeat("[", 3*1024*1024-1000) + "}")
  249. _, err := rest.Post().
  250. SetHeader("Accept", "application/json").
  251. SetHeader("Content-Type", "application/json").
  252. AbsPath("/api/v1/namespaces/default/configmaps").
  253. Body(jsonBody).
  254. DoRaw(context.TODO())
  255. if !apierrors.IsBadRequest(err) {
  256. t.Errorf("expected bad request, got %v", err)
  257. }
  258. })
  259. }