go2rtc项目中RTSP SETUP请求路径双斜杠问题分析
问题背景
在RTSP(Real Time Streaming Protocol,实时流协议)协议实现中,SETUP请求用于建立媒体流传输通道。go2rtc作为一个功能强大的摄像头流媒体应用,支持RTSP服务器功能,但在处理某些客户端的SETUP请求时,可能会遇到路径解析问题,特别是双斜杠(//)路径问题。
RTSP SETUP请求解析机制
在go2rtc的RTSP服务器实现中,SETUP请求的路径解析主要通过reqTrackID函数完成:
func reqTrackID(req *tcp.Request) int {
var s string
if req.URL.RawQuery != "" {
s = req.URL.RawQuery
} else {
s = req.URL.Path // 关键代码行
}
if i := strings.LastIndexByte(s, '='); i > 0 {
if i, err := strconv.Atoi(s[i+1:]); err == nil {
return i
}
}
return -1
}
双斜杠问题分析
问题表现
当RTSP客户端发送的SETUP请求路径包含双斜杠时,例如:
SETUP rtsp://example.com//trackID=1 RTSP/1.1
或者在某些配置不当的情况下:
SETUP //trackID=1 RTSP/1.1
问题根源
- URL路径解析:
req.URL.Path可能包含额外的斜杠 - 字符串处理:
strings.LastIndexByte(s, '=')查找等号位置时,如果路径包含双斜杠,可能导致索引计算错误 - 数字转换:
strconv.Atoi(s[i+1:])可能因为路径格式问题而失败
影响范围
| 影响方面 | 具体表现 |
|---|---|
| 媒体流建立 | SETUP请求失败,无法建立传输通道 |
| 客户端兼容性 | 某些RTSP客户端可能无法正常连接 |
| 错误处理 | 返回400 Bad Request状态码 |
解决方案
方案一:路径规范化处理
func reqTrackID(req *tcp.Request) int {
var s string
if req.URL.RawQuery != "" {
s = req.URL.RawQuery
} else {
// 规范化路径,移除多余斜杠
s = strings.Trim(req.URL.Path, "/")
s = strings.ReplaceAll(s, "//", "/")
}
if i := strings.LastIndexByte(s, '='); i > 0 {
if trackID, err := strconv.Atoi(s[i+1:]); err == nil {
return trackID
}
}
return -1
}
方案二:增强错误处理
func reqTrackID(req *tcp.Request) int {
var s string
if req.URL.RawQuery != "" {
s = req.URL.RawQuery
} else {
s = req.URL.Path
// 检查并处理双斜杠情况
if strings.Contains(s, "//") {
// 日志记录异常路径格式
log.Printf("WARN: Abnormal path format detected: %s", s)
// 尝试清理路径
s = strings.ReplaceAll(s, "//", "/")
}
}
// 支持多种格式的trackID提取
patterns := []string{"trackID=", "track=", "stream="}
for _, pattern := range patterns {
if idx := strings.LastIndex(s, pattern); idx != -1 {
start := idx + len(pattern)
if trackID, err := strconv.Atoi(s[start:]); err == nil {
return trackID
}
}
}
return -1
}
方案三:完整的路径解析器
// RTSP路径解析器结构体
type PathParser struct {
OriginalPath string
NormalizedPath string
TrackID int
IsValid bool
}
func ParseRTSPPath(path string) *PathParser {
parser := &PathParser{
OriginalPath: path,
IsValid: false,
}
// 移除开头和结尾的斜杠
normalized := strings.Trim(path, "/")
// 替换连续斜杠为单个斜杠
normalized = regexp.MustCompile(`/+`).ReplaceAllString(normalized, "/")
parser.NormalizedPath = normalized
// 尝试多种格式解析trackID
patterns := []*regexp.Regexp{
regexp.MustCompile(`trackID=(\d+)`),
regexp.MustCompile(`track=(\d+)`),
regexp.MustCompile(`stream=(\d+)`),
regexp.MustCompile(`channel=(\d+)`),
}
for _, pattern := range patterns {
if matches := pattern.FindStringSubmatch(normalized); matches != nil {
if id, err := strconv.Atoi(matches[1]); err == nil {
parser.TrackID = id
parser.IsValid = true
break
}
}
}
return parser
}
func reqTrackID(req *tcp.Request) int {
var path string
if req.URL.RawQuery != "" {
path = req.URL.RawQuery
} else {
path = req.URL.Path
}
parser := ParseRTSPPath(path)
if parser.IsValid {
return parser.TrackID
}
return -1
}
测试用例
正常情况测试
func TestReqTrackID_Normal(t *testing.T) {
req := &tcp.Request{
URL: &url.URL{Path: "trackID=1"},
}
if id := reqTrackID(req); id != 1 {
t.Errorf("Expected trackID 1, got %d", id)
}
}
双斜杠情况测试
func TestReqTrackID_DoubleSlash(t *testing.T) {
testCases := []struct {
path string
expected int
}{
{"//trackID=1", 1},
{"/trackID=2/", 2},
{"trackID=3//", 3},
{"//channel=4", 4},
}
for _, tc := range testCases {
req := &tcp.Request{URL: &url.URL{Path: tc.path}}
if id := reqTrackID(req); id != tc.expected {
t.Errorf("Path %s: expected %d, got %d", tc.path, tc.expected, id)
}
}
}
最佳实践建议
1. 输入验证和清理
// 在RTSP请求处理前添加路径验证
func validateRTSPPath(path string) string {
if path == "" {
return ""
}
// 移除多余斜杠
cleaned := strings.Trim(path, "/")
cleaned = regexp.MustCompile(`/{2,}`).ReplaceAllString(cleaned, "/")
return cleaned
}
2. 错误处理和日志记录
func (c *Conn) handleSETUP(req *tcp.Request) error {
trackID := reqTrackID(req)
if trackID == -1 {
// 记录详细的错误信息
log.Printf("ERROR: Failed to parse trackID from path: %s", req.URL.Path)
log.Printf("DEBUG: RawQuery: %s, Path: %s", req.URL.RawQuery, req.URL.Path)
return &tcp.Response{
Status: "400 Bad Request",
Header: map[string][]string{"X-Error": {"Invalid trackID format"}},
Request: req,
}
}
// ... 正常处理逻辑
}
3. 客户端兼容性处理
总结
go2rtc项目中的RTSP SETUP请求路径双斜杠问题主要源于URL路径解析时对异常格式的处理不足。通过实现路径规范化、增强错误处理和提供更好的客户端兼容性支持,可以显著提高RTSP服务器的稳定性和兼容性。
关键改进点:
- 路径预处理和规范化
- 多格式trackID解析支持
- 详细的错误日志记录
- 健壮的错误处理机制
这些改进不仅解决了双斜杠问题,还为处理其他类型的异常路径格式提供了基础,提升了整个RTSP服务器的鲁棒性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



