postAsset does the request and reads the asset URL back. It takes the file rather than the UserAsset, because nothing about sending the bytes depends on how they render. It is separate so every way it can fail picks up the same explanation on the way out.
(ctx context.Context, a asset)
| 125 | // how they render. It is separate so every way it can fail picks up the same |
| 126 | // explanation on the way out. |
| 127 | func (u *Uploader) postAsset(ctx context.Context, a asset) (string, error) { |
| 128 | url, err := safeurl.JoinPathWithHostPrefix(ghinstance.UserAssetUploadPrefix(u.host), "user-attachments", "assets") |
| 129 | if err != nil { |
| 130 | return "", err |
| 131 | } |
| 132 | url.SetQuery("name", filepath.Base(a.path)) |
| 133 | url.SetQuery("content_type", a.contentType) |
| 134 | url.SetQuery("repository_id", strconv.FormatInt(u.targetRepository, 10)) |
| 135 | |
| 136 | open := func() (io.ReadCloser, error) { return openFile(a.path) } |
| 137 | |
| 138 | f, err := open() |
| 139 | if err != nil { |
| 140 | return "", err |
| 141 | } |
| 142 | defer f.Close() |
| 143 | |
| 144 | req, err := http.NewRequestWithContext(ctx, "POST", url.String(), f) |
| 145 | if err != nil { |
| 146 | return "", err |
| 147 | } |
| 148 | req.ContentLength = a.info.Size() |
| 149 | req.Header.Set("Content-Type", "application/octet-stream") |
| 150 | req.Header.Set("Accept", "application/vnd.github+json") |
| 151 | // Without GetBody a redirect re-reads an exhausted reader. |
| 152 | req.GetBody = open |
| 153 | |
| 154 | resp, err := u.httpClient.Do(req) |
| 155 | if err != nil { |
| 156 | return "", err |
| 157 | } |
| 158 | defer resp.Body.Close() |
| 159 | |
| 160 | if resp.StatusCode < 200 || resp.StatusCode > 299 { |
| 161 | return "", api.HandleHTTPError(resp) |
| 162 | } |
| 163 | |
| 164 | var asset struct { |
| 165 | URL string `json:"url"` |
| 166 | } |
| 167 | if err := json.NewDecoder(resp.Body).Decode(&asset); err != nil { |
| 168 | return "", err |
| 169 | } |
| 170 | if asset.URL == "" { |
| 171 | return "", errors.New("the server returned no asset URL") |
| 172 | } |
| 173 | |
| 174 | return asset.URL, nil |
| 175 | } |
| 176 | |
| 177 | // newUploadError captures the status code so the message can name what the |
| 178 | // endpoint refused. |
no test coverage detected