mirror of
https://github.com/golang/go.git
synced 2025-05-20 23:03:26 +00:00
net/http: use ASCII space trimming throughout
Security hardening against HTTP request smuggling. Thank you to ZeddYu for reporting this issue. Change-Id: I98bd9f8ffe58360fc3bca9dc5d9a106773e55373 Reviewed-on: https://go-review.googlesource.com/c/go/+/231419 Reviewed-by: Katie Hockman <katie@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
d5734d4f2d
commit
21898524f6
@ -21,6 +21,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -276,8 +277,8 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
header, val := parts[0], parts[1]
|
header, val := parts[0], parts[1]
|
||||||
header = strings.TrimSpace(header)
|
header = textproto.TrimString(header)
|
||||||
val = strings.TrimSpace(val)
|
val = textproto.TrimString(val)
|
||||||
switch {
|
switch {
|
||||||
case header == "Status":
|
case header == "Status":
|
||||||
if len(val) < 3 {
|
if len(val) < 3 {
|
||||||
|
@ -7,6 +7,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -60,11 +61,11 @@ func readSetCookies(h Header) []*Cookie {
|
|||||||
}
|
}
|
||||||
cookies := make([]*Cookie, 0, cookieCount)
|
cookies := make([]*Cookie, 0, cookieCount)
|
||||||
for _, line := range h["Set-Cookie"] {
|
for _, line := range h["Set-Cookie"] {
|
||||||
parts := strings.Split(strings.TrimSpace(line), ";")
|
parts := strings.Split(textproto.TrimString(line), ";")
|
||||||
if len(parts) == 1 && parts[0] == "" {
|
if len(parts) == 1 && parts[0] == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parts[0] = strings.TrimSpace(parts[0])
|
parts[0] = textproto.TrimString(parts[0])
|
||||||
j := strings.Index(parts[0], "=")
|
j := strings.Index(parts[0], "=")
|
||||||
if j < 0 {
|
if j < 0 {
|
||||||
continue
|
continue
|
||||||
@ -83,7 +84,7 @@ func readSetCookies(h Header) []*Cookie {
|
|||||||
Raw: line,
|
Raw: line,
|
||||||
}
|
}
|
||||||
for i := 1; i < len(parts); i++ {
|
for i := 1; i < len(parts); i++ {
|
||||||
parts[i] = strings.TrimSpace(parts[i])
|
parts[i] = textproto.TrimString(parts[i])
|
||||||
if len(parts[i]) == 0 {
|
if len(parts[i]) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -242,7 +243,7 @@ func readCookies(h Header, filter string) []*Cookie {
|
|||||||
|
|
||||||
cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
|
cookies := make([]*Cookie, 0, len(lines)+strings.Count(lines[0], ";"))
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
line = strings.TrimSpace(line)
|
line = textproto.TrimString(line)
|
||||||
|
|
||||||
var part string
|
var part string
|
||||||
for len(line) > 0 { // continue since we have rest
|
for len(line) > 0 { // continue since we have rest
|
||||||
@ -251,7 +252,7 @@ func readCookies(h Header, filter string) []*Cookie {
|
|||||||
} else {
|
} else {
|
||||||
part, line = line, ""
|
part, line = line, ""
|
||||||
}
|
}
|
||||||
part = strings.TrimSpace(part)
|
part = textproto.TrimString(part)
|
||||||
if len(part) == 0 {
|
if len(part) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -756,7 +756,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
|
|||||||
var ranges []httpRange
|
var ranges []httpRange
|
||||||
noOverlap := false
|
noOverlap := false
|
||||||
for _, ra := range strings.Split(s[len(b):], ",") {
|
for _, ra := range strings.Split(s[len(b):], ",") {
|
||||||
ra = strings.TrimSpace(ra)
|
ra = textproto.TrimString(ra)
|
||||||
if ra == "" {
|
if ra == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -764,7 +764,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
|
|||||||
if i < 0 {
|
if i < 0 {
|
||||||
return nil, errors.New("invalid range")
|
return nil, errors.New("invalid range")
|
||||||
}
|
}
|
||||||
start, end := strings.TrimSpace(ra[:i]), strings.TrimSpace(ra[i+1:])
|
start, end := textproto.TrimString(ra[:i]), textproto.TrimString(ra[i+1:])
|
||||||
var r httpRange
|
var r httpRange
|
||||||
if start == "" {
|
if start == "" {
|
||||||
// If no start is specified, end specifies the
|
// If no start is specified, end specifies the
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -221,7 +222,7 @@ func (rw *ResponseRecorder) Result() *http.Response {
|
|||||||
// This a modified version of same function found in net/http/transfer.go. This
|
// This a modified version of same function found in net/http/transfer.go. This
|
||||||
// one just ignores an invalid header.
|
// one just ignores an invalid header.
|
||||||
func parseContentLength(cl string) int64 {
|
func parseContentLength(cl string) int64 {
|
||||||
cl = strings.TrimSpace(cl)
|
cl = textproto.TrimString(cl)
|
||||||
if cl == "" {
|
if cl == "" {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -387,7 +388,7 @@ func shouldPanicOnCopyError(req *http.Request) bool {
|
|||||||
func removeConnectionHeaders(h http.Header) {
|
func removeConnectionHeaders(h http.Header) {
|
||||||
for _, f := range h["Connection"] {
|
for _, f := range h["Connection"] {
|
||||||
for _, sf := range strings.Split(f, ",") {
|
for _, sf := range strings.Split(f, ",") {
|
||||||
if sf = strings.TrimSpace(sf); sf != "" {
|
if sf = textproto.TrimString(sf); sf != "" {
|
||||||
h.Del(sf)
|
h.Del(sf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,9 +660,9 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
|
|||||||
// Content-Length headers if they differ in value.
|
// Content-Length headers if they differ in value.
|
||||||
// If there are dups of the value, remove the dups.
|
// If there are dups of the value, remove the dups.
|
||||||
// See Issue 16490.
|
// See Issue 16490.
|
||||||
first := strings.TrimSpace(contentLens[0])
|
first := textproto.TrimString(contentLens[0])
|
||||||
for _, ct := range contentLens[1:] {
|
for _, ct := range contentLens[1:] {
|
||||||
if first != strings.TrimSpace(ct) {
|
if first != textproto.TrimString(ct) {
|
||||||
return 0, fmt.Errorf("http: message cannot contain multiple Content-Length headers; got %q", contentLens)
|
return 0, fmt.Errorf("http: message cannot contain multiple Content-Length headers; got %q", contentLens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,7 +701,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
|
|||||||
// Logic based on Content-Length
|
// Logic based on Content-Length
|
||||||
var cl string
|
var cl string
|
||||||
if len(contentLens) == 1 {
|
if len(contentLens) == 1 {
|
||||||
cl = strings.TrimSpace(contentLens[0])
|
cl = textproto.TrimString(contentLens[0])
|
||||||
}
|
}
|
||||||
if cl != "" {
|
if cl != "" {
|
||||||
n, err := parseContentLength(cl)
|
n, err := parseContentLength(cl)
|
||||||
@ -1032,7 +1032,7 @@ func (bl bodyLocked) Read(p []byte) (n int, err error) {
|
|||||||
// parseContentLength trims whitespace from s and returns -1 if no value
|
// parseContentLength trims whitespace from s and returns -1 if no value
|
||||||
// is set, or the value if it's >= 0.
|
// is set, or the value if it's >= 0.
|
||||||
func parseContentLength(cl string) (int64, error) {
|
func parseContentLength(cl string) (int64, error) {
|
||||||
cl = strings.TrimSpace(cl)
|
cl = textproto.TrimString(cl)
|
||||||
if cl == "" {
|
if cl == "" {
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user