50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package hw3test
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// validateResponseFraming checks headers before reading the response body.
|
|
func validateResponseFraming(resp *http.Response) error {
|
|
// net/http removes Connection: close from Header and records it in Close.
|
|
// With HTTP/1.1 and explicit framing, Close reflects that header.
|
|
closeFound := resp.ProtoMajor == 1 && resp.ProtoMinor == 1 && resp.Close
|
|
for _, value := range resp.Header.Values("Connection") {
|
|
for _, token := range strings.Split(value, ",") {
|
|
closeFound = closeFound || strings.EqualFold(strings.TrimSpace(token), "close")
|
|
}
|
|
}
|
|
if !closeFound {
|
|
return fmt.Errorf("expected Connection: close")
|
|
}
|
|
if len(resp.TransferEncoding) != 0 || len(resp.Header.Values("Transfer-Encoding")) != 0 {
|
|
return fmt.Errorf("Transfer-Encoding is not supported")
|
|
}
|
|
lengths := resp.Header.Values("Content-Length")
|
|
if resp.StatusCode == http.StatusNoContent {
|
|
if len(lengths) != 0 {
|
|
return fmt.Errorf("204 must not contain Content-Length")
|
|
}
|
|
} else if len(lengths) != 1 || resp.ContentLength < 0 {
|
|
return fmt.Errorf("expected exactly one valid Content-Length")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Bound a stalled peer, without imposing a total duration on large transfers.
|
|
type idleDeadlineReader struct {
|
|
net.Conn
|
|
Timeout time.Duration
|
|
}
|
|
|
|
func (r *idleDeadlineReader) Read(p []byte) (int, error) {
|
|
if err := r.Conn.SetReadDeadline(time.Now().Add(r.Timeout)); err != nil {
|
|
return 0, err
|
|
}
|
|
return r.Conn.Read(p)
|
|
}
|