Fix transport package

Transport refactoring introduced a bug where HTTP(S) response body is closed before it's fully read (depending on whenever gzip is used or not), this change fixes it and makes the code easier to follow by removing duplicated code and enforcing all transport packages to implement ReaderCloser interface.
This commit is contained in:
Łukasz Mierzwa
2017-04-17 12:52:27 -07:00
parent 72651bb53d
commit c2c5abd1de
3 changed files with 30 additions and 29 deletions

View File

@@ -1,6 +1,7 @@
package transport
import (
"io"
"os"
log "github.com/Sirupsen/logrus"
@@ -8,9 +9,20 @@ import (
type fileReader struct {
filename string
fd *os.File
}
func newFileReader(filname string) (*os.File, error) {
log.Infof("Reading file '%s'", filname)
return os.Open(filname)
func (fr *fileReader) Read(b []byte) (n int, err error) {
return fr.fd.Read(b)
}
func (fr *fileReader) Close() error {
return fr.fd.Close()
}
func newFileReader(filname string) (io.ReadCloser, error) {
log.Infof("Reading file '%s'", filname)
fd, err := os.Open(filname)
fr := fileReader{filename: filname, fd: fd}
return &fr, err
}

View File

@@ -15,7 +15,7 @@ type httpReader struct {
Timeout time.Duration
}
func newHTTPReader(url string, timeout time.Duration) (*io.ReadCloser, error) {
func newHTTPReader(url string, timeout time.Duration) (io.ReadCloser, error) {
hr := httpReader{URL: url, Timeout: timeout}
log.Infof("GET %s timeout=%s", hr.URL, hr.Timeout)
@@ -38,8 +38,6 @@ func newHTTPReader(url string, timeout time.Duration) (*io.ReadCloser, error) {
return nil, fmt.Errorf("Request to Alertmanager failed with %s", resp.Status)
}
defer resp.Body.Close()
var reader io.ReadCloser
switch resp.Header.Get("Content-Encoding") {
case "gzip":
@@ -47,9 +45,8 @@ func newHTTPReader(url string, timeout time.Duration) (*io.ReadCloser, error) {
if err != nil {
return nil, fmt.Errorf("Failed to decode gzipped content: %s", err.Error())
}
defer reader.Close()
default:
reader = resp.Body
}
return &reader, nil
return reader, nil
}

View File

@@ -3,37 +3,29 @@ package transport
import (
"encoding/json"
"fmt"
"io"
"net/url"
"time"
)
func readFile(filename string, target interface{}) error {
reader, err := newFileReader(filename)
if err != nil {
return err
}
return json.NewDecoder(reader).Decode(target)
}
func readHTTP(url string, timeout time.Duration, target interface{}) error {
reader, err := newHTTPReader(url, timeout)
if err != nil {
return err
}
return json.NewDecoder(*reader).Decode(target)
}
// ReadJSON using one of supported transports (file:// http://)
func ReadJSON(uri string, timeout time.Duration, target interface{}) error {
u, err := url.Parse(uri)
if err != nil {
return err
}
if u.Scheme == "file" {
return readFile(u.Path, target)
var reader io.ReadCloser
switch u.Scheme {
case "http", "https":
reader, err = newHTTPReader(u.String(), timeout)
case "file":
reader, err = newFileReader(u.Path)
default:
return fmt.Errorf("Unsupported URI scheme '%s' in '%s'", u.Scheme, u)
}
if u.Scheme == "http" || u.Scheme == "https" {
return readHTTP(u.String(), timeout, target)
if err != nil {
return err
}
return fmt.Errorf("Unsupported URI scheme '%s' in '%s'", u.Scheme, u)
defer reader.Close()
return json.NewDecoder(reader).Decode(target)
}