1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 "rtsp_common.h"
17 #include <regex>
18 #include "common/media_log.h"
19 #include "utils/crypto.h"
20
21 namespace OHOS {
22 namespace Sharing {
GetRtspDate()23 std::string RtspCommon::GetRtspDate()
24 {
25 time_t now = time(nullptr);
26 if (now <= 0) {
27 return {};
28 }
29 struct tm *t = gmtime(&now);
30 if (t == nullptr) {
31 return {};
32 }
33 char buf[32] = {0};
34 if (strftime(buf, 128, "%a, %b %d %Y %H:%M:%S GMT", t) < 0) { // 128:fixed size
35 return {};
36 }
37 return buf;
38 }
39
Split(const std::string &str, const std::string &delimiter)40 std::vector<std::string> RtspCommon::Split(const std::string &str, const std::string &delimiter)
41 {
42 std::regex reg{delimiter};
43 return {std::sregex_token_iterator(str.begin(), str.end(), reg, -1), std::sregex_token_iterator()};
44 }
45
SplitParameter(std::list<std::string> &lines, std::list<std::pair<std::string, std::string>> ¶ms)46 void RtspCommon::SplitParameter(std::list<std::string> &lines, std::list<std::pair<std::string, std::string>> ¶ms)
47 {
48 for (auto &line : lines) {
49 if (line.size() > 3) { // 3:fixed size
50 auto index = line.find_first_of(':');
51 if (index != 0 && index + 1 != line.length()) {
52 auto token = RtspCommon::Trim(line.substr(0, index));
53 auto value = RtspCommon::Trim(line.substr(index + 1));
54 params.emplace_back(token, value);
55 }
56 }
57 }
58 }
59
VerifyMethod(const std::string &method)60 bool RtspCommon::VerifyMethod(const std::string &method)
61 {
62 return method == RTSP_METHOD_OPTIONS || method == RTSP_METHOD_DESCRIBE || method == RTSP_METHOD_ANNOUNCE ||
63 method == RTSP_METHOD_SETUP || method == RTSP_METHOD_PLAY || method == RTSP_METHOD_PAUSE ||
64 method == RTSP_METHOD_TEARDOWN || method == RTSP_METHOD_GET_PARAMETER ||
65 method == RTSP_METHOD_SET_PARAMETER || method == RTSP_METHOD_REDIRECT || method == RTSP_METHOD_RECORD;
66 }
67
Trim(const std::string &str)68 std::string RtspCommon::Trim(const std::string &str)
69 {
70 if (str.empty())
71 return str;
72 auto s = str.find_first_not_of(' ');
73 auto e = str.find_last_not_of(' ');
74 if (s == std::string::npos || e == std::string::npos) {
75 return str;
76 }
77
78 return str.substr(s, e + 1 - s);
79 }
80
ParseMessage(const std::string &message, std::vector<std::string> &firstLine, std::unordered_map<std::string, std::string> &header, std::list<std::string> &body)81 RtspError RtspCommon::ParseMessage(const std::string &message, std::vector<std::string> &firstLine,
82 std::unordered_map<std::string, std::string> &header, std::list<std::string> &body)
83 {
84 auto messageV = RtspCommon::Split(message, std::string(RTSP_CRLF) + RTSP_CRLF);
85 auto headers = messageV[0];
86
87 std::vector<std::string> lines = RtspCommon::Split(headers, RTSP_CRLF);
88 if (lines.size() < 2) { // 2:fixed size
89 return {RtspErrorType::INVALID_MESSAGE, "invalid message"};
90 }
91
92 firstLine = RtspCommon::Split(lines[0], RTSP_SP);
93
94 // parse header
95 for (int32_t i = 1; i < (int32_t)lines.size(); ++i) {
96 if (lines[i].size() > 3) { // 3:fixed size
97 auto index = lines[i].find_first_of(':');
98 if (index != 0 && index != std::string::npos && index + 1 != lines[i].length()) {
99 auto token = RtspCommon::Trim(lines[i].substr(0, index));
100 auto value = RtspCommon::Trim(lines[i].substr(index + 1));
101 if (token == "WWW-Authenticate" && value.find("Digest") == std::string::npos) {
102 continue;
103 }
104 header.emplace(token, value);
105 }
106 }
107 }
108
109 // parse body
110 if (messageV.size() == 2 && header.find(RTSP_TOKEN_CONTENT_TYPE) != header.end() && // 2:fixed size
111 header.find(RTSP_TOKEN_CONTENT_LENGTH) != header.end()) {
112 int32_t length = atoi(header.at(RTSP_TOKEN_CONTENT_LENGTH).c_str());
113 if (length == 0) {
114 SHARING_LOGW("Content-Length == 0.");
115 return {};
116 }
117
118 if (length > (int32_t)messageV[1].length()) {
119 SHARING_LOGE("invalid body: Content-Length: %{public}d, body length: %{public}zu\n!", length,
120 messageV[1].length());
121 return {RtspErrorType::INCOMPLETE_MESSAGE, "body length < Content-Length"};
122 }
123
124 if (header.at(RTSP_TOKEN_CONTENT_TYPE).compare(0, 5, "text/") != 0 && // 5:fixed size
125 header.at(RTSP_TOKEN_CONTENT_TYPE) != "application/sdp") {
126 return {RtspErrorType::INVALID_MESSAGE, "unsupported content"};
127 }
128
129 auto bodyStr = messageV[1].substr(0, length);
130 auto bodyVec = RtspCommon::Split(bodyStr, RTSP_CRLF);
131 for (auto &item : bodyVec) {
132 if (!item.empty()) {
133 body.emplace_back(item);
134 }
135 }
136 } else {
137 if (messageV.size() > 1) {
138 SHARING_LOGW("may packet splicing.");
139 std::string splicingPart;
140 for (int32_t i = 1; i < messageV.size(); ++i) {
141 splicingPart += messageV[i];
142 if (i != messageV.size() - 1) {
143 splicingPart += "\r\n\r\n";
144 }
145 }
146 splicingPart += '$';
147 SHARING_LOGW("splicing \n%{public}s!", splicingPart.c_str());
148 return {RtspErrorType::OK, splicingPart};
149 }
150 }
151
152 return {};
153 }
GenerateAuthorization(const std::string &username, const std::string &realm, const std::string &password, const std::string &nonce, const std::string &method, const std::string &url)154 std::string RtspCommon::GenerateAuthorization(const std::string &username, const std::string &realm,
155 const std::string &password, const std::string &nonce,
156 const std::string &method, const std::string &url)
157 {
158 auto urpMD5 = GetMD5(username + ':' + realm + ':' + password);
159 auto pmuMD5 = GetMD5(method + url);
160 auto responseMD5 = GetMD5(urpMD5 + ':' + nonce + ':' + pmuMD5);
161 auto authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce +
162 "\", uri=\"" + url + "\", response=\"" + responseMD5 + "\"";
163 return authorization;
164 }
165 } // namespace Sharing
166 } // namespace OHOS