|
5 | 5 | "errors"
|
6 | 6 | "fmt"
|
7 | 7 | "math/bits"
|
| 8 | + "unicode/utf8" |
8 | 9 |
|
9 | 10 | "golang.org/x/xerrors"
|
10 | 11 | )
|
@@ -53,9 +54,38 @@ func parseClosePayload(p []byte) (code StatusCode, reason string, err error) {
|
53 | 54 | code = StatusCode(binary.BigEndian.Uint16(p))
|
54 | 55 | reason = string(p[2:])
|
55 | 56 |
|
| 57 | + if !utf8.ValidString(reason) { |
| 58 | + return 0, "", xerrors.Errorf("invalid utf-8: %q", reason) |
| 59 | + } |
| 60 | + if !isValidReceivedCloseCode(code) { |
| 61 | + return 0, "", xerrors.Errorf("invalid code %v", code) |
| 62 | + } |
| 63 | + |
56 | 64 | return code, reason, nil
|
57 | 65 | }
|
58 | 66 |
|
| 67 | +var validReceivedCloseCodes = map[StatusCode]bool{ |
| 68 | + // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number |
| 69 | + StatusNormalClosure: true, |
| 70 | + StatusGoingAway: true, |
| 71 | + StatusProtocolError: true, |
| 72 | + StatusUnsupportedData: true, |
| 73 | + StatusNoStatusRcvd: false, |
| 74 | + StatusAbnormalClosure: false, |
| 75 | + StatusInvalidFramePayloadData: true, |
| 76 | + StatusPolicyViolation: true, |
| 77 | + StatusMessageTooBig: true, |
| 78 | + StatusMandatoryExtension: true, |
| 79 | + StatusInternalError: true, |
| 80 | + StatusServiceRestart: true, |
| 81 | + StatusTryAgainLater: true, |
| 82 | + StatusTLSHandshake: false, |
| 83 | +} |
| 84 | + |
| 85 | +func isValidReceivedCloseCode(code StatusCode) bool { |
| 86 | + return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999) |
| 87 | +} |
| 88 | + |
59 | 89 | const maxControlFramePayload = 125
|
60 | 90 |
|
61 | 91 | func closePayload(code StatusCode, reason string) ([]byte, error) {
|
|
0 commit comments