this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Provide helpful error messages and status codes for BGS endpoints (#355)

authored by

Jaz and committed by
GitHub
6acd4e53 11b4a36a

+54 -29
+34 -24
bgs/handlers.go
··· 12 12 13 13 atproto "github.com/bluesky-social/indigo/api/atproto" 14 14 comatprototypes "github.com/bluesky-social/indigo/api/atproto" 15 + "github.com/bluesky-social/indigo/blobs" 16 + "github.com/bluesky-social/indigo/mst" 15 17 "gorm.io/gorm" 16 18 17 19 "github.com/bluesky-social/indigo/util" ··· 26 28 if errors.Is(err, gorm.ErrRecordNotFound) { 27 29 return nil, echo.NewHTTPError(http.StatusNotFound, "user not found") 28 30 } 31 + log.Errorw("failed to lookup user", "err", err, "did", did) 29 32 return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to lookup user") 30 33 } 31 34 ··· 41 44 if commit != "" { 42 45 reqCid, err = cid.Decode(commit) 43 46 if err != nil { 44 - return nil, fmt.Errorf("failed to decode commit cid: %w", err) 47 + log.Errorw("failed to decode commit cid", "err", err, "cid", commit) 48 + return nil, echo.NewHTTPError(http.StatusBadRequest, "failed to decode commit cid") 45 49 } 46 50 } 47 51 48 52 _, record, err := s.repoman.GetRecord(ctx, u.ID, collection, rkey, reqCid) 49 53 if err != nil { 50 - return nil, fmt.Errorf("failed to get record: %w", err) 54 + if errors.Is(err, mst.ErrNotFound) { 55 + return nil, echo.NewHTTPError(http.StatusNotFound, "record not found in repo") 56 + } 57 + log.Errorw("failed to get record from repo", "err", err, "did", did, "collection", collection, "rkey", rkey) 58 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to get record from repo") 51 59 } 52 60 53 61 buf := new(bytes.Buffer) 54 62 err = record.MarshalCBOR(buf) 55 63 if err != nil { 56 - return nil, fmt.Errorf("failed to marshal record: %w", err) 64 + log.Errorw("failed to marshal record to CBOR", "err", err, "did", did, "collection", collection, "rkey", rkey) 65 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to marshal record to CBOR") 57 66 } 58 67 59 68 return buf, nil ··· 65 74 if errors.Is(err, gorm.ErrRecordNotFound) { 66 75 return nil, echo.NewHTTPError(http.StatusNotFound, "user not found") 67 76 } 77 + log.Errorw("failed to lookup user", "err", err, "did", did) 68 78 return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to lookup user") 69 79 } 70 80 ··· 79 89 // TODO: stream the response 80 90 buf := new(bytes.Buffer) 81 91 if err := s.repoman.ReadRepo(ctx, u.ID, since, buf); err != nil { 82 - return nil, fmt.Errorf("failed to read repo: %w", err) 92 + log.Errorw("failed to read repo into buffer", "err", err, "did", did) 93 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to read repo into buffer") 83 94 } 84 95 85 96 return buf, nil ··· 92 103 func (s *BGS) handleComAtprotoSyncRequestCrawl(ctx context.Context, body *comatprototypes.SyncRequestCrawl_Input) error { 93 104 host := body.Hostname 94 105 if host == "" { 95 - return fmt.Errorf("must pass valid hostname") 106 + return echo.NewHTTPError(http.StatusBadRequest, "must pass hostname") 96 107 } 97 108 98 109 if strings.HasPrefix(host, "https://") || strings.HasPrefix(host, "http://") { 99 - return &echo.HTTPError{ 100 - Code: 400, 101 - Message: "must pass domain without protocol scheme", 102 - } 110 + return echo.NewHTTPError(http.StatusBadRequest, "must pass domain without protocol scheme") 103 111 } 104 112 105 113 norm, err := util.NormalizeHostname(host) 106 114 if err != nil { 107 - return err 115 + return echo.NewHTTPError(http.StatusBadRequest, "failed to normalize hostname") 108 116 } 109 117 110 118 banned, err := s.domainIsBanned(ctx, host) 111 119 if banned { 112 - return &echo.HTTPError{ 113 - Code: 401, 114 - Message: "domain is banned", 115 - } 120 + return echo.NewHTTPError(http.StatusUnauthorized, "domain is banned") 116 121 } 117 122 118 123 log.Warnf("TODO: better host validation for crawl requests") ··· 128 133 129 134 desc, err := atproto.ServerDescribeServer(ctx, c) 130 135 if err != nil { 131 - return &echo.HTTPError{ 132 - Code: 401, 133 - Message: fmt.Sprintf("given host failed to respond to ping: %s", err), 134 - } 136 + return echo.NewHTTPError(http.StatusBadRequest, "requested host failed to respond to describe request") 135 137 } 136 138 137 139 // Maybe we could do something with this response later ··· 152 154 153 155 b, err := s.blobs.GetBlob(ctx, cid, did) 154 156 if err != nil { 155 - return nil, err 157 + if errors.Is(err, blobs.NotFoundErr) { 158 + return nil, echo.NewHTTPError(http.StatusNotFound, "blob not found") 159 + } 160 + log.Errorw("failed to get blob", "err", err, "cid", cid, "did", did) 161 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to get blob") 156 162 } 157 163 158 164 return bytes.NewReader(b), nil ··· 169 175 if cursor != "" { 170 176 c, err = strconv.ParseInt(cursor, 10, 64) 171 177 if err != nil { 172 - return nil, fmt.Errorf("invalid cursor: %w", err) 178 + return nil, echo.NewHTTPError(http.StatusBadRequest, "couldn't parse your cursor as an integer") 173 179 } 174 180 } 175 181 ··· 178 184 if err == gorm.ErrRecordNotFound { 179 185 return &comatprototypes.SyncListRepos_Output{}, nil 180 186 } 181 - return nil, fmt.Errorf("failed to get users: %w", err) 187 + log.Errorw("failed to query users", "err", err) 188 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to query users") 182 189 } 183 190 184 191 if len(users) == 0 { ··· 194 201 195 202 root, err := s.repoman.GetRepoRoot(ctx, user.ID) 196 203 if err != nil { 197 - return nil, fmt.Errorf("failed to get repo root for (%s): %w", user.Did, err) 204 + log.Errorw("failed to get repo root", "err", err, "did", user.Did) 205 + return nil, echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get repo root for (%s): %v", user.Did, err.Error())) 198 206 } 199 207 200 208 resp.Repos = append(resp.Repos, &comatprototypes.SyncListRepos_Repo{ ··· 229 237 230 238 root, err := s.repoman.GetRepoRoot(ctx, u.ID) 231 239 if err != nil { 232 - return nil, fmt.Errorf("failed to get repo root: %w", err) 240 + log.Errorw("failed to get repo root", "err", err, "did", u.Did) 241 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to get repo root") 233 242 } 234 243 235 244 rev, err := s.repoman.GetRepoRev(ctx, u.ID) 236 245 if err != nil { 237 - return nil, fmt.Errorf("failed to get repo rev: %w", err) 246 + log.Errorw("failed to get repo rev", "err", err, "did", u.Did) 247 + return nil, echo.NewHTTPError(http.StatusInternalServerError, "failed to get repo rev") 238 248 } 239 249 240 250 return &comatprototypes.SyncGetLatestCommit_Output{
+11
blobs/blobs.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "fmt" 5 6 "os" 6 7 "path/filepath" 7 8 ) 9 + 10 + var NotFoundErr = fmt.Errorf("blob not found") 8 11 9 12 type BlobStore interface { 10 13 PutBlob(ctx context.Context, cid string, did string, blob []byte) error ··· 25 28 } 26 29 27 30 func (dbs *DiskBlobStore) GetBlob(ctx context.Context, cid string, did string) ([]byte, error) { 31 + // Check if the blob exists 32 + _, err := os.Stat(filepath.Join(dbs.Dir, did, cid)) 33 + if err != nil { 34 + if os.IsNotExist(err) { 35 + return nil, NotFoundErr 36 + } 37 + return nil, err 38 + } 28 39 return os.ReadFile(filepath.Join(dbs.Dir, did, cid)) 29 40 }
+9 -5
testing/integ_test.go
··· 380 380 t.Fatal("domain should be banned") 381 381 } 382 382 383 - if err := atproto.SyncRequestCrawl(context.TODO(), c, &atproto.SyncRequestCrawl_Input{Hostname: "app.pds.foo.com"}); err == nil { 383 + err := atproto.SyncRequestCrawl(context.TODO(), c, &atproto.SyncRequestCrawl_Input{Hostname: "app.pds.foo.com"}) 384 + if err == nil { 384 385 t.Fatal("domain should be banned") 386 + } 387 + 388 + if !strings.Contains(err.Error(), "XRPC ERROR 401") { 389 + t.Fatal("should have failed with a 401") 385 390 } 386 391 387 392 // should not be banned 388 - err := atproto.SyncRequestCrawl(context.TODO(), c, &atproto.SyncRequestCrawl_Input{Hostname: "foo.bar.com"}) 393 + err = atproto.SyncRequestCrawl(context.TODO(), c, &atproto.SyncRequestCrawl_Input{Hostname: "foo.bar.com"}) 389 394 if err == nil { 390 395 t.Fatal("should still fail") 391 396 } 392 397 393 - if !strings.Contains(err.Error(), "XRPC ERROR 401") { 394 - t.Fatal("should have failed with a 401") 398 + if !strings.Contains(err.Error(), "XRPC ERROR 400") { 399 + t.Fatal("should have failed with a 400") 395 400 } 396 - 397 401 }