2018-04-04 05:47:10 +00:00
|
|
|
package server
|
2018-04-04 04:01:26 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ErrCloseSent is returned when the application writes a message to the
|
|
|
|
// connection after sending a close message.
|
|
|
|
var ErrCloseSent = errors.New("socket: close sent")
|
|
|
|
|
|
|
|
// ErrReadLimit is returned when reading a message that is larger than the
|
|
|
|
// read limit set for the connection.
|
|
|
|
var ErrReadLimit = errors.New("socket: read limit exceeded")
|
|
|
|
|
|
|
|
// netError satisfies the net Error interface.
|
|
|
|
type netError struct {
|
|
|
|
msg string
|
|
|
|
temporary bool
|
|
|
|
timeout bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *netError) Error() string { return e.msg }
|
|
|
|
func (e *netError) Temporary() bool { return e.temporary }
|
|
|
|
func (e *netError) Timeout() bool { return e.timeout }
|
|
|
|
|
|
|
|
// CloseError represents close frame.
|
|
|
|
type CloseError struct {
|
|
|
|
|
|
|
|
// Code is defined in RFC 6455, section 11.7.
|
|
|
|
Code int
|
|
|
|
|
|
|
|
// Text is the optional text payload.
|
|
|
|
Text string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *CloseError) Error() string {
|
|
|
|
s := []byte("socket: close ")
|
|
|
|
s = strconv.AppendInt(s, int64(e.Code), 10)
|
|
|
|
switch e.Code {
|
|
|
|
case CloseNormalClosure:
|
|
|
|
s = append(s, " (normal)"...)
|
|
|
|
case CloseGoingAway:
|
|
|
|
s = append(s, " (going away)"...)
|
|
|
|
case CloseProtocolError:
|
|
|
|
s = append(s, " (protocol error)"...)
|
|
|
|
case CloseUnsupportedData:
|
|
|
|
s = append(s, " (unsupported data)"...)
|
|
|
|
case CloseNoStatusReceived:
|
|
|
|
s = append(s, " (no status)"...)
|
|
|
|
case CloseAbnormalClosure:
|
|
|
|
s = append(s, " (abnormal closure)"...)
|
|
|
|
case CloseInvalidFramePayloadData:
|
|
|
|
s = append(s, " (invalid payload data)"...)
|
|
|
|
case ClosePolicyViolation:
|
|
|
|
s = append(s, " (policy violation)"...)
|
|
|
|
case CloseMessageTooBig:
|
|
|
|
s = append(s, " (message too big)"...)
|
|
|
|
case CloseMandatoryExtension:
|
|
|
|
s = append(s, " (mandatory extension missing)"...)
|
|
|
|
case CloseInternalServerErr:
|
|
|
|
s = append(s, " (internal server error)"...)
|
|
|
|
case CloseTLSHandshake:
|
|
|
|
s = append(s, " (TLS handshake error)"...)
|
|
|
|
}
|
|
|
|
if e.Text != "" {
|
|
|
|
s = append(s, ": "...)
|
|
|
|
s = append(s, e.Text...)
|
|
|
|
}
|
|
|
|
return string(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsCloseError returns boolean indicating whether the error is a *CloseError
|
|
|
|
// with one of the specified codes.
|
|
|
|
func IsCloseError(err error, codes ...int) bool {
|
|
|
|
if e, ok := err.(*CloseError); ok {
|
|
|
|
for _, code := range codes {
|
|
|
|
if e.Code == code {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsUnexpectedCloseError returns boolean indicating whether the error is a
|
|
|
|
// *CloseError with a code not in the list of expected codes.
|
|
|
|
func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
|
|
|
|
if e, ok := err.(*CloseError); ok {
|
|
|
|
for _, code := range expectedCodes {
|
|
|
|
if e.Code == code {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
errWriteTimeout = &netError{msg: "socket: write timeout", timeout: true, temporary: true}
|
|
|
|
errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
|
|
|
|
errBadWriteOpCode = errors.New("socket: bad write message type")
|
|
|
|
errWriteClosed = errors.New("socket: write closed")
|
|
|
|
errInvalidControlFrame = errors.New("socket: invalid control frame")
|
|
|
|
// ErrBadHandshake is returned when the server response to opening handshake is
|
|
|
|
// invalid.
|
|
|
|
ErrBadHandshake = errors.New("socket: bad handshake")
|
|
|
|
ErrInvalidCompression = errors.New("socket: invalid compression negotiation")
|
|
|
|
)
|