123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- package ws
- import "unicode/utf8"
- // State represents state of websocket endpoint.
- // It used by some functions to be more strict when checking compatibility with RFC6455.
- type State uint8
- const (
- // StateServerSide means that endpoint (caller) is a server.
- StateServerSide State = 0x1 << iota
- // StateClientSide means that endpoint (caller) is a client.
- StateClientSide
- // StateExtended means that extension was negotiated during handshake.
- StateExtended
- // StateFragmented means that endpoint (caller) has received fragmented
- // frame and waits for continuation parts.
- StateFragmented
- )
- // Is checks whether the s has v enabled.
- func (s State) Is(v State) bool {
- return uint8(s)&uint8(v) != 0
- }
- // Set enables v state on s.
- func (s State) Set(v State) State {
- return s | v
- }
- // Clear disables v state on s.
- func (s State) Clear(v State) State {
- return s & (^v)
- }
- // ServerSide reports whether states represents server side.
- func (s State) ServerSide() bool { return s.Is(StateServerSide) }
- // ClientSide reports whether state represents client side.
- func (s State) ClientSide() bool { return s.Is(StateClientSide) }
- // Extended reports whether state is extended.
- func (s State) Extended() bool { return s.Is(StateExtended) }
- // Fragmented reports whether state is fragmented.
- func (s State) Fragmented() bool { return s.Is(StateFragmented) }
- // ProtocolError describes error during checking/parsing websocket frames or
- // headers.
- type ProtocolError string
- // Error implements error interface.
- func (p ProtocolError) Error() string { return string(p) }
- // Errors used by the protocol checkers.
- var (
- ErrProtocolOpCodeReserved = ProtocolError("use of reserved op code")
- ErrProtocolControlPayloadOverflow = ProtocolError("control frame payload limit exceeded")
- ErrProtocolControlNotFinal = ProtocolError("control frame is not final")
- ErrProtocolNonZeroRsv = ProtocolError("non-zero rsv bits with no extension negotiated")
- ErrProtocolMaskRequired = ProtocolError("frames from client to server must be masked")
- ErrProtocolMaskUnexpected = ProtocolError("frames from server to client must be not masked")
- ErrProtocolContinuationExpected = ProtocolError("unexpected non-continuation data frame")
- ErrProtocolContinuationUnexpected = ProtocolError("unexpected continuation data frame")
- ErrProtocolStatusCodeNotInUse = ProtocolError("status code is not in use")
- ErrProtocolStatusCodeApplicationLevel = ProtocolError("status code is only application level")
- ErrProtocolStatusCodeNoMeaning = ProtocolError("status code has no meaning yet")
- ErrProtocolStatusCodeUnknown = ProtocolError("status code is not defined in spec")
- ErrProtocolInvalidUTF8 = ProtocolError("invalid utf8 sequence in close reason")
- )
- // CheckHeader checks h to contain valid header data for given state s.
- //
- // Note that zero state (0) means that state is clean,
- // neither server or client side, nor fragmented, nor extended.
- func CheckHeader(h Header, s State) error {
- if h.OpCode.IsReserved() {
- return ErrProtocolOpCodeReserved
- }
- if h.OpCode.IsControl() {
- if h.Length > MaxControlFramePayloadSize {
- return ErrProtocolControlPayloadOverflow
- }
- if !h.Fin {
- return ErrProtocolControlNotFinal
- }
- }
- switch {
- // [RFC6455]: MUST be 0 unless an extension is negotiated that defines meanings for
- // non-zero values. If a nonzero value is received and none of the
- // negotiated extensions defines the meaning of such a nonzero value, the
- // receiving endpoint MUST _Fail the WebSocket Connection_.
- case h.Rsv != 0 && !s.Extended():
- return ErrProtocolNonZeroRsv
- // [RFC6455]: The server MUST close the connection upon receiving a frame that is not masked.
- // In this case, a server MAY send a Close frame with a status code of 1002 (protocol error)
- // as defined in Section 7.4.1. A server MUST NOT mask any frames that it sends to the client.
- // A client MUST close a connection if it detects a masked frame. In this case, it MAY use the
- // status code 1002 (protocol error) as defined in Section 7.4.1.
- case s.ServerSide() && !h.Masked:
- return ErrProtocolMaskRequired
- case s.ClientSide() && h.Masked:
- return ErrProtocolMaskUnexpected
- // [RFC6455]: See detailed explanation in 5.4 section.
- case s.Fragmented() && !h.OpCode.IsControl() && h.OpCode != OpContinuation:
- return ErrProtocolContinuationExpected
- case !s.Fragmented() && h.OpCode == OpContinuation:
- return ErrProtocolContinuationUnexpected
- default:
- return nil
- }
- }
- // CheckCloseFrameData checks received close information
- // to be valid RFC6455 compatible close info.
- //
- // Note that code.Empty() or code.IsAppLevel() will raise error.
- //
- // If endpoint sends close frame without status code (with frame.Length = 0),
- // application should not check its payload.
- func CheckCloseFrameData(code StatusCode, reason string) error {
- switch {
- case code.IsNotUsed():
- return ErrProtocolStatusCodeNotInUse
- case code.IsProtocolReserved():
- return ErrProtocolStatusCodeApplicationLevel
- case code == StatusNoMeaningYet:
- return ErrProtocolStatusCodeNoMeaning
- case code.IsProtocolSpec() && !code.IsProtocolDefined():
- return ErrProtocolStatusCodeUnknown
- case !utf8.ValidString(reason):
- return ErrProtocolInvalidUTF8
- default:
- return nil
- }
- }
|