| 837 | } |
| 838 | |
| 839 | Result HttpWebSocketFrameWriter::beginFrame(const HttpWebSocketFrameHeaderView& frame, Span<char> storage, |
| 840 | Span<const char>& encodedHeader) |
| 841 | { |
| 842 | SC_TRY_MSG(not frameInProgress, "HttpWebSocketFrameWriter frame already in progress"); |
| 843 | SC_TRY_MSG(scHttpWebSocketIsSupportedOpcode(frame.opcode), "HttpWebSocketFrameWriter unsupported opcode"); |
| 844 | |
| 845 | if (frame.isControlFrame()) |
| 846 | { |
| 847 | SC_TRY_MSG(frame.fin, "HttpWebSocketFrameWriter control frames must not be fragmented"); |
| 848 | SC_TRY_MSG(frame.payloadLength <= 125, "HttpWebSocketFrameWriter control frame payload too large"); |
| 849 | } |
| 850 | else |
| 851 | { |
| 852 | if (frame.opcode == HttpWebSocketOpcode::Continuation) |
| 853 | { |
| 854 | SC_TRY_MSG(fragmentedMessageInProgress, "HttpWebSocketFrameWriter unexpected continuation frame"); |
| 855 | } |
| 856 | else |
| 857 | { |
| 858 | SC_TRY_MSG(not fragmentedMessageInProgress, "HttpWebSocketFrameWriter expected continuation frame"); |
| 859 | } |
| 860 | } |
| 861 | |
| 862 | const bool requiresMask = scHttpWebSocketRequiresOutgoingMask(endpointRole); |
| 863 | SC_TRY_MSG(frame.masked == requiresMask, "HttpWebSocketFrameWriter invalid frame masking for endpoint role"); |
| 864 | |
| 865 | const size_t encodedLength = |
| 866 | 2 + (frame.payloadLength < 126 ? 0 : (frame.payloadLength <= 0xFFFF ? 2 : 8)) + (frame.masked ? 4 : 0); |
| 867 | SC_TRY_MSG(storage.sizeInBytes() >= encodedLength, "HttpWebSocketFrameWriter header buffer too small"); |
| 868 | |
| 869 | currentFrame = frame; |
| 870 | |
| 871 | uint8_t* output = reinterpret_cast<uint8_t*>(storage.data()); |
| 872 | output[0] = static_cast<uint8_t>((frame.fin ? 0x80 : 0) | static_cast<uint8_t>(frame.opcode)); |
| 873 | |
| 874 | size_t headerOffset = 1; |
| 875 | if (frame.payloadLength < 126) |
| 876 | { |
| 877 | output[headerOffset++] = static_cast<uint8_t>((frame.masked ? 0x80 : 0) | frame.payloadLength); |
| 878 | } |
| 879 | else if (frame.payloadLength <= 0xFFFF) |
| 880 | { |
| 881 | output[headerOffset++] = static_cast<uint8_t>((frame.masked ? 0x80 : 0) | 126); |
| 882 | output[headerOffset++] = static_cast<uint8_t>((frame.payloadLength >> 8) & 0xFF); |
| 883 | output[headerOffset++] = static_cast<uint8_t>(frame.payloadLength & 0xFF); |
| 884 | } |
| 885 | else |
| 886 | { |
| 887 | output[headerOffset++] = static_cast<uint8_t>((frame.masked ? 0x80 : 0) | 127); |
| 888 | for (int shift = 56; shift >= 0; shift -= 8) |
| 889 | { |
| 890 | output[headerOffset++] = static_cast<uint8_t>((frame.payloadLength >> shift) & 0xFF); |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | if (frame.masked) |
| 895 | { |
| 896 | for (size_t idx = 0; idx < 4; ++idx) |