obs-webrtc: Improve WHIP compliance

Location header is now required. Support relative and absolute URLs
This commit is contained in:
aggresss 2023-07-24 16:20:06 +08:00 committed by Colin Edwards
parent 34e57a0496
commit c81f531edb
2 changed files with 60 additions and 27 deletions

View file

@ -290,7 +290,7 @@ bool WHIPOutput::Connect()
}
std::string read_buffer;
std::string location_header;
std::vector<std::string> location_headers;
char offer_sdp[4096] = {0};
rtcGetLocalDescription(peer_connection, offer_sdp, sizeof(offer_sdp));
@ -307,7 +307,7 @@ bool WHIPOutput::Connect()
curl_easy_setopt(c, CURLOPT_WRITEDATA, (void *)&read_buffer);
curl_easy_setopt(c, CURLOPT_HEADERFUNCTION,
curl_header_location_function);
curl_easy_setopt(c, CURLOPT_HEADERDATA, (void *)&location_header);
curl_easy_setopt(c, CURLOPT_HEADERDATA, (void *)&location_headers);
curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(c, CURLOPT_URL, endpoint_url.c_str());
curl_easy_setopt(c, CURLOPT_POST, 1L);
@ -323,7 +323,7 @@ bool WHIPOutput::Connect()
CURLcode res = curl_easy_perform(c);
if (res != CURLE_OK) {
do_log(LOG_WARNING,
do_log(LOG_ERROR,
"Connect failed: CURL returned result not CURLE_OK");
cleanup();
obs_output_signal_stop(output, OBS_OUTPUT_CONNECT_FAILED);
@ -333,7 +333,7 @@ bool WHIPOutput::Connect()
long response_code;
curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 201) {
do_log(LOG_WARNING,
do_log(LOG_ERROR,
"Connect failed: HTTP endpoint returned response code %ld",
response_code);
cleanup();
@ -342,35 +342,65 @@ bool WHIPOutput::Connect()
}
if (read_buffer.empty()) {
do_log(LOG_WARNING,
do_log(LOG_ERROR,
"Connect failed: No data returned from HTTP endpoint request");
cleanup();
obs_output_signal_stop(output, OBS_OUTPUT_CONNECT_FAILED);
return false;
}
if (location_header.empty()) {
do_log(LOG_WARNING,
long redirect_count = 0;
curl_easy_getinfo(c, CURLINFO_REDIRECT_COUNT, &redirect_count);
if (location_headers.size() < static_cast<size_t>(redirect_count) + 1) {
do_log(LOG_ERROR,
"WHIP server did not provide a resource URL via the Location header");
} else {
CURLU *h = curl_url();
curl_url_set(h, CURLUPART_URL, endpoint_url.c_str(), 0);
curl_url_set(h, CURLUPART_URL, location_header.c_str(), 0);
char *url = nullptr;
CURLUcode rc = curl_url_get(h, CURLUPART_URL, &url,
CURLU_NO_DEFAULT_PORT);
if (!rc) {
resource_url = url;
curl_free(url);
do_log(LOG_DEBUG, "WHIP Resource URL is: %s",
resource_url.c_str());
} else {
do_log(LOG_WARNING,
"Unable to process resource URL response");
}
curl_url_cleanup(h);
cleanup();
obs_output_signal_stop(output, OBS_OUTPUT_CONNECT_FAILED);
return false;
}
CURLU *url_builder = curl_url();
auto last_location_header = location_headers.back();
// If Location header doesn't start with `http` it is a relative URL.
// Construct a absolute URL using the host of the effective URL
if (last_location_header.find("http") != 0) {
char *effective_url = nullptr;
curl_easy_getinfo(c, CURLINFO_EFFECTIVE_URL, &effective_url);
if (effective_url == nullptr) {
do_log(LOG_ERROR, "Failed to build Resource URL");
cleanup();
obs_output_signal_stop(output,
OBS_OUTPUT_CONNECT_FAILED);
return false;
}
curl_url_set(url_builder, CURLUPART_URL, effective_url, 0);
curl_url_set(url_builder, CURLUPART_PATH,
last_location_header.c_str(), 0);
curl_url_set(url_builder, CURLUPART_QUERY, "", 0);
} else {
curl_url_set(url_builder, CURLUPART_URL,
last_location_header.c_str(), 0);
}
char *url = nullptr;
CURLUcode rc = curl_url_get(url_builder, CURLUPART_URL, &url,
CURLU_NO_DEFAULT_PORT);
if (rc) {
do_log(LOG_ERROR,
"WHIP server provided a invalid resource URL via the Location header");
cleanup();
obs_output_signal_stop(output, OBS_OUTPUT_CONNECT_FAILED);
return false;
}
resource_url = url;
curl_free(url);
do_log(LOG_DEBUG, "WHIP Resource URL is: %s", resource_url.c_str());
curl_url_cleanup(url_builder);
#ifdef DEBUG_SDP
do_log(LOG_DEBUG, "Answer SDP:\n%s", read_buffer.c_str());
#endif

View file

@ -45,7 +45,7 @@ static size_t curl_writefunction(char *data, size_t size, size_t nmemb,
static size_t curl_header_location_function(char *data, size_t size,
size_t nmemb, void *priv_data)
{
auto header_buffer = static_cast<std::string *>(priv_data);
auto header_buffer = static_cast<std::vector<std::string> *>(priv_data);
size_t real_size = size * nmemb;
@ -54,8 +54,11 @@ static size_t curl_header_location_function(char *data, size_t size,
if (!astrcmpi_n(data, "location: ", LOCATION_HEADER_LENGTH)) {
char *val = data + LOCATION_HEADER_LENGTH;
header_buffer->append(val, real_size - LOCATION_HEADER_LENGTH);
*header_buffer = trim_string(*header_buffer);
auto header_temp =
std::string(val, real_size - LOCATION_HEADER_LENGTH);
header_temp = trim_string(header_temp);
header_buffer->push_back(header_temp);
}
return real_size;