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 KEY_LENGTH = GetBase64EncodingLength(16); 33 // SHA1 will write SHA_DIGEST_LENGTH == 20 bytes of output 34 static constexpr size_t ENCODED_KEY_LEN = GetBase64EncodingLength(SHA_DIGEST_LENGTH); 35 36 static bool EncodeKey(std::string_view key, unsigned char (&destination)[ENCODED_KEY_LEN + 1]); 37 static bool EncodeKey(const unsigned char(&key)[KEY_LENGTH + 1], unsigned char (&destination)[ENCODED_KEY_LEN + 1]); 38 39 private: 40 static bool EncodeKey(const unsigned char *source, size_t length, 41 unsigned char (&destination)[ENCODED_KEY_LEN + 1]); 42 }; 43 44 class ProtocolUpgradeBuilder { 45 public: CopyStringToBuffer(std::string_view source, size_t startIndex)46 constexpr size_t CopyStringToBuffer(std::string_view source, size_t startIndex) 47 { 48 for (size_t i = 0, end = source.size(); i < end; ++i, ++startIndex) { 49 upgradeBuffer_[startIndex] = source[i]; 50 } 51 return startIndex; 52 } 53 54 template <typename T, size_t LENGTH> 55 constexpr size_t CopyStringToBuffer(const T (&source)[LENGTH], size_t startIndex) 56 { 57 for (size_t i = 0, end = LENGTH - 1; i < end; ++i, ++startIndex) { 58 upgradeBuffer_[startIndex] = source[i]; 59 } 60 return startIndex; 61 } 62 ProtocolUpgradeBuilder()63 constexpr ProtocolUpgradeBuilder() 64 { 65 size_t index = CopyStringToBuffer(SWITCHING_PROTOCOLS, 0); 66 index = CopyStringToBuffer(HttpBase::EOL, index); 67 index = CopyStringToBuffer(CONNECTION_UPGRADE, index); 68 index = CopyStringToBuffer(HttpBase::EOL, index); 69 index = CopyStringToBuffer(UPGRADE_WEBSOCKET, index); 70 index = CopyStringToBuffer(HttpBase::EOL, index); 71 index = CopyStringToBuffer(ACCEPT_KEY, index); 72 // will copy key without null terminator 73 index += WebSocketKeyEncoder::ENCODED_KEY_LEN; 74 index = CopyStringToBuffer(HttpBase::EOL, index); 75 index = CopyStringToBuffer(HttpBase::EOL, index); 76 } 77 ProtocolUpgradeBuilder( const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1])78 constexpr explicit ProtocolUpgradeBuilder( 79 const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1]) 80 : ProtocolUpgradeBuilder() 81 { 82 SetKey(encodedKey); 83 } 84 SetKey(const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1])85 constexpr void SetKey(const unsigned char (&encodedKey)[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1]) 86 { 87 CopyStringToBuffer(encodedKey, KEY_START); 88 } 89 GetUpgradeMessage()90 constexpr const char *GetUpgradeMessage() 91 { 92 return upgradeBuffer_.data(); 93 } 94 GetLength()95 static constexpr size_t GetLength() 96 { 97 return MESSAGE_LENGTH; 98 } 99 100 private: 101 static constexpr std::string_view SWITCHING_PROTOCOLS = "HTTP/1.1 101 Switching Protocols"; 102 static constexpr std::string_view CONNECTION_UPGRADE = "Connection: Upgrade"; 103 static constexpr std::string_view UPGRADE_WEBSOCKET = "Upgrade: websocket"; 104 static constexpr std::string_view ACCEPT_KEY = "Sec-WebSocket-Accept: "; 105 static constexpr size_t KEY_START = SWITCHING_PROTOCOLS.size() 106 + CONNECTION_UPGRADE.size() 107 + UPGRADE_WEBSOCKET.size() 108 + ACCEPT_KEY.size() 109 + 3 * HttpBase::EOL.size(); 110 static constexpr size_t MESSAGE_LENGTH = KEY_START 111 + WebSocketKeyEncoder::ENCODED_KEY_LEN 112 + 2 * HttpBase::EOL.size(); 113 114 private: 115 // null-terminated string buffer 116 std::array<char, MESSAGE_LENGTH + 1> upgradeBuffer_ {0}; 117 }; 118 } // namespace OHOS::ArkCompiler::Toolchain 119 120 #endif // ARKCOMPILER_TOOLCHAIN_WEBSOCKET_HANDSHAKE_HELPER_H 121