xref: /arkcompiler/toolchain/websocket/http.cpp (revision e509ee18)
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#include "common/log_wrapper.h"
17#include "http.h"
18
19namespace OHOS::ArkCompiler::Toolchain {
20/* static */
21std::string HttpBase::DecodeHeader(const std::string& headersText, std::string_view headerName)
22{
23    auto startPos = headersText.find(headerName);
24    if (startPos != std::string::npos) {
25        auto endOfLinePos = headersText.find(EOL, startPos);
26        startPos += headerName.size();
27        if (startPos < headersText.size() && startPos < endOfLinePos) {
28            return headersText.substr(startPos, endOfLinePos - startPos);
29        }
30    }
31    return "";
32}
33
34/* static */
35std::string HttpRequest::DecodeVersion(const std::string& request, std::string::size_type methodStartPos)
36{
37    if (methodStartPos >= request.size()) {
38        return "";
39    }
40
41    auto endOfLinePos = request.find(EOL, methodStartPos);
42    // the typical header is "GET /chat HTTP/1.1", where protocol version is located after the second space symbol
43    methodStartPos = request.find(' ', methodStartPos);
44    if (methodStartPos != std::string::npos) {
45        methodStartPos = request.find(' ', methodStartPos + 1);
46    }
47    if (methodStartPos != std::string::npos &&
48        methodStartPos + 1 < request.size() &&
49        methodStartPos + 1 < endOfLinePos) {
50        return request.substr(methodStartPos + 1, endOfLinePos - (methodStartPos + 1));
51    }
52    return "";
53}
54
55// request example can be found at https://www.rfc-editor.org/rfc/rfc6455#section-1.3
56/* static */
57bool HttpRequest::Decode(const std::string& request, HttpRequest& parsed)
58{
59    auto pos = request.find(GET);
60    if (pos == std::string::npos) {
61        LOGW("Handshake failed: lack of necessary info");
62        return false;
63    }
64
65    parsed.version = DecodeVersion(request, pos);
66    parsed.connection = DecodeHeader(request, CONNECTION);
67    parsed.upgrade = DecodeHeader(request, UPGRADE);
68    parsed.secWebSocketKey = DecodeHeader(request, SEC_WEBSOCKET_KEY);
69
70    return true;
71}
72
73/* static */
74std::string HttpResponse::DecodeVersion(const std::string& response, std::string::size_type versionStartPos)
75{
76    // status-line example: "HTTP/1.1 404 Not Found"
77    if (versionStartPos < response.size()) {
78        auto versionEndPos = response.find(' ', versionStartPos);
79        if (versionEndPos != std::string::npos) {
80            return response.substr(versionStartPos, versionEndPos - versionStartPos);
81        }
82    }
83    return "";
84}
85
86/* static */
87std::string HttpResponse::DecodeStatus(const std::string& response, std::string::size_type versionEndPos)
88{
89    // status-line example: "HTTP/1.1 404 Not Found"
90    if (versionEndPos < response.size() && response[versionEndPos] == ' ') {
91        auto statusStartPos = response.find_first_not_of(' ', versionEndPos);
92        if (statusStartPos != std::string::npos) {
93            auto statusEndPos = response.find(' ', statusStartPos);
94            statusEndPos = (statusEndPos == std::string::npos) ? response.find(EOL, statusStartPos) : statusEndPos;
95            if (statusEndPos != std::string::npos) {
96                return response.substr(statusStartPos, statusEndPos - statusStartPos);
97            }
98        }
99    }
100    return "";
101}
102
103// request example can be found at https://www.rfc-editor.org/rfc/rfc6455#section-1.2
104/* static */
105bool HttpResponse::Decode(const std::string& response, HttpResponse& parsed)
106{
107    // find start of status-line
108    auto versionStartPos = response.find("HTTP");
109    if (versionStartPos == std::string::npos) {
110        LOGW("Handshake failed: lack of necessary info, no status-line found");
111        return false;
112    }
113
114    parsed.version = DecodeVersion(response, versionStartPos);
115    parsed.status = DecodeStatus(response, versionStartPos + parsed.version.size());
116    parsed.connection = DecodeHeader(response, CONNECTION);
117    parsed.upgrade = DecodeHeader(response, UPGRADE);
118    parsed.secWebSocketAccept = DecodeHeader(response, SEC_WEBSOCKET_ACCEPT);
119
120    return true;
121}
122} // namespace OHOS::ArkCompiler::Toolchain
123