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