(isClient bool)
| 690 | } |
| 691 | |
| 692 | func (w *websocket) readFrame(isClient bool) (*websocketFrame, error) { |
| 693 | header := make([]byte, 2) |
| 694 | if _, err := w.readFull(isClient, header); err != nil { |
| 695 | return nil, fmt.Errorf("read header: %w", err) |
| 696 | } |
| 697 | |
| 698 | fin := header[0]&0x80 != 0 |
| 699 | |
| 700 | rsv := header[0] & 0x70 |
| 701 | rsv1 := rsv&0x40 != 0 |
| 702 | rsv2 := rsv&0x20 != 0 |
| 703 | rsv3 := rsv&0x10 != 0 |
| 704 | |
| 705 | if rsv2 || rsv3 { |
| 706 | return nil, fmt.Errorf("unsupported extension: RSV1=%t, RSV2=%t, RSV3=%t", rsv1, rsv2, rsv3) |
| 707 | } |
| 708 | |
| 709 | opcode := header[0] & 0x0F |
| 710 | |
| 711 | masked := header[1]&0x80 != 0 |
| 712 | if isClient && !masked { |
| 713 | return nil, fmt.Errorf("client sent unmasked frame") |
| 714 | } |
| 715 | |
| 716 | switch opcode { |
| 717 | case wsOpcodeContinuation, wsOpcodeText, wsOpcodeBinary, wsOpcodePing, wsOpcodePong, wsOpcodeClose: |
| 718 | default: |
| 719 | return nil, fmt.Errorf("invalid opcode: %x", opcode) |
| 720 | } |
| 721 | |
| 722 | payloadLen := uint64(header[1] & 0x7F) |
| 723 | if payloadLen == 126 { |
| 724 | ext := make([]byte, 2) |
| 725 | if _, err := w.readFull(isClient, ext); err != nil { |
| 726 | return nil, fmt.Errorf("read extended length (len=126): %w", err) |
| 727 | } |
| 728 | payloadLen = uint64(binary.BigEndian.Uint16(ext)) |
| 729 | } else if payloadLen == 127 { |
| 730 | ext := make([]byte, 8) |
| 731 | if _, err := w.readFull(isClient, ext); err != nil { |
| 732 | return nil, fmt.Errorf("read extended length (len=127): %w", err) |
| 733 | } |
| 734 | payloadLen = binary.BigEndian.Uint64(ext) |
| 735 | } |
| 736 | |
| 737 | mask := make([]byte, 4) |
| 738 | if masked { |
| 739 | if _, err := w.readFull(isClient, mask); err != nil { |
| 740 | return nil, fmt.Errorf("read mask: %w", err) |
| 741 | } |
| 742 | } |
| 743 | |
| 744 | // Check beforehand so we don't allocate arbitrarily large amounts of memory |
| 745 | // for the payload. All the other reads use fixed size buffers, so they're fine. |
| 746 | remaining := w.n.Load() |
| 747 | if remaining < payloadLen { |
| 748 | return nil, fmt.Errorf("%w: limit=%d, have=%d, want=%d, msgsRead=%d", errWebsocketPayloadLimitExceeded, tracer.PayloadLimitBytes, remaining, payloadLen, len(w.getMessages())) |
| 749 | } |
no test coverage detected