Coverage Report

Created: 2025-10-13 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzmq/src/ws_encoder.cpp
Line
Count
Source
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
#include "ws_protocol.hpp"
5
#include "ws_encoder.hpp"
6
#include "msg.hpp"
7
#include "likely.hpp"
8
#include "wire.hpp"
9
#include "random.hpp"
10
11
#include <limits.h>
12
13
zmq::ws_encoder_t::ws_encoder_t (size_t bufsize_, bool must_mask_) :
14
0
    encoder_base_t<ws_encoder_t> (bufsize_), _must_mask (must_mask_)
15
0
{
16
    //  Write 0 bytes to the batch and go to message_ready state.
17
0
    next_step (NULL, 0, &ws_encoder_t::message_ready, true);
18
0
    _masked_msg.init ();
19
0
}
20
21
zmq::ws_encoder_t::~ws_encoder_t ()
22
0
{
23
0
    _masked_msg.close ();
24
0
}
25
26
void zmq::ws_encoder_t::message_ready ()
27
0
{
28
0
    int offset = 0;
29
30
0
    _is_binary = false;
31
32
0
    if (in_progress ()->is_ping ())
33
0
        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_ping;
34
0
    else if (in_progress ()->is_pong ())
35
0
        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_pong;
36
0
    else if (in_progress ()->is_close_cmd ())
37
0
        _tmp_buf[offset++] = 0x80 | zmq::ws_protocol_t::opcode_close;
38
0
    else {
39
0
        _tmp_buf[offset++] = 0x82; // Final | binary
40
0
        _is_binary = true;
41
0
    }
42
43
0
    _tmp_buf[offset] = _must_mask ? 0x80 : 0x00;
44
45
0
    size_t size = in_progress ()->size ();
46
0
    if (_is_binary)
47
0
        size++;
48
    //  TODO: create an opcode for subscribe/cancel
49
0
    if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())
50
0
        size++;
51
52
0
    if (size <= 125)
53
0
        _tmp_buf[offset++] |= static_cast<unsigned char> (size & 127);
54
0
    else if (size <= 0xFFFF) {
55
0
        _tmp_buf[offset++] |= 126;
56
0
        _tmp_buf[offset++] = static_cast<unsigned char> ((size >> 8) & 0xFF);
57
0
        _tmp_buf[offset++] = static_cast<unsigned char> (size & 0xFF);
58
0
    } else {
59
0
        _tmp_buf[offset++] |= 127;
60
0
        put_uint64 (_tmp_buf + offset, size);
61
0
        offset += 8;
62
0
    }
63
64
0
    if (_must_mask) {
65
0
        const uint32_t random = generate_random ();
66
0
        put_uint32 (_tmp_buf + offset, random);
67
0
        put_uint32 (_mask, random);
68
0
        offset += 4;
69
0
    }
70
71
0
    int mask_index = 0;
72
0
    if (_is_binary) {
73
        //  Encode flags.
74
0
        unsigned char protocol_flags = 0;
75
0
        if (in_progress ()->flags () & msg_t::more)
76
0
            protocol_flags |= ws_protocol_t::more_flag;
77
0
        if (in_progress ()->flags () & msg_t::command)
78
0
            protocol_flags |= ws_protocol_t::command_flag;
79
80
0
        _tmp_buf[offset++] =
81
0
          _must_mask ? protocol_flags ^ _mask[mask_index++] : protocol_flags;
82
0
    }
83
84
    //  Encode the subscribe/cancel byte.
85
    //  TODO: remove once there is an opcode for subscribe/cancel
86
0
    if (in_progress ()->is_subscribe ())
87
0
        _tmp_buf[offset++] = _must_mask ? 1 ^ _mask[mask_index++] : 1;
88
0
    else if (in_progress ()->is_cancel ())
89
0
        _tmp_buf[offset++] = _must_mask ? 0 ^ _mask[mask_index++] : 0;
90
91
0
    next_step (_tmp_buf, offset, &ws_encoder_t::size_ready, false);
92
0
}
93
94
void zmq::ws_encoder_t::size_ready ()
95
0
{
96
0
    if (_must_mask) {
97
0
        assert (in_progress () != &_masked_msg);
98
0
        const size_t size = in_progress ()->size ();
99
100
0
        unsigned char *src =
101
0
          static_cast<unsigned char *> (in_progress ()->data ());
102
0
        unsigned char *dest = src;
103
104
        //  If msg is shared or data is constant we cannot mask in-place, allocate a new msg for it
105
0
        if (in_progress ()->flags () & msg_t::shared
106
0
            || in_progress ()->is_cmsg ()) {
107
0
            _masked_msg.close ();
108
0
            _masked_msg.init_size (size);
109
0
            dest = static_cast<unsigned char *> (_masked_msg.data ());
110
0
        }
111
112
0
        int mask_index = 0;
113
0
        if (_is_binary)
114
0
            ++mask_index;
115
        //  TODO: remove once there is an opcode for subscribe/cancel
116
0
        if (in_progress ()->is_subscribe () || in_progress ()->is_cancel ())
117
0
            ++mask_index;
118
0
        for (size_t i = 0; i < size; ++i, mask_index++)
119
0
            dest[i] = src[i] ^ _mask[mask_index % 4];
120
121
0
        next_step (dest, size, &ws_encoder_t::message_ready, true);
122
0
    } else {
123
0
        next_step (in_progress ()->data (), in_progress ()->size (),
124
0
                   &ws_encoder_t::message_ready, true);
125
0
    }
126
0
}