aboutsummaryrefslogtreecommitdiffstats
path: root/dashboard
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2024-12-13 10:36:01 +0100
committerTaras Madan <tarasmadan@google.com>2024-12-13 10:01:11 +0000
commitb2d784d6bd0a9f398bb3ec8962d684a6665f47b5 (patch)
tree22058cc0f828d8d790c7123131e50c5f1098343d /dashboard
parentb1b5e51af82983bdf6cd2c23eee2cb9a14e589ab (diff)
dashboard/app: deserialize data directly from gz reader
Diffstat (limited to 'dashboard')
-rw-r--r--dashboard/app/api.go102
-rw-r--r--dashboard/app/reporting_external.go21
2 files changed, 60 insertions, 63 deletions
diff --git a/dashboard/app/api.go b/dashboard/app/api.go
index b70cac882..651a1a08e 100644
--- a/dashboard/app/api.go
+++ b/dashboard/app/api.go
@@ -74,8 +74,8 @@ var apiNamespaceHandlers = map[string]APINamespaceHandler{
}
type JSONHandler func(c context.Context, r *http.Request) (interface{}, error)
-type APIHandler func(c context.Context, r *http.Request, payload []byte) (interface{}, error)
-type APINamespaceHandler func(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error)
+type APIHandler func(c context.Context, r *http.Request, payload io.Reader) (interface{}, error)
+type APINamespaceHandler func(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error)
const (
maxReproPerBug = 10
@@ -143,23 +143,19 @@ func handleAPI(c context.Context, r *http.Request) (reply interface{}, err error
if err != nil {
return nil, fmt.Errorf("checkClient('%s') error: %w", client, err)
}
- var payload []byte
+ var payloadReader io.Reader
if str := r.PostFormValue("payload"); str != "" {
gr, err := gzip.NewReader(strings.NewReader(str))
if err != nil {
return nil, fmt.Errorf("failed to ungzip payload: %w", err)
}
- payload, err = io.ReadAll(gr)
- if err != nil {
- return nil, fmt.Errorf("failed to ungzip payload: %w", err)
- }
- if err := gr.Close(); err != nil {
- return nil, fmt.Errorf("failed to ungzip payload: %w", err)
- }
+ payloadReader = gr
+ // Ignore Close() error because we may not read all data.
+ defer gr.Close()
}
handler := apiHandlers[method]
if handler != nil {
- return handler(c, r, payload)
+ return handler(c, r, payloadReader)
}
nsHandler := apiNamespaceHandlers[method]
if nsHandler == nil {
@@ -168,21 +164,21 @@ func handleAPI(c context.Context, r *http.Request) (reply interface{}, err error
if ns == "" {
return nil, fmt.Errorf("method %q must be called within a namespace", method)
}
- return nsHandler(c, ns, r, payload)
+ return nsHandler(c, ns, r, payloadReader)
}
-func apiLogError(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiLogError(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.LogEntry)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
log.Errorf(c, "%v: %v", req.Name, req.Text)
return nil, nil
}
-func apiBuilderPoll(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiBuilderPoll(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.BuilderPollReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
bugs, _, err := loadAllBugs(c, func(query *db.Query) *db.Query {
@@ -229,7 +225,7 @@ func reportEmail(c context.Context, ns string) string {
return ""
}
-func apiCommitPoll(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiCommitPoll(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
resp := &dashapi.CommitPollResp{
ReportEmail: reportEmail(c, ns),
}
@@ -295,9 +291,9 @@ func pollBackportCommits(c context.Context, ns string, count int) ([]string, err
return backportTitles, nil
}
-func apiUploadCommits(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiUploadCommits(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.CommitPollResultReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
// This adds fixing commits to bugs.
@@ -400,13 +396,13 @@ func addCommitInfoToBugImpl(c context.Context, bug *Bug, com dashapi.Commit) (bo
return changed, nil
}
-func apiJobPoll(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiJobPoll(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
if stop, err := emergentlyStopped(c); err != nil || stop {
// The bot's operation was aborted. Don't accept new crash reports.
return &dashapi.JobPollResp{}, err
}
req := new(dashapi.JobPollReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
if len(req.Managers) == 0 {
@@ -416,9 +412,9 @@ func apiJobPoll(c context.Context, r *http.Request, payload []byte) (interface{}
}
// nolint: dupl
-func apiJobDone(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiJobDone(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.JobDoneReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
err := doneJob(c, req)
@@ -426,18 +422,18 @@ func apiJobDone(c context.Context, r *http.Request, payload []byte) (interface{}
}
// nolint: dupl
-func apiJobReset(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiJobReset(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.JobResetReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
err := resetJobs(c, req)
return nil, err
}
-func apiUploadBuild(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiUploadBuild(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.Build)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
now := timeNow(c)
@@ -706,9 +702,9 @@ func managerList(c context.Context, ns string) ([]string, error) {
return managers, nil
}
-func apiReportBuildError(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportBuildError(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.BuildErrorReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
now := timeNow(c)
@@ -740,13 +736,13 @@ const (
suppressedReportTitle = "suppressed report"
)
-func apiReportCrash(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportCrash(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
if stop, err := emergentlyStopped(c); err != nil || stop {
// The bot's operation was aborted. Don't accept new crash reports.
return &dashapi.ReportCrashResp{}, err
}
req := new(dashapi.Crash)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
build, err := loadBuild(c, ns, req.BuildID)
@@ -1050,9 +1046,9 @@ func purgeOldCrashes(c context.Context, bug *Bug, bugKey *db.Key) {
log.Infof(c, "deleted %v crashes for bug %q", deleted, bug.Title)
}
-func apiReportFailedRepro(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportFailedRepro(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.CrashID)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
req.Title = canonicalizeCrashTitle(req.Title, req.Corrupted, req.Suppressed)
@@ -1122,9 +1118,9 @@ func saveReproAttempt(c context.Context, bug *Bug, build *Build, log []byte) err
return nil
}
-func apiNeedRepro(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiNeedRepro(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.CrashID)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
if req.Corrupted {
@@ -1174,9 +1170,9 @@ func normalizeCrashTitle(title string) string {
return strings.TrimSpace(limitLength(title, maxTextLen))
}
-func apiManagerStats(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiManagerStats(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.ManagerStatsReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
now := timeNow(c)
@@ -1211,7 +1207,7 @@ func apiManagerStats(c context.Context, ns string, r *http.Request, payload []by
return nil, err
}
-func apiBugList(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiBugList(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
keys, err := db.NewQuery("Bug").
Filter("Namespace=", ns).
KeysOnly().
@@ -1226,9 +1222,9 @@ func apiBugList(c context.Context, ns string, r *http.Request, payload []byte) (
return resp, nil
}
-func apiUpdateReport(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiUpdateReport(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.UpdateReportReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
bug := new(Bug)
@@ -1256,9 +1252,9 @@ func apiUpdateReport(c context.Context, ns string, r *http.Request, payload []by
return nil, runInTransaction(c, tx, nil)
}
-func apiLoadBug(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiLoadBug(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.LoadBugReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
bug := new(Bug)
@@ -1272,9 +1268,9 @@ func apiLoadBug(c context.Context, ns string, r *http.Request, payload []byte) (
return loadBugReport(c, bug)
}
-func apiLoadFullBug(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiLoadFullBug(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.LoadFullBugReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
bug, bugKey, err := findBugByReportingID(c, req.BugID)
@@ -1302,9 +1298,9 @@ func loadBugReport(c context.Context, bug *Bug) (*dashapi.BugReport, error) {
return createBugReport(c, bug, crash, crashKey, bugReporting, reporting)
}
-func apiAddBuildAssets(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiAddBuildAssets(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.AddBuildAssetsReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
assets := []Asset{}
@@ -1347,7 +1343,7 @@ func parseIncomingAsset(c context.Context, newAsset dashapi.NewAsset, ns string)
}, nil
}
-func apiNeededAssetsList(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiNeededAssetsList(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
return queryNeededAssets(c)
}
@@ -1728,9 +1724,9 @@ func handleRefreshSubsystems(w http.ResponseWriter, r *http.Request) {
}
}
-func apiSaveDiscussion(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiSaveDiscussion(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.SaveDiscussionReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
d := req.Discussion
@@ -1771,9 +1767,9 @@ func recordEmergencyStop(c context.Context) error {
// Share crash logs for non-reproduced bugs with syz-managers.
// In future, this can also take care of repro exchange between instances
// in the place of syz-hub.
-func apiLogToReproduce(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) {
+func apiLogToReproduce(c context.Context, ns string, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.LogToReproReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
build, err := loadBuild(c, ns, req.BuildID)
@@ -1895,9 +1891,9 @@ func takeReproTask(c context.Context, ns, manager string) ([]byte, error) {
return log, err
}
-func apiSaveCoverage(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiSaveCoverage(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.SaveCoverageReq)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
coverage := req.Coverage
diff --git a/dashboard/app/reporting_external.go b/dashboard/app/reporting_external.go
index abeaedd0b..973bfc680 100644
--- a/dashboard/app/reporting_external.go
+++ b/dashboard/app/reporting_external.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"net/http"
"github.com/google/syzkaller/dashboard/dashapi"
@@ -18,12 +19,12 @@ import (
// The external system is meant to poll for new bugs with apiReportingPoll,
// and report back bug status updates with apiReportingUpdate.
-func apiReportingPollBugs(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportingPollBugs(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
if stop, err := emergentlyStopped(c); err != nil || stop {
return &dashapi.PollBugsResponse{}, err
}
req := new(dashapi.PollBugsRequest)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
reports := reportingPollBugs(c, req.Type)
@@ -38,12 +39,12 @@ func apiReportingPollBugs(c context.Context, r *http.Request, payload []byte) (i
return resp, nil
}
-func apiReportingPollNotifications(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportingPollNotifications(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
if stop, err := emergentlyStopped(c); err != nil || stop {
return &dashapi.PollNotificationsResponse{}, err
}
req := new(dashapi.PollNotificationsRequest)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
notifs := reportingPollNotifications(c, req.Type)
@@ -53,12 +54,12 @@ func apiReportingPollNotifications(c context.Context, r *http.Request, payload [
return resp, nil
}
-func apiReportingPollClosed(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportingPollClosed(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
if stop, err := emergentlyStopped(c); err != nil || stop {
return &dashapi.PollClosedResponse{}, err
}
req := new(dashapi.PollClosedRequest)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
ids, err := reportingPollClosed(c, req.IDs)
@@ -71,9 +72,9 @@ func apiReportingPollClosed(c context.Context, r *http.Request, payload []byte)
return resp, nil
}
-func apiReportingUpdate(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiReportingUpdate(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.BugUpdate)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
if req.JobID != "" {
@@ -96,9 +97,9 @@ func apiReportingUpdate(c context.Context, r *http.Request, payload []byte) (int
}, nil
}
-func apiNewTestJob(c context.Context, r *http.Request, payload []byte) (interface{}, error) {
+func apiNewTestJob(c context.Context, r *http.Request, payload io.Reader) (interface{}, error) {
req := new(dashapi.TestPatchRequest)
- if err := json.Unmarshal(payload, req); err != nil {
+ if err := json.NewDecoder(payload).Decode(req); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
resp := &dashapi.TestPatchReply{}