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