getJSON retrieves JSON and unmarshals JSON from the URL, as specified in both RFC 9728 and RFC 8414. It will not read more than limit bytes from the body.
(ctx context.Context, c *http.Client, url string, limit int64)
| 31 | // RFC 9728 and RFC 8414. |
| 32 | // It will not read more than limit bytes from the body. |
| 33 | func getJSON[T any](ctx context.Context, c *http.Client, url string, limit int64) (*T, error) { |
| 34 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) |
| 35 | if err != nil { |
| 36 | return nil, err |
| 37 | } |
| 38 | if c == nil { |
| 39 | c = http.DefaultClient |
| 40 | } |
| 41 | res, err := c.Do(req) |
| 42 | if err != nil { |
| 43 | return nil, err |
| 44 | } |
| 45 | defer res.Body.Close() |
| 46 | |
| 47 | if res.StatusCode != http.StatusOK { |
| 48 | return nil, &httpStatusError{StatusCode: res.StatusCode} |
| 49 | } |
| 50 | ct := res.Header.Get("Content-Type") |
| 51 | mediaType, _, err := mime.ParseMediaType(ct) |
| 52 | if err != nil || mediaType != "application/json" { |
| 53 | return nil, fmt.Errorf("bad content type %q", ct) |
| 54 | } |
| 55 | |
| 56 | var t T |
| 57 | dec := json.NewDecoder(io.LimitReader(res.Body, limit)) |
| 58 | if err := dec.Decode(&t); err != nil { |
| 59 | return nil, err |
| 60 | } |
| 61 | return &t, nil |
| 62 | } |
| 63 | |
| 64 | // checkURLScheme ensures that its argument is a valid URL with a scheme |
| 65 | // that prevents XSS attacks. |
nothing calls this directly
no test coverage detected
searching dependent graphs…