2021-05-21 05:49:02 +02:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
2021-05-28 01:19:57 +02:00
|
|
|
"sync"
|
|
|
|
"time"
|
2021-05-21 05:49:02 +02:00
|
|
|
|
2021-05-21 19:09:02 +02:00
|
|
|
"github.com/lbryio/reflector.go/internal/metrics"
|
2022-07-29 04:59:15 +02:00
|
|
|
"github.com/lbryio/reflector.go/reflector"
|
2021-07-20 02:09:14 +02:00
|
|
|
"github.com/lbryio/reflector.go/shared"
|
2021-05-21 05:49:02 +02:00
|
|
|
"github.com/lbryio/reflector.go/store"
|
2021-07-20 02:09:14 +02:00
|
|
|
|
|
|
|
"github.com/lbryio/lbry.go/v2/extras/errors"
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2021-08-05 17:47:20 +02:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-05-21 05:49:02 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func (s *Server) getBlob(c *gin.Context) {
|
2021-05-28 01:19:57 +02:00
|
|
|
waiter := &sync.WaitGroup{}
|
|
|
|
waiter.Add(1)
|
|
|
|
enqueue(&blobRequest{c: c, finished: waiter})
|
|
|
|
waiter.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) HandleGetBlob(c *gin.Context) {
|
2021-08-05 17:47:20 +02:00
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
log.Errorf("Recovered from panic: %v", r)
|
|
|
|
}
|
|
|
|
}()
|
2021-05-28 01:19:57 +02:00
|
|
|
start := time.Now()
|
2021-05-21 05:49:02 +02:00
|
|
|
hash := c.Query("hash")
|
2022-07-29 04:59:15 +02:00
|
|
|
edgeToken := c.Query("edge_token")
|
2021-07-22 20:13:05 +02:00
|
|
|
|
2022-07-29 04:59:15 +02:00
|
|
|
if reflector.IsProtected(hash) && edgeToken != s.edgeToken {
|
|
|
|
_ = c.Error(errors.Err("requested blob is protected"))
|
|
|
|
c.String(http.StatusForbidden, "requested blob is protected")
|
|
|
|
return
|
|
|
|
}
|
2021-05-28 01:19:57 +02:00
|
|
|
if s.missesCache.Has(hash) {
|
|
|
|
serialized, err := shared.NewBlobTrace(time.Since(start), "http").Serialize()
|
2021-07-22 20:13:05 +02:00
|
|
|
c.Header("Via", serialized)
|
2021-05-28 01:19:57 +02:00
|
|
|
if err != nil {
|
2021-07-22 20:13:05 +02:00
|
|
|
_ = c.Error(errors.Err(err))
|
|
|
|
c.String(http.StatusInternalServerError, err.Error())
|
2021-05-28 01:19:57 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
c.AbortWithStatus(http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
2021-05-21 05:49:02 +02:00
|
|
|
blob, trace, err := s.store.Get(hash)
|
|
|
|
if err != nil {
|
|
|
|
serialized, serializeErr := trace.Serialize()
|
|
|
|
if serializeErr != nil {
|
2021-07-22 20:13:05 +02:00
|
|
|
_ = c.Error(errors.Prefix(serializeErr.Error(), err))
|
|
|
|
c.String(http.StatusInternalServerError, errors.Prefix(serializeErr.Error(), err).Error())
|
2021-05-21 05:49:02 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Header("Via", serialized)
|
|
|
|
|
|
|
|
if errors.Is(err, store.ErrBlobNotFound) {
|
2021-05-28 01:19:57 +02:00
|
|
|
_ = s.missesCache.Set(hash, true)
|
2021-05-21 05:49:02 +02:00
|
|
|
c.AbortWithStatus(http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
2021-07-22 20:13:05 +02:00
|
|
|
_ = c.Error(err)
|
|
|
|
c.String(http.StatusInternalServerError, err.Error())
|
2021-05-21 05:49:02 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
serialized, err := trace.Serialize()
|
|
|
|
if err != nil {
|
2021-07-22 20:13:05 +02:00
|
|
|
_ = c.Error(err)
|
|
|
|
c.String(http.StatusInternalServerError, err.Error())
|
2021-05-21 05:49:02 +02:00
|
|
|
return
|
|
|
|
}
|
2021-05-21 19:09:02 +02:00
|
|
|
metrics.MtrOutBytesHttp.Add(float64(len(blob)))
|
|
|
|
metrics.BlobDownloadCount.Inc()
|
|
|
|
metrics.HttpDownloadCount.Inc()
|
2021-05-21 05:49:02 +02:00
|
|
|
c.Header("Via", serialized)
|
|
|
|
c.Header("Content-Disposition", "filename="+hash)
|
|
|
|
c.Data(http.StatusOK, "application/octet-stream", blob)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) hasBlob(c *gin.Context) {
|
|
|
|
hash := c.Query("hash")
|
|
|
|
has, err := s.store.Has(hash)
|
|
|
|
if err != nil {
|
2021-07-22 20:13:05 +02:00
|
|
|
_ = c.Error(err)
|
|
|
|
c.String(http.StatusInternalServerError, err.Error())
|
2021-05-21 05:49:02 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if has {
|
|
|
|
c.Status(http.StatusNoContent)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Status(http.StatusNotFound)
|
|
|
|
}
|
2021-06-12 00:56:57 +02:00
|
|
|
|
|
|
|
func (s *Server) recoveryHandler(c *gin.Context, err interface{}) {
|
|
|
|
c.JSON(500, gin.H{
|
|
|
|
"title": "Error",
|
|
|
|
"err": err,
|
|
|
|
})
|
|
|
|
}
|