(ctx context.Context, httpClient *http.Client, uploadURL safeurl.SafeURL, asset AssetForUpload)
| 156 | } |
| 157 | |
| 158 | func uploadAsset(ctx context.Context, httpClient *http.Client, uploadURL safeurl.SafeURL, asset AssetForUpload) (*ReleaseAsset, error) { |
| 159 | u, err := url.Parse(uploadURL.String()) |
| 160 | if err != nil { |
| 161 | return nil, err |
| 162 | } |
| 163 | params := u.Query() |
| 164 | params.Set("name", asset.Name) |
| 165 | params.Set("label", asset.Label) |
| 166 | u.RawQuery = params.Encode() |
| 167 | |
| 168 | // Since u is derived from uploadURL, an already-trusted safeurl.SafeURL, the resulting URL is safe to declare as such. |
| 169 | safeURL := safeurl.NewImmutableSafeURL(u.String()) |
| 170 | |
| 171 | f, err := asset.Open() |
| 172 | if err != nil { |
| 173 | return nil, err |
| 174 | } |
| 175 | defer f.Close() |
| 176 | |
| 177 | req, err := http.NewRequestWithContext(ctx, "POST", safeURL.String(), f) |
| 178 | if err != nil { |
| 179 | return nil, err |
| 180 | } |
| 181 | req.ContentLength = asset.Size |
| 182 | req.Header.Set("Content-Type", asset.MIMEType) |
| 183 | req.GetBody = asset.Open |
| 184 | |
| 185 | // DoRequest rather than Request because ContentLength and GetBody are set on the request |
| 186 | // itself, and neither can be expressed as a header. The upload URL is supplied by the API |
| 187 | // and points at the uploads host, so there is no endpoint resolution to delegate here. |
| 188 | // TODO(api-client-rollout) |
| 189 | // This line of code is part of a mechanical roll out of the api client. |
| 190 | // As a follow up, consider whether the api client can be injected to this call site, rather than constructed |
| 191 | resp, err := api.NewClientFromHTTP(httpClient).DoRequest(req) |
| 192 | if err != nil { |
| 193 | // Only transport failures are retryable as network errors. A response that arrived and |
| 194 | // carried a failing status is reported as is, so shouldRetry can judge it by status. |
| 195 | if _, ok := errors.AsType[api.HTTPError](err); ok { |
| 196 | return nil, err |
| 197 | } |
| 198 | return nil, errNetwork{err} |
| 199 | } |
| 200 | defer resp.Body.Close() |
| 201 | |
| 202 | var newAsset ReleaseAsset |
| 203 | dec := json.NewDecoder(resp.Body) |
| 204 | if err := dec.Decode(&newAsset); err != nil { |
| 205 | return nil, err |
| 206 | } |
| 207 | |
| 208 | return &newAsset, nil |
| 209 | } |
| 210 | |
| 211 | func deleteAsset(ctx context.Context, httpClient *http.Client, hostname string, assetURL safeurl.SafeURL) error { |
| 212 | // The asset URL is supplied by the API, so it is absolute and requested as given. |
no test coverage detected