ossrs / srs

SRS is a simple, high-efficiency, real-time media server supporting RTMP, WebRTC, HLS, HTTP-FLV, HTTP-TS, SRT, MPEG-DASH, and GB28181.
https://ossrs.io
MIT License
25.57k stars 5.37k forks source link

API: RTMP push streaming url parameters are separated by '#', the parameter 'param' obtained from the HTTP callback is incomplete. #3213

Closed sin-zx closed 1 year ago

sin-zx commented 2 years ago

Note: Please read FAQ before file an issue, see 2716

Note: Before asking a question, please refer to the FAQ, specifically 2716.

Description (描述)

In version 5.0, when the rtmp push stream URL contains multiple parameters separated by "#", only the first parameter is obtained in the on_publish callback. However, in Release v4.0-r0 version, all parameters can be obtained correctly.

  1. SRS Version: Release v5.0.63

  2. SRS Log:

  1. SRS Config:
listen              1935;
max_connections     10000;
daemon              off;
srs_log_level       trace;

http_server {
    enabled         on;
    listen          8080;
    dir             ./streaming_data/;
}
vhost __defaultVhost__ {
    dvr {
        enabled      on;
        dvr_apply    all;
        dvr_path     ./streaming_data/[app]/[2006][01][02]/[stream]/[timestamp].mp4;
        # dvr_plan     session;
        dvr_plan     segment;
        dvr_duration    10800;
    }
    http_remux {
        enabled     on;
        mount       [vhost]/[app]/[stream].flv;
    }
    http_hooks {
        enabled         on;
        on_publish      http://127.0.0.1:9088/api/v1/streams;
        on_unpublish    http://127.0.0.1:9088/api/v1/streams;
        on_dvr          http://127.0.0.1:9088/api/v1/dvrs;
    }
}

Replay:

> Please describe how to replay the bug? (重现Bug的步骤)

Translation:

Execute ffmpeg -re -i ./test1_out.mp4 -c copy -f flv "rtmp://127.0.0.1/live/livestream?a=1#b=2"
Check the on_publish request received by the callback server:
[2022-10-20 16:47:32][trace] post to streams, req={"server_id":"vid-563b3n4","action":"on_publish","client_id":"s418yts3","ip":"127.0.0.1","vhost":"__defaultVhost__","app":"live","tcUrl":"rtmp://127.0.0.1:1935/live","stream":"livestream","param":"?a=1","stream_url":"/live/livestream","stream_id":"vid-0359502"}
[2022-10-20 16:47:32][trace] srs on_publish: client id=s418yts3, ip=127.0.0.1, vhost=__defaultVhost__, app=live, stream=livestream, param=?a=1
127.0.0.1 - - [20/Oct/2022:16:47:32] "POST /api/v1/streams HTTP/1.1" 200 25 "" "SRS/5.0.63(Bee)"

Translation:

In the param, only the first part of the parameter "?a=1" is present.
**Expected Behavior**

Translation:

In the param, the first part of the complete parameter should be "?a=1#b=2".

TRANS_BY_GPT3

duiniuluantanqin commented 1 year ago

Execute ffmpeg -re -i ./test1_out.mp4 -c copy -f flv "rtmp://127.0.0.1/live/livestream?a=1#b=2" The rtmp push streaming URL contains multiple parameters, separated by "#". However, only the first part of the parameter "?a=1" is obtained in the on_publish callback. Expected: The param should contain the complete first part of the parameter "?a=1#b=2".

According to the definition of URI in RFC 3986, ? represents the query, and # represents the fragment. If a=1#b=2 is forcibly interpreted as a query, will it cause other compatibility issues?

After taking a look, the relevant code is in the function srs_error_t SrsHttpUri::initialize(string url) in srs_protocol_http_stack.cpp.

In this function:

  1. http_parser_parse_url is responsible for parsing the URI.
  2. query = get_uri_field(parsing_url, &hp_u, UF_QUERY); is responsible for extracting the query.

In the above code, b=2 is interpreted as a fragment instead of a query, so the callback parameter param is incomplete.

TRANS_BY_GPT3

winlinvip commented 1 year ago

http parser has this field:

  , UF_QUERY            = 4
  , UF_FRAGMENT         = 5

However, SRS only retrieves the query:

srs_error_t SrsHttpUri::initialize(string url) {
    query = get_uri_field(parsing_url, &hp_u, UF_QUERY);

It is equivalent to discarding the fragment, but the fragment should be saved.

During the callback, both the query and fragment can be placed in the param.

"param":"?token=xxx&salt=yyy#fragment"

Here it is not a query, but a param parameter, so it can include a fragment.

TRANS_BY_GPT3