(ctx context.Context, httpClient httpDoer, uploadURL safeurl.SafeURL, asset AssetForUpload)
| 160 | } |
| 161 | |
| 162 | func uploadAsset(ctx context.Context, httpClient httpDoer, uploadURL safeurl.SafeURL, asset AssetForUpload) (*ReleaseAsset, error) { |
| 163 | u, err := url.Parse(uploadURL.String()) |
| 164 | if err != nil { |
| 165 | return nil, err |
| 166 | } |
| 167 | params := u.Query() |
| 168 | params.Set("name", asset.Name) |
| 169 | params.Set("label", asset.Label) |
| 170 | u.RawQuery = params.Encode() |
| 171 | |
| 172 | // Since u is derived from uploadURL, an already-trusted safeurl.SafeURL, the resulting URL is safe to declare as such. |
| 173 | safeURL := safeurl.NewImmutableSafeURL(u.String()) |
| 174 | |
| 175 | f, err := asset.Open() |
| 176 | if err != nil { |
| 177 | return nil, err |
| 178 | } |
| 179 | defer f.Close() |
| 180 | |
| 181 | req, err := http.NewRequestWithContext(ctx, "POST", safeURL.String(), f) |
| 182 | if err != nil { |
| 183 | return nil, err |
| 184 | } |
| 185 | req.ContentLength = asset.Size |
| 186 | req.Header.Set("Content-Type", asset.MIMEType) |
| 187 | req.GetBody = asset.Open |
| 188 | |
| 189 | resp, err := httpClient.Do(req) |
| 190 | if err != nil { |
| 191 | return nil, errNetwork{err} |
| 192 | } |
| 193 | defer resp.Body.Close() |
| 194 | |
| 195 | success := resp.StatusCode >= 200 && resp.StatusCode < 300 |
| 196 | if !success { |
| 197 | return nil, api.HandleHTTPError(resp) |
| 198 | } |
| 199 | |
| 200 | var newAsset ReleaseAsset |
| 201 | dec := json.NewDecoder(resp.Body) |
| 202 | if err := dec.Decode(&newAsset); err != nil { |
| 203 | return nil, err |
| 204 | } |
| 205 | |
| 206 | return &newAsset, nil |
| 207 | } |
| 208 | |
| 209 | func deleteAsset(ctx context.Context, httpClient httpDoer, assetURL safeurl.SafeURL) error { |
| 210 | req, err := http.NewRequestWithContext(ctx, "DELETE", assetURL.String(), nil) |
no test coverage detected