diff --git a/pkg/geocode/geocode.go b/pkg/geocode/geocode.go index 152545668..cca7a347f 100644 --- a/pkg/geocode/geocode.go +++ b/pkg/geocode/geocode.go @@ -25,7 +25,6 @@ import ( "sync" "camlistore.org/pkg/context" - "camlistore.org/pkg/httputil" "camlistore.org/pkg/singleflight" ) @@ -63,7 +62,7 @@ func Lookup(ctx *context.Context, address string) ([]Rect, error) { if err != nil { return nil, err } - defer httputil.CloseBody(res.Body) + defer res.Body.Close() rects, err := decodeGoogleResponse(res.Body) log.Printf("Google geocode lookup (%q) = %#v, %v", address, rects, err) if err == nil { diff --git a/pkg/googlestorage/googlestorage.go b/pkg/googlestorage/googlestorage.go index c629755d1..c4b162013 100644 --- a/pkg/googlestorage/googlestorage.go +++ b/pkg/googlestorage/googlestorage.go @@ -34,7 +34,6 @@ import ( "unicode/utf8" "camlistore.org/pkg/blob" - "camlistore.org/pkg/httputil" "golang.org/x/net/context" "golang.org/x/oauth2" @@ -308,7 +307,7 @@ func (gsa *Client) EnumerateObjects(bucket, after string, limit int) ([]SizedObj var xres struct { Contents []SizedObject } - defer httputil.CloseBody(resp.Body) + defer resp.Body.Close() if err = xml.NewDecoder(resp.Body).Decode(&xres); err != nil { return nil, err } diff --git a/pkg/httputil/httputil.go b/pkg/httputil/httputil.go index 6702d13fd..48712d897 100644 --- a/pkg/httputil/httputil.go +++ b/pkg/httputil/httputil.go @@ -294,7 +294,7 @@ func putBuf(b *bytes.Buffer) { // res.Body. // It defensively caps the JSON at 8 MB for now. func DecodeJSON(res *http.Response, dest interface{}) error { - defer CloseBody(res.Body) + defer res.Body.Close() buf := getBuf() defer putBuf(buf) if err := json.NewDecoder(io.TeeReader(io.LimitReader(res.Body, 8<<20), buf)).Decode(dest); err != nil { @@ -303,35 +303,6 @@ func DecodeJSON(res *http.Response, dest interface{}) error { return nil } -// CloseBody should be used to close an http.Response.Body. -// -// It does a final little Read to maybe see EOF (to trigger connection -// re-use) before calling Close. -func CloseBody(rc io.ReadCloser) { - // Go 1.2 pseudo-bug: the NewDecoder(res.Body).Decode never - // sees an EOF, so we have to do this 0-byte copy here to - // force the http Transport to see its own EOF and recycle the - // connection. In Go 1.1 at least, the Close would cause it to - // read to EOF and recycle the connection, but in Go 1.2, a - // Close before EOF kills the underlying TCP connection. - // - // Will hopefully be fixed in Go 1.3, at least for bodies with - // Content-Length. Or maybe Go 1.3's Close itself would look - // to see if we're at EOF even if it hasn't been Read. - - // TODO: use a bytepool package somewhere for this byte? - // Justification for 3 byte reads: two for up to "\r\n" after - // a JSON/XML document, and then 1 to see EOF if we haven't yet. - buf := make([]byte, 1) - for i := 0; i < 3; i++ { - _, err := rc.Read(buf) - if err != nil { - break - } - } - rc.Close() -} - func IsWebsocketUpgrade(req *http.Request) bool { return req.Method == "GET" && req.Header.Get("Upgrade") == "websocket" } diff --git a/pkg/httputil/httputil_test.go b/pkg/httputil/httputil_test.go deleted file mode 100644 index da865c372..000000000 --- a/pkg/httputil/httputil_test.go +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2014 The Camlistore Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package httputil - -import ( - "io" - "net/http" - "net/http/httptest" - "strconv" - "testing" -) - -func TestCloseBody(t *testing.T) { - const msg = "{\"foo\":\"bar\"}\r\n" - addrSeen := make(map[string]int) - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - addrSeen[r.RemoteAddr]++ - w.Header().Set("Content-Length", strconv.Itoa(len(msg))) - w.WriteHeader(200) - w.Write([]byte(msg)) - })) - defer ts.Close() - - buf := make([]byte, len(msg)) - - for _, trim := range []int{0, 2} { - for i := 0; i < 3; i++ { - res, err := http.Get(ts.URL) - if err != nil { - t.Errorf("Get: %v", err) - continue - } - want := len(buf) - trim - n, err := res.Body.Read(buf[:want]) - CloseBody(res.Body) - if n != want { - t.Errorf("Read = %v; want %v", n, want) - } - if err != nil && err != io.EOF { - t.Errorf("Read = %v", err) - } - } - } - if len(addrSeen) != 1 { - t.Errorf("server saw %d distinct client addresses; want 1", len(addrSeen)) - } -} diff --git a/pkg/importer/feed/feed.go b/pkg/importer/feed/feed.go index fc337d610..e48dcb5f5 100644 --- a/pkg/importer/feed/feed.go +++ b/pkg/importer/feed/feed.go @@ -200,7 +200,7 @@ func doGet(ctx *context.Context, url string) ([]byte, error) { log.Printf("Error fetching %s: %v", url, err) return nil, err } - defer httputil.CloseBody(res.Body) + defer res.Body.Close() if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("Get request on %s failed with: %s", url, res.Status) } diff --git a/pkg/misc/amazon/s3/client.go b/pkg/misc/amazon/s3/client.go index a7b44e95a..20cdc701d 100644 --- a/pkg/misc/amazon/s3/client.go +++ b/pkg/misc/amazon/s3/client.go @@ -37,7 +37,6 @@ import ( "time" "camlistore.org/pkg/blob" - "camlistore.org/pkg/httputil" ) const maxList = 1000 @@ -88,7 +87,7 @@ func (c *Client) Buckets() ([]*Bucket, error) { if err != nil { return nil, err } - defer httputil.CloseBody(res.Body) + defer res.Body.Close() if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("s3: Unexpected status code %d fetching bucket list", res.StatusCode) } @@ -145,7 +144,7 @@ func (c *Client) PutObject(key, bucket string, md5 hash.Hash, size int64, body i res, err := c.transport().RoundTrip(req) if res != nil && res.Body != nil { - defer httputil.CloseBody(res.Body) + defer res.Body.Close() } if err != nil { return err @@ -251,7 +250,7 @@ func (c *Client) ListBucket(bucket string, startAt string, maxKeys int) (items [ log.Print(err) } } - httputil.CloseBody(res.Body) + res.Body.Close() if err != nil { if try < maxTries-1 { continue