github.com/rigado/snapd@v2.42.5-go-mod+incompatible/daemon/api_download.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package daemon 21 22 import ( 23 "context" 24 "encoding/json" 25 "net/http" 26 27 "github.com/snapcore/snapd/overlord/auth" 28 "github.com/snapcore/snapd/store" 29 ) 30 31 var snapDownloadCmd = &Command{ 32 Path: "/v2/download", 33 PolkitOK: "io.snapcraft.snapd.manage", 34 POST: postSnapDownload, 35 } 36 37 // SnapDownloadAction is used to request a snap download 38 type snapDownloadAction struct { 39 Action string `json:"action"` 40 Snaps []string `json:"snaps,omitempty"` 41 } 42 43 func postSnapDownload(c *Command, r *http.Request, user *auth.UserState) Response { 44 var action snapDownloadAction 45 decoder := json.NewDecoder(r.Body) 46 if err := decoder.Decode(&action); err != nil { 47 return BadRequest("cannot decode request body into download operation: %v", err) 48 } 49 if decoder.More() { 50 return BadRequest("extra content found after download operation") 51 } 52 53 if len(action.Snaps) == 0 { 54 return BadRequest("download operation requires one snap name") 55 } 56 57 if len(action.Snaps) != 1 { 58 return BadRequest("download operation supports only one snap") 59 } 60 61 if action.Action == "" { 62 return BadRequest("download operation requires action") 63 } 64 65 switch action.Action { 66 case "download": 67 snapName := action.Snaps[0] 68 return streamOneSnap(c, user, snapName) 69 default: 70 return BadRequest("unknown download operation %q", action.Action) 71 } 72 } 73 74 func streamOneSnap(c *Command, user *auth.UserState, snapName string) Response { 75 info, err := getStore(c).SnapInfo(context.TODO(), store.SnapSpec{Name: snapName}, user) 76 if err != nil { 77 return SnapNotFound(snapName, err) 78 } 79 80 downloadInfo := info.DownloadInfo 81 r, err := getStore(c).DownloadStream(context.TODO(), snapName, &downloadInfo, user) 82 if err != nil { 83 return InternalError(err.Error()) 84 } 85 86 return fileStream{ 87 SnapName: snapName, 88 Info: downloadInfo, 89 stream: r, 90 } 91 }