Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit bytes during response body read / NPE fix #1202

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
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
8 changes: 7 additions & 1 deletion bridge/setu/listener/rootchain_selfheal_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
jsoniter "github.com/json-iterator/go"

"github.com/maticnetwork/heimdall/helper"
)

// StakeUpdate represents the StakeUpdate event
Expand Down Expand Up @@ -42,6 +44,7 @@ type stateSyncResponse struct {
} `json:"data"`
}

// querySubGraph queries the subgraph and limits the read size
func (rl *RootChainListener) querySubGraph(query []byte, ctx context.Context) (data []byte, err error) {
request, err := http.NewRequestWithContext(ctx, http.MethodPost, rl.subGraphClient.graphUrl, bytes.NewBuffer(query))
if err != nil {
Expand All @@ -56,7 +59,10 @@ func (rl *RootChainListener) querySubGraph(query []byte, ctx context.Context) (d
}
defer response.Body.Close()

return io.ReadAll(response.Body)
// Limit the number of bytes read from the response body
limitedBody := http.MaxBytesReader(nil, response.Body, helper.APIBodyLimit)

return io.ReadAll(limitedBody)
}

// getLatestStateID returns state ID from the latest StateSynced event
Expand Down
8 changes: 5 additions & 3 deletions bridge/setu/processor/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,14 @@ func (bp *BaseProcessor) checkTxAgainstMempool(msg types.Msg, event interface{})
bp.Logger.Error("Error fetching mempool tx", "url", endpoint, "error", err)
return false, err
}

body, err := io.ReadAll(resp.Body)
defer resp.Body.Close()

// Limit the number of bytes read from the response body
limitedBody := http.MaxBytesReader(nil, resp.Body, helper.APIBodyLimit)

body, err := io.ReadAll(limitedBody)
if err != nil {
bp.Logger.Error("Error fetching mempool tx", "error", err)
bp.Logger.Error("Error reading response body for mempool tx", "error", err)
return false, err
}

Expand Down
6 changes: 4 additions & 2 deletions bridge/setu/util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,10 +652,12 @@ func GetUnconfirmedTxnCount(event interface{}) int {
logger.Error("Error fetching mempool txs count", "url", endpoint, "error", err)
return 0
}

body, err := io.ReadAll(resp.Body)
defer resp.Body.Close()

// Limit the number of bytes read from the response body
limitedBody := http.MaxBytesReader(nil, resp.Body, helper.APIBodyLimit)

body, err := io.ReadAll(limitedBody)
if err != nil {
logger.Error("Error fetching mempool txs count", "error", err)
return 0
Expand Down
9 changes: 6 additions & 3 deletions helper/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,10 @@ func (c *ContractCaller) GetRootHash(start uint64, end uint64, checkpointLength
return common.FromHex(rootHash), nil
}

// GetRootHash get root hash from bor chain
// GetVoteOnHash gets vote on hash from bor chain
func (c *ContractCaller) GetVoteOnHash(start uint64, end uint64, milestoneLength uint64, hash string, milestoneID string) (bool, error) {
if start > end {
return false, errors.New("Start block number is greater than the end block number")
return false, errors.New("start block number is greater than the end block number")
}

ctx, cancel := context.WithTimeout(context.Background(), c.MaticChainTimeout)
Expand Down Expand Up @@ -368,7 +368,7 @@ func (c *ContractCaller) GetValidatorInfo(valID types.ValidatorID, stakingInfoIn
// amount, startEpoch, endEpoch, signer, status, err := c.StakingInfoInstance.GetStakerDetails(nil, big.NewInt(int64(valID)))
stakerDetails, err := stakingInfoInstance.GetStakerDetails(nil, big.NewInt(int64(valID)))
if err != nil {
Logger.Error("Error fetching validator information from stake manager", "validatorId", valID, "status", stakerDetails.Status, "error", err)
Logger.Error("Error fetching validator information from stake manager", "validatorId", valID, "error", err)
return
}

Expand Down Expand Up @@ -814,6 +814,9 @@ func (c *ContractCaller) GetSpanDetails(id *big.Int, validatorSetInstance *valid
error,
) {
d, err := validatorSetInstance.GetSpan(nil, id)
if err != nil {
return nil, nil, nil, err
}
return d.Number, d.StartBlock, d.EndBlock, err
}

Expand Down
24 changes: 19 additions & 5 deletions helper/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import (
"github.com/maticnetwork/heimdall/types/rest"
)

const APIBodyLimit = 128 * 1024 * 1024 // 128 MB

//go:generate mockgen -destination=./mocks/http_client_mock.go -package=mocks . HTTPClient
type HTTPClient interface {
Get(string) (resp *http.Response, err error)
Expand Down Expand Up @@ -567,10 +569,19 @@ func SignStdTx(cliCtx context.CLIContext, stdTx authTypes.StdTx, appendSig bool,
// ReadStdTxFromFile and decode a StdTx from the given filename. Can pass "-" to read from stdin.
func ReadStdTxFromFile(cdc *amino.Codec, filename string) (stdTx authTypes.StdTx, err error) {
var bytes []byte

if filename == "-" {
bytes, err = io.ReadAll(os.Stdin)
limitedReader := &io.LimitedReader{R: os.Stdin, N: APIBodyLimit}
bytes, err = io.ReadAll(limitedReader)
} else {
bytes, err = os.ReadFile(filename)
file, er := os.Open(filename)
if er != nil {
err = er
return
}
defer file.Close()
limitedReader := &io.LimitedReader{R: file, N: APIBodyLimit}
bytes, err = io.ReadAll(limitedReader)
}

if err != nil {
Expand Down Expand Up @@ -802,7 +813,7 @@ func GetHeimdallServerEndpoint(endpoint string) string {
return u.String()
}

// FetchFromAPI fetches data from any URL
// FetchFromAPI fetches data from any URL with limited read size
func FetchFromAPI(cliCtx cliContext.CLIContext, URL string) (result rest.ResponseWithHeight, err error) {
resp, err := Client.Get(URL)
if err != nil {
Expand All @@ -811,9 +822,12 @@ func FetchFromAPI(cliCtx cliContext.CLIContext, URL string) (result rest.Respons

defer resp.Body.Close()

// response
// Limit the number of bytes read from the response body
limitedBody := http.MaxBytesReader(nil, resp.Body, APIBodyLimit)

// Handle the response
if resp.StatusCode == 200 {
body, err := io.ReadAll(resp.Body)
body, err := io.ReadAll(limitedBody)
if err != nil {
return result, err
}
Expand Down
8 changes: 6 additions & 2 deletions types/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import (

const (
DefaultPage = 1
DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
APIBodyLimit = 128 * 1024 * 1024 // 128 MB
)

var (
Expand Down Expand Up @@ -128,7 +129,10 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
// ReadRESTReq reads and unmarshals a Request's body to the BaseReq struct.
// Writes an error response to ResponseWriter and returns true if errors occurred.
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) bool {
body, err := io.ReadAll(r.Body)
// Limit the number of bytes read from the request body
limitedBody := http.MaxBytesReader(w, r.Body, APIBodyLimit)

body, err := io.ReadAll(limitedBody)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return false
Expand Down
Loading