• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ARKCOMPILER_TOOLCHAIN_WEBSOCKET_HANDSHAKE_HELPER_H
17 #define ARKCOMPILER_TOOLCHAIN_WEBSOCKET_HANDSHAKE_HELPER_H
18 
19 #include "define.h"
20 #include "http.h"
21 #include "network.h"
22 
23 #include <array>
24 #include <string_view>
25 
26 namespace OHOS::ArkCompiler::Toolchain {
27 class WebSocketKeyEncoder {
28 public:
29     // WebSocket Globally Unique Identifier
30     static constexpr std::string_view WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
31     // The value of |Sec-WebSocket-Key| header field MUST be a nonce consisting of a randomly selected 16-byte value
32     static constexpr size_t SEC_WEBSOCKET_KEY_BYTES_LEN = 16;
33     static constexpr size_t KEY_LENGTH = GetBase64EncodingLength(SEC_WEBSOCKET_KEY_BYTES_LEN);
34     // SHA1 will write SHA_DIGEST_LENGTH == 20 bytes of output
35     static constexpr size_t ENCODED_KEY_LEN = GetBase64EncodingLength(SHA_DIGEST_LENGTH);
36 
37     static std::string GenerateRandomSecWSKey();
38     static bool EncodeKey(std::string_view key, unsigned char (&destination)[ENCODED_KEY_LEN + 1]);
39     static bool EncodeKey(const unsigned char(&key)[KEY_LENGTH + 1], unsigned char (&destination)[ENCODED_KEY_LEN + 1]);
40 
41 private:
42     static bool EncodeKey(const unsigned char *source, size_t length,
43                           unsigned char (&destination)[ENCODED_KEY_LEN + 1]);
44 };
45 
46 class ProtocolUpgradeBuilder {
47 public:
CopyStringToBuffer(std::string_view source,size_t startIndex)48     constexpr size_t CopyStringToBuffer(std::string_view source, size_t startIndex)
49     {
50         for (size_t i = 0, end = source.size(); i < end; ++i, ++startIndex) {
51             upgradeBuffer_[startIndex] = source[i];
52         }
53         return startIndex;
54     }
55 
56     template <typename T, size_t LENGTH>
CopyStringToBuffer(const T (& source)[LENGTH],size_t startIndex)57     constexpr size_t CopyStringToBuffer(const T (&source)[LENGTH], size_t startIndex)
58     {
59         for (size_t i = 0, end = LENGTH - 1; i < end; ++i, ++startIndex) {
60             upgradeBuffer_[startIndex] = source[i];
61         }
62         return startIndex;
63     }
64 
ProtocolUpgradeBuilder()65     constexpr ProtocolUpgradeBuilder()
66     {
67         size_t index = CopyStringToBuffer(SWITCHING_PROTOCOLS, 0);
68         index = CopyStringToBuffer(HttpBase::EOL, index);
69         index = CopyStringToBuffer(CONNECTION_UPGRADE, index);
70         index = CopyStringToBuffer(HttpBase::EOL, index);
71         index = CopyStringToBuffer(UPGRADE_WEBSOCKET, index);
72         index = CopyStringToBuffer(HttpBase::EOL, index);
73         index = CopyStringToBuffer(ACCEPT_KEY, index);
74         // will copy key without null terminator
75         index += WebSocketKeyEncoder::ENCODED_KEY_LEN;
76         index = CopyStringToBuffer(HttpBase::EOL, index);
77         index = CopyStringToBuffer(HttpBase::EOL, index);
78     }
79 
ProtocolUpgradeBuilder(const unsigned char (& encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN+1])80     constexpr explicit ProtocolUpgradeBuilder(
81         const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1])
82         : ProtocolUpgradeBuilder()
83     {
84         SetKey(encodedKey);
85     }
86 
SetKey(const unsigned char (& encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN+1])87     constexpr void SetKey(const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1])
88     {
89         CopyStringToBuffer(encodedKey, KEY_START);
90     }
91 
GetUpgradeMessage()92     constexpr const char *GetUpgradeMessage()
93     {
94         return upgradeBuffer_.data();
95     }
96 
GetLength()97     static constexpr size_t GetLength()
98     {
99         return MESSAGE_LENGTH;
100     }
101 
102 private:
103     static constexpr std::string_view SWITCHING_PROTOCOLS = "HTTP/1.1 101 Switching Protocols";
104     static constexpr std::string_view CONNECTION_UPGRADE = "Connection: Upgrade";
105     static constexpr std::string_view UPGRADE_WEBSOCKET = "Upgrade: websocket";
106     static constexpr std::string_view ACCEPT_KEY = "Sec-WebSocket-Accept: ";
107     static constexpr size_t KEY_START = SWITCHING_PROTOCOLS.size()
108         + CONNECTION_UPGRADE.size()
109         + UPGRADE_WEBSOCKET.size()
110         + ACCEPT_KEY.size()
111         + 3 * HttpBase::EOL.size();
112     static constexpr size_t MESSAGE_LENGTH = KEY_START
113         + WebSocketKeyEncoder::ENCODED_KEY_LEN
114         + 2 * HttpBase::EOL.size();
115 
116 private:
117     // null-terminated string buffer
118     std::array<char, MESSAGE_LENGTH + 1> upgradeBuffer_ {0};
119 };
120 } // namespace OHOS::ArkCompiler::Toolchain
121 
122 #endif // ARKCOMPILER_TOOLCHAIN_WEBSOCKET_HANDSHAKE_HELPER_H
123