Masks and Control Frames
Messages in Pieces
Every encode_frame(OP_TEXT, "Hel", fin=False), a frame that is not final. That frame is half of a real example. RFC 6455 section 5.7 sends “Hello” as two frames:
01 03 48 65 6c
80 02 6c 6f
The first frame is 01: FIN clear, 80: FIN set, opcode 0, then the length 2 and “lo”. Together they carry one text message, “Hello”. This is fragmentation, and this lesson reads it without writing any code for it.
The rules of section 5.4
A message split across several frames, its fragments, follows three rules:
The first frame carries the message’s opcode, 1 for text or 2 for binary, with FIN clear.
Any middle frames carry opcode 0, continuation, with FIN clear.
The last frame carries opcode 0 with FIN set.
Opcode 0 says “this frame continues the message already in progress”; only the first frame says what kind of message it is. FIN marks the end, so the receiver keeps collecting payloads until a continuation frame arrives with FIN set, then joins them. A message in one frame is simply the case where the first frame is also the last: opcode 1 or 2 with FIN set, the only kind your codec has seen so far.
This block reads both frames with the bit operations from Chapter 3 and joins their payloads:
Which frame ends a fragmented message?
Why split a message
Two situations make a sender split a message. The first is a sender that does not know how long the message will be when it starts, for example one that sends data as it produces it. A frame’s header states the payload length before the payload, so such a sender sends what it has as a fragment and marks the last piece with FIN when it is done.
The second is a long message that should not block everything else. Lesson 3 gave control frames a third rule: they may arrive between the fragments of a message. A sender in the middle of a large message can stop between two fragments, send a
01 03 48 65 6c
89 05 48 65 6c 6c 6f
80 02 6c 6f
The receiver handles the ping on its own, then goes back to collecting “Hello”. Data frames may not interleave this way: a new text or binary message cannot start until the last fragment of the current one has arrived. Only control frames may cut in, which is one reason a control frame is never fragmented itself and stays at 125 bytes or fewer.
A ping arrives between 01 03 48 65 6c and 80 02 6c 6f. Is that allowed?
What the learning codec does
Reassembling fragments takes state that lasts across frames: the opcode of the message in progress, the payloads collected so far, a size limit on their total, and the rule that a control frame may arrive in the middle. The learning codec does not do this. The read_message you write in Lesson 6 refuses any frame with FIN clear or with opcode 0, and names a
No close code means “this endpoint does not reassemble fragmented messages”. 1003, unsupported data, is the least wrong choice: it says the endpoint cannot accept what arrived. 1002, protocol error, would be wrong, because it blames the peer, and a peer that fragments a message breaks no rule. This is a limit of the learning codec, chosen to keep the codec small enough to write in one chapter, not a fault of the peer. A conforming
The websockets library you use from Chapter 6 does accept them. In a run made while this course was written, frames built with the learning codec carried “Hel”, a ping, and “lo” to a library server over
Why does the learning codec close with 1003 when it sees a fragment?
So the learning codec is not a complete WebSocket implementation, and it says so with a code instead of failing in a confusing way. The next lesson, the chapter’s project, puts every rule from this chapter behind one read_message, which turns a stream of bytes into messages and control events, and gives each refusal its close code.