Storage: refactor readonly support (#52127)

This commit is contained in:
Ryan McKinley
2022-07-13 10:15:25 -07:00
committed by GitHub
parent 074bcf8599
commit ab6cf9e94d
5 changed files with 129 additions and 120 deletions
+75 -73
View File
@@ -15,8 +15,6 @@ import (
"github.com/grafana/grafana/pkg/web"
)
var errFileTooBig = response.Error(400, "Please limit file uploaded under 1MB", errors.New("file is too big"))
// HTTPStorageService passes raw HTTP requests to a well typed storage service
type HTTPStorageService interface {
List(c *models.ReqContext) response.Response
@@ -57,87 +55,91 @@ func UploadErrorToStatusCode(err error) int {
}
func (s *httpStorage) Upload(c *models.ReqContext) response.Response {
// 32 MB is the default used by FormFile()
if err := c.Req.ParseMultipartForm(32 << 20); err != nil {
return response.Error(400, "error in parsing form", err)
type rspInfo struct {
Message string `json:"message,omitempty"`
Path string `json:"path,omitempty"`
Count int `json:"count,omitempty"`
Bytes int `json:"bytes,omitempty"`
Error bool `json:"err,omitempty"`
}
rsp := &rspInfo{Message: "uploaded"}
c.Req.Body = http.MaxBytesReader(c.Resp, c.Req.Body, MAX_UPLOAD_SIZE)
if err := c.Req.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
msg := fmt.Sprintf("Please limit file uploaded under %s", util.ByteCountSI(MAX_UPLOAD_SIZE))
return response.Error(400, msg, err)
rsp.Message = fmt.Sprintf("Please limit file uploaded under %s", util.ByteCountSI(MAX_UPLOAD_SIZE))
rsp.Error = true
return response.JSON(400, rsp)
}
message := getMultipartFormValue(c.Req, "message")
overwriteExistingFile := getMultipartFormValue(c.Req, "overwriteExistingFile") != "false" // must explicitly overwrite
folder := getMultipartFormValue(c.Req, "folder")
for k, fileHeaders := range c.Req.MultipartForm.File {
path := getMultipartFormValue(c.Req, k+".path") // match the path with a file
if len(fileHeaders) > 1 {
path = ""
}
if path == "" && folder == "" {
rsp.Message = "please specify the upload folder or full path"
rsp.Error = true
return response.JSON(400, rsp)
}
for _, fileHeader := range fileHeaders {
// restrict file size based on file size
// open each file to copy contents
file, err := fileHeader.Open()
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
err = file.Close()
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
data, err := ioutil.ReadAll(file)
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
if path == "" {
path = folder + "/" + fileHeader.Filename
}
entityType := EntityTypeJSON
mimeType := http.DetectContentType(data)
if strings.HasPrefix(mimeType, "image") {
entityType = EntityTypeImage
}
err = s.store.Upload(c.Req.Context(), c.SignedInUser, &UploadRequest{
Contents: data,
MimeType: mimeType,
EntityType: entityType,
Path: path,
OverwriteExistingFile: overwriteExistingFile,
Properties: map[string]string{
"message": message, // the commit/changelog entry
},
})
if err != nil {
return response.Error(UploadErrorToStatusCode(err), err.Error(), err)
}
rsp.Count++
rsp.Bytes += len(data)
rsp.Path = path
}
}
files := c.Req.MultipartForm.File["file"]
if len(files) != 1 {
return response.JSON(400, map[string]interface{}{
"message": "please upload files one at a time",
"err": true,
})
}
folder, ok := getMultipartFormValue(c.Req, "folder")
if !ok || folder == "" {
return response.JSON(400, map[string]interface{}{
"message": "please specify the upload folder",
"err": true,
})
}
overwriteExistingFile, _ := getMultipartFormValue(c.Req, "overwriteExistingFile")
fileHeader := files[0]
if fileHeader.Size > MAX_UPLOAD_SIZE {
return errFileTooBig
}
// restrict file size based on file size
// open each file to copy contents
file, err := fileHeader.Open()
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
err = file.Close()
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
data, err := ioutil.ReadAll(file)
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
if (len(data)) > MAX_UPLOAD_SIZE {
return errFileTooBig
}
path := folder + "/" + fileHeader.Filename
mimeType := http.DetectContentType(data)
err = s.store.Upload(c.Req.Context(), c.SignedInUser, &UploadRequest{
Contents: data,
MimeType: mimeType,
EntityType: EntityTypeImage,
Path: path,
OverwriteExistingFile: overwriteExistingFile == "true",
})
if err != nil {
return response.Error(UploadErrorToStatusCode(err), err.Error(), err)
}
return response.JSON(200, map[string]interface{}{
"message": "Uploaded successfully",
"path": path,
"file": fileHeader.Filename,
"err": true,
})
return response.JSON(200, rsp)
}
func getMultipartFormValue(req *http.Request, key string) (string, bool) {
func getMultipartFormValue(req *http.Request, key string) string {
v, ok := req.MultipartForm.Value[key]
if !ok || len(v) != 1 {
return "", false
return ""
}
return v[0], ok
return v[0]
}
func (s *httpStorage) Read(c *models.ReqContext) response.Response {