@@ -5,8 +5,11 @@ package libpod
55import (
66 "errors"
77 "fmt"
8+ "io/fs"
89 "net/http"
10+ "path/filepath"
911
12+ "github.com/containers/podman/v6/internal/localapi"
1013 "github.com/containers/podman/v6/libpod"
1114 "github.com/containers/podman/v6/pkg/api/handlers/utils"
1215 api "github.com/containers/podman/v6/pkg/api/types"
@@ -212,19 +215,21 @@ func BatchRemoveArtifact(w http.ResponseWriter, r *http.Request) {
212215 utils .WriteResponse (w , http .StatusOK , artifacts )
213216}
214217
218+ type artifactAddRequestQuery struct {
219+ Name string `schema:"name"`
220+ FileName string `schema:"fileName"`
221+ FileMIMEType string `schema:"fileMIMEType"`
222+ Annotations []string `schema:"annotations"`
223+ ArtifactMIMEType string `schema:"artifactMIMEType"`
224+ Append bool `schema:"append"`
225+ Replace bool `schema:"replace"`
226+ Path string `schema:"path"`
227+ }
228+
215229func AddArtifact (w http.ResponseWriter , r * http.Request ) {
216- runtime := r .Context ().Value (api .RuntimeKey ).(* libpod.Runtime )
217230 decoder := r .Context ().Value (api .DecoderKey ).(* schema.Decoder )
218231
219- query := struct {
220- Name string `schema:"name"`
221- FileName string `schema:"fileName"`
222- FileMIMEType string `schema:"fileMIMEType"`
223- Annotations []string `schema:"annotations"`
224- ArtifactMIMEType string `schema:"artifactMIMEType"`
225- Append bool `schema:"append"`
226- Replace bool `schema:"replace"`
227- }{}
232+ query := artifactAddRequestQuery {}
228233
229234 if err := decoder .Decode (& query , r .URL .Query ()); err != nil {
230235 utils .Error (w , http .StatusBadRequest , fmt .Errorf ("failed to parse parameters for %s: %w" , r .URL .String (), err ))
@@ -236,6 +241,56 @@ func AddArtifact(w http.ResponseWriter, r *http.Request) {
236241 return
237242 }
238243
244+ artifactBlobs := []entities.ArtifactBlob {{
245+ BlobReader : r .Body ,
246+ FileName : query .FileName ,
247+ }}
248+
249+ addArtifactHelper (query , artifactBlobs , w , r )
250+ }
251+
252+ func AddLocalArtifact (w http.ResponseWriter , r * http.Request ) {
253+ decoder := r .Context ().Value (api .DecoderKey ).(* schema.Decoder )
254+
255+ query := artifactAddRequestQuery {}
256+
257+ if err := decoder .Decode (& query , r .URL .Query ()); err != nil {
258+ utils .Error (w , http .StatusBadRequest , fmt .Errorf ("failed to parse parameters for %s: %w" , r .URL .String (), err ))
259+ return
260+ }
261+
262+ if query .Name == "" || query .FileName == "" {
263+ utils .Error (w , http .StatusBadRequest , errors .New ("name and file parameters are required" ))
264+ return
265+ }
266+
267+ cleanPath := filepath .Clean (query .Path )
268+ // Check if the path exists on server side.
269+ // Note: localapi.ValidatePathForLocalAPI returns nil if the file exists and path is absolute, not an error.
270+ switch err := localapi .ValidatePathForLocalAPI (cleanPath ); {
271+ case err == nil :
272+ // no error -> continue
273+ case errors .Is (err , localapi .ErrPathNotAbsolute ):
274+ utils .Error (w , http .StatusBadRequest , err )
275+ return
276+ case errors .Is (err , fs .ErrNotExist ):
277+ utils .Error (w , http .StatusNotFound , fmt .Errorf ("file does not exist: %q" , cleanPath ))
278+ return
279+ default :
280+ utils .Error (w , http .StatusInternalServerError , fmt .Errorf ("failed to access file: %w" , err ))
281+ return
282+ }
283+
284+ artifactBlobs := []entities.ArtifactBlob {{
285+ BlobFilePath : cleanPath ,
286+ FileName : query .FileName ,
287+ }}
288+
289+ addArtifactHelper (query , artifactBlobs , w , r )
290+ }
291+
292+ func addArtifactHelper (query artifactAddRequestQuery , artifactBlobs []entities.ArtifactBlob , w http.ResponseWriter , r * http.Request ) {
293+ runtime := r .Context ().Value (api .RuntimeKey ).(* libpod.Runtime )
239294 annotations , err := domain_utils .ParseAnnotations (query .Annotations )
240295 if err != nil {
241296 utils .Error (w , http .StatusBadRequest , err )
@@ -250,13 +305,7 @@ func AddArtifact(w http.ResponseWriter, r *http.Request) {
250305 Replace : query .Replace ,
251306 }
252307
253- artifactBlobs := []entities.ArtifactBlob {{
254- BlobReader : r .Body ,
255- FileName : query .FileName ,
256- }}
257-
258308 imageEngine := abi.ImageEngine {Libpod : runtime }
259-
260309 artifacts , err := imageEngine .ArtifactAdd (r .Context (), query .Name , artifactBlobs , artifactAddOptions )
261310 if err != nil {
262311 if errors .Is (err , libartifact_types .ErrArtifactNotExist ) {
0 commit comments