在使用Golang时,是否建议(进一步)限制表单的大小?

huangapple go评论82阅读模式
英文:

Is it advisable to (further) limit the size of forms when using golang?

问题

我搜索了一下,据我所知,POST表单请求的大小已经限制在10MB以内(http://golang.org/src/net/http/request.go#L721)。

如果我想在我的ServeHTTP方法中减小这个限制,我不确定如何正确地做到这一点。我会尝试像这样的代码:

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 
err := r.ParseForm()
if err != nil {
     //重定向到某个错误页面
     return
}

但是,如果发生错误后返回,连接会被关闭吗?我该如何避免读取所有内容?我在这里找到了一个解答:https://stackoverflow.com/a/26393261/2202497,但是如果内容长度没有设置,在读取过程中我意识到文件太大怎么办?

我将这样使用它作为一种安全措施,以防止有人占用我的服务器资源。

英文:

I searched around and as far as I can tell, POST form requests are already limited to 10MB (http://golang.org/src/net/http/request.go#L721).

If I were to go about reducing this in my ServeHTTP method, I'm not sure how to properly do it. I would try something like this:

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 
err := r.ParseForm()
if err != nil {
     //redirect to some error page
     return
}

But would returning upon error close the connection as well? How would I prevent having to read everything? I found this: https://stackoverflow.com/a/26393261/2202497, but what if content length is not set and in the middle of reading I realize that the file is too big.

I'm using this as a security measure to prevent someone from hogging my server's resources.

答案1

得分: 39

正确限制请求体大小的方法是按照你所建议的进行操作:

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 
err := r.ParseForm()
if err != nil {
 // 重定向或设置错误状态码。
 return
}

当达到限制时,MaxBytesReader会在响应中设置一个标志。当设置了该标志时,服务器不会读取请求体的剩余部分,并在处理程序返回时关闭连接。

如果你担心恶意客户端,还应该设置Server.ReadTimeout、Server.WriteTimeout和可能的Server.MaxHeaderBytes。

如果你想为所有处理程序设置请求体限制,可以在将根处理程序包装在一个处理程序中之前设置限制:

type maxBytesHandler struct {
    h http.Handler
    n int64
}

func (h *maxBytesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.Body = http.MaxBytesReader(w, r.Body, h.n) 
    h.h.ServeHTTP(w, r)
}

在调用ListenAndServe时包装根处理程序:

log.Fatal(http.ListenAndServe(":8080", &maxBytesHandler{h:mux, n:4096}))

或在配置服务器时进行包装:

s := http.Server{
    Addr:    ":8080",
    Handler: &maxBytesReader{h:mux, n:4096},
}
log.Fatal(s.ListenAndServe())

不需要像另一个答案中建议的补丁。MaxBytesReader是限制请求体大小的官方方法。

英文:

The correct way to limit the size of the request body is to do as you suggested:

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 
err := r.ParseForm()
if err != nil {
 // redirect or set error status code.
 return
}

MaxBytesReader sets a flag on the response when the limit is reached. When this flag is set, the server does not read the remainder of the request body and the server closes the connection on return from the handler.

If you are concerned about malicious clients, then you should also set Server.ReadTimeout, Server.WriteTimeout and possibly Server.MaxHeaderBytes.

If you want to set the request body limit for all of your handlers, then wrap root handler with a handler that sets the limit before delegating to the root handler:

 type maxBytesHandler struct {
     h http.Handler
     n int64
 }

 func (h *maxBytesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
     r.Body = http.MaxBytesReader(w, r.Body, h.n) 
     h.h.ServeHTTP(w, r)
 }

Wrap the root handler when calling ListenAndServe:

log.Fatal(http.ListenAndServe(":8080", &maxBytesHandler{h:mux, n:4096))

or when configuring a server:

s := http.Server{
    Addr: ":8080",
    Handler: &maxBytesReader{h:mux, n:4096},
}
log.Fatal(s.ListenAndServe())

There's no need for a patch as suggested in another answer. MaxBytesReader is the official way to limit the size of the request body.

答案2

得分: 0

编辑:正如其他人引用的那样,MaxByteReader是支持的方式。有趣的是,默认的读取器实际上是在类型断言为max byte reader之后的limitreader。

提交一个补丁到Go源代码并使其可配置!毕竟你正在与一个开源项目合作。为http.Request添加一个setter,并为其编写一些单元测试可能只需要20分钟的工作。在这里硬编码一个值有点笨拙,回馈并修复它吧 :)。

当然,如果你真的需要覆盖这个功能,你可以实现自己的ParseForm(r *http.Request)方法。Go本质上是BSD许可,所以你可以复制粘贴库中的ParseForm函数并更改限制,但这有点丑陋,不是吗?

英文:

Edit: As others cited MaxByteReader is the supported way. It is interesting that the default reader is instead, limitreader after type asserting for max byte reader.

<strike>Submit a patch to the Go source code and make it configurable! You are working with an open source project after all. Adding a setter to http.Request and some unit tests for it is probably only 20 minutes worth of work. Having a hardcoded value here is a bit clunky, give back and fix it :).

You can of course implement your own ParseForm(r *http.Request) method if you really need to override this. Go is essentially BSD, so you can copy paste the library ParseForm and change the limit, but thats a bit ugly no?</strike>

huangapple
  • 本文由 发表于 2015年2月3日 00:35:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/28282370.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定