1e509ee18Sopenharmony_ci/*
2e509ee18Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3e509ee18Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e509ee18Sopenharmony_ci * you may not use this file except in compliance with the License.
5e509ee18Sopenharmony_ci * You may obtain a copy of the License at
6e509ee18Sopenharmony_ci *
7e509ee18Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e509ee18Sopenharmony_ci *
9e509ee18Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e509ee18Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e509ee18Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e509ee18Sopenharmony_ci * See the License for the specific language governing permissions and
13e509ee18Sopenharmony_ci * limitations under the License.
14e509ee18Sopenharmony_ci */
15e509ee18Sopenharmony_ci
16e509ee18Sopenharmony_ci#include "frame_builder.h"
17e509ee18Sopenharmony_ci
18e509ee18Sopenharmony_cinamespace OHOS::ArkCompiler::Toolchain {
19e509ee18Sopenharmony_ciServerFrameBuilder& ServerFrameBuilder::SetFinal(bool fin)
20e509ee18Sopenharmony_ci{
21e509ee18Sopenharmony_ci    fin_ = fin;
22e509ee18Sopenharmony_ci    return *this;
23e509ee18Sopenharmony_ci}
24e509ee18Sopenharmony_ci
25e509ee18Sopenharmony_ciServerFrameBuilder& ServerFrameBuilder::SetOpcode(FrameType opcode)
26e509ee18Sopenharmony_ci{
27e509ee18Sopenharmony_ci    opcode_ = opcode;
28e509ee18Sopenharmony_ci    return *this;
29e509ee18Sopenharmony_ci}
30e509ee18Sopenharmony_ci
31e509ee18Sopenharmony_ciServerFrameBuilder& ServerFrameBuilder::SetPayload(const std::string& payload)
32e509ee18Sopenharmony_ci{
33e509ee18Sopenharmony_ci    payload_ = payload;
34e509ee18Sopenharmony_ci    return *this;
35e509ee18Sopenharmony_ci}
36e509ee18Sopenharmony_ci
37e509ee18Sopenharmony_ciServerFrameBuilder& ServerFrameBuilder::SetPayload(std::string&& payload)
38e509ee18Sopenharmony_ci{
39e509ee18Sopenharmony_ci    payload_ = std::move(payload);
40e509ee18Sopenharmony_ci    return *this;
41e509ee18Sopenharmony_ci}
42e509ee18Sopenharmony_ci
43e509ee18Sopenharmony_ciServerFrameBuilder& ServerFrameBuilder::AppendPayload(const std::string& payload)
44e509ee18Sopenharmony_ci{
45e509ee18Sopenharmony_ci    payload_.append(payload);
46e509ee18Sopenharmony_ci    return *this;
47e509ee18Sopenharmony_ci}
48e509ee18Sopenharmony_ci
49e509ee18Sopenharmony_cistd::string ServerFrameBuilder::Build() const
50e509ee18Sopenharmony_ci{
51e509ee18Sopenharmony_ci    std::string message;
52e509ee18Sopenharmony_ci    PushFullHeader(message, 0);
53e509ee18Sopenharmony_ci    PushPayload(message);
54e509ee18Sopenharmony_ci    return message;
55e509ee18Sopenharmony_ci}
56e509ee18Sopenharmony_ci
57e509ee18Sopenharmony_civoid ServerFrameBuilder::PushFullHeader(std::string& message, size_t additionalReservedMem) const
58e509ee18Sopenharmony_ci{
59e509ee18Sopenharmony_ci    auto headerBytes = WebSocketFrame::HEADER_LEN;
60e509ee18Sopenharmony_ci    auto payloadBytes = payload_.size();
61e509ee18Sopenharmony_ci    uint8_t payloadLenField = 0;
62e509ee18Sopenharmony_ci
63e509ee18Sopenharmony_ci    if (payloadBytes <= WebSocketFrame::ONE_BYTE_LENTH_ENC_LIMIT) {
64e509ee18Sopenharmony_ci        payloadLenField = static_cast<uint8_t>(payloadBytes);
65e509ee18Sopenharmony_ci    } else if (payloadBytes < WebSocketFrame::TWO_BYTES_LENGTH_LIMIT) {
66e509ee18Sopenharmony_ci        payloadLenField = WebSocketFrame::TWO_BYTES_LENTH_ENC;
67e509ee18Sopenharmony_ci        headerBytes += WebSocketFrame::TWO_BYTES_LENTH;
68e509ee18Sopenharmony_ci    } else {
69e509ee18Sopenharmony_ci        payloadLenField = WebSocketFrame::EIGHT_BYTES_LENTH_ENC;
70e509ee18Sopenharmony_ci        headerBytes += WebSocketFrame::EIGHT_BYTES_LENTH;
71e509ee18Sopenharmony_ci    }
72e509ee18Sopenharmony_ci
73e509ee18Sopenharmony_ci    message.reserve(headerBytes + payloadBytes + additionalReservedMem);
74e509ee18Sopenharmony_ci    PushHeader(message, payloadLenField);
75e509ee18Sopenharmony_ci    PushPayloadLength(message, payloadLenField);
76e509ee18Sopenharmony_ci}
77e509ee18Sopenharmony_ci
78e509ee18Sopenharmony_civoid ServerFrameBuilder::PushHeader(std::string& message, uint8_t payloadLenField) const
79e509ee18Sopenharmony_ci{
80e509ee18Sopenharmony_ci    uint8_t byte = EnumToNumber(opcode_);
81e509ee18Sopenharmony_ci    if (fin_) {
82e509ee18Sopenharmony_ci        byte |= 0x80;
83e509ee18Sopenharmony_ci    }
84e509ee18Sopenharmony_ci    message.push_back(byte);
85e509ee18Sopenharmony_ci
86e509ee18Sopenharmony_ci    // A server MUST NOT mask any frames that it sends to the client,
87e509ee18Sopenharmony_ci    // hence mask bit must be set to zero (see https://www.rfc-editor.org/rfc/rfc6455#section-5.1)
88e509ee18Sopenharmony_ci    byte = payloadLenField & 0x7f;
89e509ee18Sopenharmony_ci    message.push_back(byte);
90e509ee18Sopenharmony_ci}
91e509ee18Sopenharmony_ci
92e509ee18Sopenharmony_civoid ServerFrameBuilder::PushPayloadLength(std::string& message, uint8_t payloadLenField) const
93e509ee18Sopenharmony_ci{
94e509ee18Sopenharmony_ci    uint64_t payloadLen = payload_.size();
95e509ee18Sopenharmony_ci    if (payloadLenField == WebSocketFrame::TWO_BYTES_LENTH_ENC) {
96e509ee18Sopenharmony_ci        PushNumberPerByte(message, static_cast<uint16_t>(payloadLen));
97e509ee18Sopenharmony_ci    } else if (payloadLenField == WebSocketFrame::EIGHT_BYTES_LENTH_ENC) {
98e509ee18Sopenharmony_ci        PushNumberPerByte(message, payloadLen);
99e509ee18Sopenharmony_ci    }
100e509ee18Sopenharmony_ci}
101e509ee18Sopenharmony_ci
102e509ee18Sopenharmony_civoid ServerFrameBuilder::PushPayload(std::string& message) const
103e509ee18Sopenharmony_ci{
104e509ee18Sopenharmony_ci    message.append(payload_);
105e509ee18Sopenharmony_ci}
106e509ee18Sopenharmony_ci
107e509ee18Sopenharmony_ciClientFrameBuilder::ClientFrameBuilder(bool final, FrameType opcode, const uint8_t maskingKey[WebSocketFrame::MASK_LEN])
108e509ee18Sopenharmony_ci    : ServerFrameBuilder(final, opcode)
109e509ee18Sopenharmony_ci{
110e509ee18Sopenharmony_ci    SetMask(maskingKey);
111e509ee18Sopenharmony_ci}
112e509ee18Sopenharmony_ci
113e509ee18Sopenharmony_ciClientFrameBuilder& ClientFrameBuilder::SetMask(const uint8_t maskingKey[WebSocketFrame::MASK_LEN])
114e509ee18Sopenharmony_ci{
115e509ee18Sopenharmony_ci    for (size_t i = 0; i < WebSocketFrame::MASK_LEN; ++i) {
116e509ee18Sopenharmony_ci        maskingKey_[i] = maskingKey[i];
117e509ee18Sopenharmony_ci    }
118e509ee18Sopenharmony_ci    return *this;
119e509ee18Sopenharmony_ci}
120e509ee18Sopenharmony_ci
121e509ee18Sopenharmony_civoid ClientFrameBuilder::PushFullHeader(std::string& message, size_t additionalReservedMem) const
122e509ee18Sopenharmony_ci{
123e509ee18Sopenharmony_ci    // reserve additional 4 bytes for mask
124e509ee18Sopenharmony_ci    ServerFrameBuilder::PushFullHeader(message, additionalReservedMem + WebSocketFrame::MASK_LEN);
125e509ee18Sopenharmony_ci    // If the data is being sent by the client, the frame(s) MUST be masked
126e509ee18Sopenharmony_ci    // (see https://www.rfc-editor.org/rfc/rfc6455#section-6.1)
127e509ee18Sopenharmony_ci    message[1] |= 0x80;
128e509ee18Sopenharmony_ci    PushMask(message);
129e509ee18Sopenharmony_ci}
130e509ee18Sopenharmony_ci
131e509ee18Sopenharmony_civoid ClientFrameBuilder::PushPayload(std::string& message) const
132e509ee18Sopenharmony_ci{
133e509ee18Sopenharmony_ci    // push masked payload
134e509ee18Sopenharmony_ci    for (size_t i = 0, end = payload_.size(); i < end; ++i) {
135e509ee18Sopenharmony_ci        char c = payload_[i] ^ maskingKey_[i % WebSocketFrame::MASK_LEN];
136e509ee18Sopenharmony_ci        message.push_back(c);
137e509ee18Sopenharmony_ci    }
138e509ee18Sopenharmony_ci}
139e509ee18Sopenharmony_ci
140e509ee18Sopenharmony_civoid ClientFrameBuilder::PushMask(std::string& message) const
141e509ee18Sopenharmony_ci{
142e509ee18Sopenharmony_ci    for (size_t i = 0; i < WebSocketFrame::MASK_LEN; ++i) {
143e509ee18Sopenharmony_ci        message.push_back(static_cast<char>(maskingKey_[i]));
144e509ee18Sopenharmony_ci    }
145e509ee18Sopenharmony_ci}
146e509ee18Sopenharmony_ci} // OHOS::ArkCompiler::Toolchain
147