Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions gno.land/pkg/gnoweb/feature/playground/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ const (
// against memory exhaustion from large or numerous on-chain package files.
maxForkCodeSize = 1 << 20 // 1 MiB

// maxEvalBodyBytes caps the eval request body to guard against memory
// exhaustion from oversized JSON payloads.
maxEvalBodyBytes = 1 << 20 // 1 MiB

// maxEvalPkgPathLen and maxEvalExpressionLen bound the eval request fields
// well below maxEvalBodyBytes, rejecting oversized requests before they are
// forwarded to the RPC node. Legitimate values are far smaller.
maxEvalPkgPathLen = 1024
maxEvalExpressionLen = 64 * 1024

// defaultCode defines the default code displayed in the code editor.
defaultCode = `package main

Expand Down Expand Up @@ -212,6 +222,8 @@ func (h *Handler) serveEval(w http.ResponseWriter, r *http.Request) {
return
}

r.Body = http.MaxBytesReader(w, r.Body, maxEvalBodyBytes)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Missing test: the three new caps have no coverage. Add to TestHandlerPlaygroundEval:

test cases
{
	name:       "oversized body",
	method:     http.MethodPost,
	body:       `{"pkg_path":"r/x","expression":"` + strings.Repeat("a", maxEvalBodyBytes+1) + `"}`,
	wantStatus: http.StatusBadRequest,
	wantError:  "invalid request body",
},
{
	name:       "oversized pkg_path",
	method:     http.MethodPost,
	body:       `{"pkg_path":"` + strings.Repeat("a", maxEvalPkgPathLen+1) + `","expression":"Render(\"\")"}`,
	wantStatus: http.StatusBadRequest,
	wantError:  "too long",
},
{
	name:       "oversized expression",
	method:     http.MethodPost,
	body:       `{"pkg_path":"r/x","expression":"` + strings.Repeat("a", maxEvalExpressionLen+1) + `"}`,
	wantStatus: http.StatusBadRequest,
	wantError:  "too long",
},


var req evalRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, evalResponse{Error: "invalid request body"})
Expand All @@ -223,6 +235,11 @@ func (h *Handler) serveEval(w http.ResponseWriter, r *http.Request) {
return
}

if len(req.PkgPath) > maxEvalPkgPathLen || len(req.Expression) > maxEvalExpressionLen {
writeJSON(w, http.StatusBadRequest, evalResponse{Error: "pkg_path or expression is too long"})
return
}

// Clean the pkg path.
pkgPath := strings.TrimPrefix(req.PkgPath, h.deps.Domain+"/")
pkgPath = strings.TrimPrefix(pkgPath, h.deps.Domain)
Expand Down