Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Created December 31, 2022 21:16
Show Gist options
  • Save xeoncross/7f9b3bfc55feef3410888c9381b210f9 to your computer and use it in GitHub Desktop.
Save xeoncross/7f9b3bfc55feef3410888c9381b210f9 to your computer and use it in GitHub Desktop.
Making a HTTP request in Go requires you check multiple things if you want to be safe. Below is an example of something that takes, timeouts, context deadlines, HTTP status codes, and a size limit on the response.
package safehttp
// HttpGetRequest assumes the response fits in memory and you're not trying to
// decode a json payload which would be better using json.NewDecoder()
func HttpGetRequest(ctx context.Context, url string, timeout time.Duration, sizeLimit int64) ([]byte, error) {
// Create a new HTTP client with a timeout
client := http.Client{Timeout: timeout}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
// Also respect the context deadline
req = req.WithContext(ctx)
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
// Assumes a well-behaved (trustable?) server
if res.StatusCode < 200 || res.StatusCode > 299 {
return nil, fmt.Errorf("unexpected status: got %v", res.Status)
}
// set sane defaults on expected payload size
r := http.MaxBytesReader(nil, res.Body, sizeLimit)
// Read the response body
body, err := ioutil.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
// If reading JSON, we would do this instead
// t := new(T)
// if err := json.NewDecoder(res.Body).Decode(t); err != nil {
// return nil, err
// }
// return t, nil
return body, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment