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