diff --git a/router/middleware.go b/router/middleware.go index 3adc7a9..e2754b9 100644 --- a/router/middleware.go +++ b/router/middleware.go @@ -1,6 +1,7 @@ package router import ( + "errors" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/pkg/errors" @@ -100,6 +101,9 @@ func (m *Middleware) RequireAuthorization() gin.HandlerFunc { } // Helper function to fetch a server out of the servers collection stored in memory. +// +// This function should not be used in new controllers, prefer ExtractServer where +// possible. func GetServer(uuid string) *server.Server { return server.GetServers().Find(func(s *server.Server) bool { return uuid == s.Id() diff --git a/router/router.go b/router/router.go index 4748315..e1a0919 100644 --- a/router/router.go +++ b/router/router.go @@ -82,6 +82,7 @@ func Configure() *gin.Engine { files.PUT("/rename", putServerRenameFiles) files.POST("/copy", postServerCopyFile) files.POST("/write", postServerWriteFile) + files.POST("/writeUrl", postServerDownloadRemoteFile) files.POST("/create-directory", postServerCreateDirectory) files.POST("/delete", postServerDeleteFiles) files.POST("/compress", postServerCompressFiles) diff --git a/router/router_server_files.go b/router/router_server_files.go index 58a0e56..1e4c1bc 100644 --- a/router/router_server_files.go +++ b/router/router_server_files.go @@ -270,6 +270,51 @@ func postServerDownloadRemoteFile(c *gin.Context) { c.Status(http.StatusNoContent) } +// Writes the contents of the remote URL to a file on a server. +func postServerDownloadRemoteFile(c *gin.Context) { + s := ExtractServer(c) + var data struct { + URL string `binding:"required" json:"url"` + BasePath string `json:"path"` + } + if err := c.BindJSON(&data); err != nil { + return + } + + u, err := url.Parse(data.URL) + if err != nil { + if e, ok := err.(*url.Error); ok { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ + "error": "An error occurred while parsing that URL: " + e.Err.Error(), + }) + return + } + TrackedServerError(err, s).AbortWithServerError(c) + return + } + + resp, err := http.Get(u.String()) + if err != nil { + TrackedServerError(err, s).AbortWithServerError(c) + return + } + defer resp.Body.Close() + + filename := strings.Split(u.Path, "/") + if err := s.Filesystem().Writefile(filepath.Join(data.BasePath, filename[len(filename)-1]), resp.Body); err != nil { + if errors.Is(err, filesystem.ErrIsDirectory) { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{ + "error": "Cannot write file, name conflicts with an existing directory by the same name.", + }) + return + } + TrackedServerError(err, s).AbortFilesystemError(c) + return + } + + c.Status(http.StatusNoContent) +} + // Create a directory on a server. func postServerCreateDirectory(c *gin.Context) { s := GetServer(c.Param("server"))