diff --git a/src/Common/Parser.cpp b/src/Common/Parser.cpp index 34fbd765..2620ba31 100644 --- a/src/Common/Parser.cpp +++ b/src/Common/Parser.cpp @@ -159,7 +159,81 @@ StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const ch } return ret; } +std::string Parser::merge_url(const string &base_url, const string &path) { + //以base_url为基础, 合并path路径生成新的url, path支持相对路径和绝对路径 + if (base_url.empty()) { + return path; + } + if (path.empty()) { + return base_url; + } + // 如果包含协议,则直接返回 + if (path.find("://") != string::npos) { + return path; + } + string protocol = "http://"; + size_t protocol_end = base_url.find("://"); + if (protocol_end != string::npos) { + protocol = base_url.substr(0, protocol_end + 3); + } + // 如果path以"//"开头,则直接拼接协议 + if (path.find("//") == 0) { + return protocol + path.substr(2); + } + string host; + size_t pos = 0; + if (protocol_end != string::npos) { + pos = base_url.find('/', protocol_end + 3); + host = base_url.substr(0, pos); + if (pos == string::npos) { + pos = base_url.size(); + } else { + pos++; + } + } + // 如果path以"/"开头,则直接拼接协议和主机 + if (path[0] == '/') { + return host + path; + } + vector path_parts; + size_t next_pos = 0; + if (!host.empty()) { + path_parts.emplace_back(host); + } + while ((next_pos = base_url.find('/', pos)) != string::npos) { + path_parts.emplace_back(base_url.substr(pos, next_pos - pos)); + pos = next_pos + 1; + } + pos = 0; + while ((next_pos = path.find('/', pos)) != string::npos) { + string part = path.substr(pos, next_pos - pos); + if (part == "..") { + if (!path_parts.empty() && !path_parts.back().empty()) { + if (path_parts.size() > 1 || protocol_end == string::npos) { + path_parts.pop_back(); + } + } + } else if (part != "." && !part.empty()) { + path_parts.emplace_back(part); + } + pos = next_pos + 1; + } + + string part = path.substr(pos); + if (part != ".." && part != "." && !part.empty()) { + path_parts.emplace_back(part); + } + stringstream final_url; + for (size_t i = 0; i < path_parts.size(); ++i) { + if (i == 0) { + final_url << path_parts[i]; + } else { + final_url << '/' << path_parts[i]; + } + } + return final_url.str(); +} void RtspUrl::parse(const string &strUrl) { auto schema = FindField(strUrl.data(), nullptr, "://"); bool is_ssl = strcasecmp(schema.data(), "rtsps") == 0; @@ -238,4 +312,4 @@ static onceToken token([](){ }); #endif -}//namespace mediakit \ No newline at end of file +}//namespace mediakit diff --git a/src/Common/Parser.h b/src/Common/Parser.h index 4e0485a2..6f312664 100644 --- a/src/Common/Parser.h +++ b/src/Common/Parser.h @@ -105,6 +105,8 @@ public: //解析?后面的参数 static StrCaseMap parseArgs(const std::string &str, const char *pair_delim = "&", const char *key_delim = "="); + static std::string merge_url(const std::string &base_url, const std::string &path); + private: std::string _strMethod; std::string _strUrl; diff --git a/src/Http/HlsParser.cpp b/src/Http/HlsParser.cpp index bd92cf41..ff9c7856 100644 --- a/src/Http/HlsParser.cpp +++ b/src/Http/HlsParser.cpp @@ -37,15 +37,7 @@ bool HlsParser::parse(const string &http_url, const string &m3u8) { if ((_is_m3u8_inner || extinf_dur != 0) && line[0] != '#') { segment.duration = extinf_dur; - if (line.find("http://") == 0 || line.find("https://") == 0) { - segment.url = line; - } else { - if (line.find("/") == 0) { - segment.url = http_url.substr(0, http_url.find("/", 8)) + line; - } else { - segment.url = http_url.substr(0, http_url.rfind("/") + 1) + line; - } - } + segment.url = Parser::merge_url(http_url, line); if (!_is_m3u8_inner) { //ts按照先后顺序排序 ts_map.emplace(index++, segment); diff --git a/src/Http/HttpClient.cpp b/src/Http/HttpClient.cpp index ab5da258..0e50fe0c 100644 --- a/src/Http/HttpClient.cpp +++ b/src/Http/HttpClient.cpp @@ -182,8 +182,8 @@ void HttpClient::onErr(const SockException &ex) { ssize_t HttpClient::onRecvHeader(const char *data, size_t len) { _parser.Parse(data); - if (_parser.Url() == "302" || _parser.Url() == "301") { - auto new_url = _parser["Location"]; + if (_parser.Url() == "302" || _parser.Url() == "301" || _parser.Url() == "303") { + auto new_url = Parser::merge_url(_url, _parser["Location"]); if (new_url.empty()) { throw invalid_argument("未找到Location字段(跳转url)"); } @@ -206,7 +206,11 @@ ssize_t HttpClient::onRecvHeader(const char *data, size_t len) { onResponseBody(data, len); } else { _total_body_size = _recved_body_size; - onResponseCompleted_l(SockException(Err_success, "success")); + if (_recved_body_size > 0) { + onResponseCompleted_l(SockException(Err_success, "success")); + }else{ + onResponseCompleted_l(SockException(Err_other, "no body")); + } } }); //后续为源源不断的body