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_response.h"
17 #include <iostream>
18 #include <sstream>
19 
20 namespace OHOS {
21 namespace Sharing {
Stringify()22 std::string RtspResponse::Stringify()
23 {
24     std::stringstream ss;
25     ss << RTSP_VERSION << RTSP_SP << status_ << RTSP_SP;
26 
27     switch (status_) {
28         case RTSP_STATUS_OK:
29             ss << RTSP_STATUS_TO_STR(RTSP_STATUS_OK);
30             break;
31         case RTSP_STATUS_CONTINUE:
32             ss << RTSP_STATUS_TO_STR(RTSP_STATUS_CONTINUE);
33             break;
34         case RTSP_STATUS_BAD_REQUEST:
35             ss << RTSP_STATUS_TO_STR(RTSP_STATUS_BAD_REQUEST);
36             break;
37         case RTSP_STATUS_UNAUTHORIZED:
38             ss << RTSP_STATUS_TO_STR(RTSP_STATUS_UNAUTHORIZED);
39             break;
40         default:
41             ss << RTSP_STATUS_TO_STR(RTSP_STATUS_OK);
42             break;
43     }
44 
45     ss << RTSP_CRLF;
46 
47     ss << RTSP_TOKEN_CSEQ << ":" << RTSP_SP << cSeq_ << RTSP_CRLF;
48 
49     ss << RTSP_TOKEN_DATE << ":" << RTSP_SP << RtspCommon::GetRtspDate() << RTSP_CRLF;
50 
51     if (!customHeaders_.empty()) {
52         ss << customHeaders_ << RTSP_CRLF;
53     }
54     if (!session_.empty()) {
55         ss << RTSP_TOKEN_SESSION << ":" << RTSP_SP << session_;
56         if (timeout_ > 0) {
57             ss << ";timeout=" << timeout_;
58         }
59         ss << RTSP_CRLF;
60     }
61     ss << RTSP_CRLF;
62     return ss.str();
63 }
64 
Parse(const std::string &response)65 RtspError RtspResponse::Parse(const std::string &response)
66 {
67     std::vector<std::string> firstLine;
68     auto result = RtspCommon::ParseMessage(response, firstLine, tokens_, body_);
69     if (result.code != RtspErrorType::OK || firstLine.size() < 2 || tokens_.empty()) { // 2:rstp line
70         tokens_.clear();
71         body_.clear();
72         return {RtspErrorType::INVALID_MESSAGE, "invalid message"};
73     }
74 
75     // "RTSP/1.0 200 OK"
76     if (firstLine.size() < 3 || firstLine[0] != RTSP_VERSION) { // 3:rstp line
77         tokens_.clear();
78         body_.clear();
79         return {RtspErrorType::INVALID_MESSAGE, "invalid message"};
80     }
81 
82     status_ = atoi(firstLine[1].c_str());
83 
84     if (tokens_.find(RTSP_TOKEN_CSEQ) != tokens_.end()) {
85         cSeq_ = (int32_t)strtol(tokens_.at(RTSP_TOKEN_CSEQ).c_str(), nullptr, 10); // 10:unit
86     }
87 
88     if (tokens_.find(RTSP_TOKEN_DATE) != tokens_.end()) {
89         date_ = tokens_.at(RTSP_TOKEN_DATE);
90     }
91 
92     if (tokens_.find(RTSP_TOKEN_SESSION) != tokens_.end()) {
93         session_ = tokens_.at(RTSP_TOKEN_SESSION);
94         auto si = session_.find(';');
95         if (si != std::string::npos) {
96             std::string to = session_.substr(si + 1);
97             auto ti = to.find('=');
98             if (ti != std::string::npos) {
99                 auto timeoutStr = to.substr(ti + 1);
100                 timeout_ = atoi(timeoutStr.c_str());
101             }
102 
103             session_ = session_.substr(0, si);
104         }
105     }
106 
107     if (tokens_.find(RTSP_TOKEN_WWW_AUTHENTICATE) != tokens_.end()) {
108         auto authenticate = RtspCommon::Split(tokens_.at(RTSP_TOKEN_WWW_AUTHENTICATE), ", ");
109         for (auto &item : authenticate) {
110             auto separator = item.find('=');
111             if (separator != std::string::npos && item.length() >= separator + 2) { // 2:fixed size
112                 auto key = item.substr(0, separator);
113                 if (key == "Digest realm") {
114                     auto value = item.substr(separator + 2); // 2:fixed size
115                     value.pop_back();
116                     digestRealm_ = value;
117                 } else if (key == "nonce") {
118                     auto value = item.substr(separator + 2); // 2:fixed size
119                     value.pop_back();
120                     nonce_ = value;
121                 }
122             }
123         }
124     }
125 
126     if (result.info.size() > 2 && result.info.back() == '$') { // 2:fixed size
127         return result;
128     }
129 
130     return {};
131 }
132 
GetToken(const std::string &token) const133 std::string RtspResponse::GetToken(const std::string &token) const
134 {
135     if (tokens_.find(token) != tokens_.end()) {
136         return tokens_.at(token);
137     }
138 
139     return {};
140 }
141 
Stringify()142 std::string RtspResponseOptions::Stringify()
143 {
144     std::stringstream ss;
145     ss << RTSP_TOKEN_PUBLIC << ":" << RTSP_SP << publicItems_;
146     ClearCustomHeader();
147     AddCustomHeader(ss.str());
148     return RtspResponse::Stringify();
149 }
150 
Stringify()151 std::string RtspResponseDescribe::Stringify()
152 {
153     std::stringstream body;
154     for (auto &item : body_) {
155         body << item << RTSP_CRLF;
156     }
157 
158     std::stringstream ss;
159     if (!url_.empty()) {
160         ss << RTSP_TOKEN_CONTENT_BASE << ":" << RTSP_SP << url_ << RTSP_CRLF;
161     }
162     ss << RTSP_TOKEN_CONTENT_TYPE << ":" << RTSP_SP << "application/sdp" << RTSP_CRLF;
163     ss << RTSP_TOKEN_CONTENT_LENGTH << ":" << RTSP_SP << body.str().length();
164     ClearCustomHeader();
165     AddCustomHeader(ss.str());
166 
167     return RtspResponse::Stringify() + body.str();
168 }
169 
Stringify()170 std::string RtspResponseSetup::Stringify()
171 {
172     std::stringstream ss;
173 
174     ss << RTSP_TOKEN_TRANSPORT << ":" << RTSP_SP << "RTP/AVP;unicast;";
175     if (!destination_.empty()) {
176         ss << "destination=" << destination_ << ";";
177     }
178     if (!source_.empty()) {
179         ss << "source=" << source_ << ";";
180     }
181     if (minClientPort_ != 0) {
182         ss << "client_port=" << minClientPort_ << "-"
183            << (maxClientPort_ > minClientPort_ ? maxClientPort_ : (minClientPort_ + 1)) << ";";
184     }
185 
186     if (minServerPort_ != 0) {
187         ss << "server_port=" << minServerPort_ << "-"
188            << (maxServerPort_ > minServerPort_ ? maxServerPort_ : (minServerPort_ + 1)) << ";";
189     }
190     ss << RTSP_CRLF;
191     ClearCustomHeader();
192     AddCustomHeader(ss.str());
193     return RtspResponse::Stringify();
194 }
195 
Stringify()196 std::string RtspResponseGetParameter::Stringify()
197 {
198     std::stringstream body;
199     for (auto &item : body_) {
200         body << item << RTSP_CRLF;
201     }
202 
203     std::stringstream ss;
204     ss << RTSP_TOKEN_CONTENT_TYPE << ":" << RTSP_SP << "text/parameters" << RTSP_CRLF;
205     ss << RTSP_TOKEN_CONTENT_LENGTH << ":" << RTSP_SP << body.str().length();
206     ClearCustomHeader();
207     AddCustomHeader(ss.str());
208 
209     if (body.str().empty()) {
210         return RtspResponse::Stringify();
211     }
212 
213     return RtspResponse::Stringify() + body.str();
214 }
215 } // namespace Sharing
216 } // namespace OHOS