Fix RTSP GET_PARAMETER empty and non-empty operation.
Test coverage included. Thanks to Massimo Callegari for the bug report
This commit is contained in:

committed by
Daniel Stenberg

parent
50b51161c9
commit
1ac168e576
@@ -1345,7 +1345,9 @@ terminate the RTSP session since it is valid to control an RTSP session over
|
|||||||
different connections. (Added in 7.20.0)
|
different connections. (Added in 7.20.0)
|
||||||
.IP CURL_RTSPREQ_GET_PARAMETER
|
.IP CURL_RTSPREQ_GET_PARAMETER
|
||||||
Retrieve a parameter from the server. By default, libcurl will automatically
|
Retrieve a parameter from the server. By default, libcurl will automatically
|
||||||
include an \fIAccept: text/parameters\fP header unless a custom one is set.
|
include a \fIContent-Type: text/parameters\fP header on all non-empty requests
|
||||||
|
unless a custom one is set. GET_PARAMETER acts just like an HTTP PUT or POST
|
||||||
|
(see \fICURL_RTSPREQ_SET_PARAMETER\fP).
|
||||||
Applications wishing to send a heartbeat message (e.g. in the presence of a
|
Applications wishing to send a heartbeat message (e.g. in the presence of a
|
||||||
server-specified timeout) should send use an empty GET_PARAMETER request.
|
server-specified timeout) should send use an empty GET_PARAMETER request.
|
||||||
(Added in 7.20.0)
|
(Added in 7.20.0)
|
||||||
|
23
lib/rtsp.c
23
lib/rtsp.c
@@ -234,8 +234,8 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
p_request = "TEARDOWN";
|
p_request = "TEARDOWN";
|
||||||
break;
|
break;
|
||||||
case RTSPREQ_GET_PARAMETER:
|
case RTSPREQ_GET_PARAMETER:
|
||||||
|
/* GET_PARAMETER's no_body status is determined later */
|
||||||
p_request = "GET_PARAMETER";
|
p_request = "GET_PARAMETER";
|
||||||
data->set.opt_no_body = FALSE;
|
|
||||||
break;
|
break;
|
||||||
case RTSPREQ_SET_PARAMETER:
|
case RTSPREQ_SET_PARAMETER:
|
||||||
p_request = "SET_PARAMETER";
|
p_request = "SET_PARAMETER";
|
||||||
@@ -321,12 +321,6 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default to text/parameters for GET_PARAMETER */
|
|
||||||
if(rtspreq == RTSPREQ_GET_PARAMETER) {
|
|
||||||
p_accept = Curl_checkheaders(data, "Accept:")?
|
|
||||||
NULL:"Accept: text/parameters\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The User-Agent string might have been allocated in url.c already, because
|
/* The User-Agent string might have been allocated in url.c already, because
|
||||||
it might have been used in the proxy connect, but if we have got a header
|
it might have been used in the proxy connect, but if we have got a header
|
||||||
with the user-agent string specified, we erase the previously made string
|
with the user-agent string specified, we erase the previously made string
|
||||||
@@ -433,7 +427,10 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(rtspreq == RTSPREQ_ANNOUNCE || rtspreq == RTSPREQ_SET_PARAMETER) {
|
if(rtspreq == RTSPREQ_ANNOUNCE ||
|
||||||
|
rtspreq == RTSPREQ_SET_PARAMETER ||
|
||||||
|
rtspreq == RTSPREQ_GET_PARAMETER) {
|
||||||
|
|
||||||
if(data->set.upload) {
|
if(data->set.upload) {
|
||||||
putsize = data->set.infilesize;
|
putsize = data->set.infilesize;
|
||||||
data->set.httpreq = HTTPREQ_PUT;
|
data->set.httpreq = HTTPREQ_PUT;
|
||||||
@@ -446,6 +443,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
data->set.httpreq = HTTPREQ_POST;
|
data->set.httpreq = HTTPREQ_POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(putsize > 0 || postsize > 0) {
|
||||||
/* As stated in the http comments, it is probably not wise to
|
/* As stated in the http comments, it is probably not wise to
|
||||||
* actually set a custom Content-Length in the headers */
|
* actually set a custom Content-Length in the headers */
|
||||||
if(!Curl_checkheaders(data, "Content-Length:")) {
|
if(!Curl_checkheaders(data, "Content-Length:")) {
|
||||||
@@ -456,7 +454,8 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rtspreq == RTSPREQ_SET_PARAMETER) {
|
if(rtspreq == RTSPREQ_SET_PARAMETER ||
|
||||||
|
rtspreq == RTSPREQ_GET_PARAMETER) {
|
||||||
if(!Curl_checkheaders(data, "Content-Type:")) {
|
if(!Curl_checkheaders(data, "Content-Type:")) {
|
||||||
result = Curl_add_bufferf(req_buffer,
|
result = Curl_add_bufferf(req_buffer,
|
||||||
"Content-Type: text/parameters\r\n");
|
"Content-Type: text/parameters\r\n");
|
||||||
@@ -475,8 +474,12 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
|
|
||||||
data->state.expect100header = FALSE; /* RTSP posts are simple/small */
|
data->state.expect100header = FALSE; /* RTSP posts are simple/small */
|
||||||
|
} else if(rtspreq == RTSPREQ_GET_PARAMETER) {
|
||||||
|
/* Check for an empty GET_PARAMETER (heartbeat) request */
|
||||||
|
data->set.httpreq = HTTPREQ_HEAD;
|
||||||
|
data->set.opt_no_body = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* RTSP never allows chunked transfer */
|
/* RTSP never allows chunked transfer */
|
||||||
data->req.forbidchunk = TRUE;
|
data->req.forbidchunk = TRUE;
|
||||||
|
@@ -65,7 +65,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
|
|||||||
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
|
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
|
||||||
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
|
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
|
||||||
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
|
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
|
||||||
test568 test569 test570 test571 test804
|
test568 test569 test570 test571 test804 test572
|
||||||
|
|
||||||
filecheck:
|
filecheck:
|
||||||
@mkdir test-place; \
|
@mkdir test-place; \
|
||||||
|
121
tests/data/test572
Normal file
121
tests/data/test572
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<testcase>
|
||||||
|
|
||||||
|
#Informational
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
RTSP
|
||||||
|
GET_PARAMETER
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data1>
|
||||||
|
RTSP/1.0 200 OK
|
||||||
|
Server: RTSPD/libcurl-test
|
||||||
|
Session: getparams-test
|
||||||
|
CSeq: 1
|
||||||
|
|
||||||
|
</data1>
|
||||||
|
|
||||||
|
<data2>
|
||||||
|
RTSP/1.0 200 OK
|
||||||
|
Server: RTSPD/libcurl-test
|
||||||
|
Session: getparams-test
|
||||||
|
Content-Type: text/parameters
|
||||||
|
Content-Length: 32
|
||||||
|
Cseq: 2
|
||||||
|
|
||||||
|
scale=enormous
|
||||||
|
speed=ludicrous
|
||||||
|
</data2>
|
||||||
|
|
||||||
|
<data3>
|
||||||
|
RTSP/1.0 200 OK
|
||||||
|
Server: RTSPD/libcurl-test
|
||||||
|
Session: getparams-test
|
||||||
|
Cseq: 3
|
||||||
|
|
||||||
|
</data3>
|
||||||
|
|
||||||
|
<data4>
|
||||||
|
RTSP/1.0 200 Okie Dokie
|
||||||
|
Server: RTSPD/libcurl-test
|
||||||
|
Session: getparams-test
|
||||||
|
Cseq: 4
|
||||||
|
Content-Length: 37
|
||||||
|
|
||||||
|
packets_received: 1000
|
||||||
|
jitter: 0.314
|
||||||
|
</data4>
|
||||||
|
<data5>
|
||||||
|
RTSP/1.0 200 OK
|
||||||
|
Server: RTSPD/libcurl-test
|
||||||
|
Session: getparams-test
|
||||||
|
CSeq: 5
|
||||||
|
Curl-private: swsclose
|
||||||
|
Informational: Empty Options Response
|
||||||
|
|
||||||
|
</data5>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
# Client-Side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
rtsp
|
||||||
|
</server>
|
||||||
|
<tool>
|
||||||
|
lib572
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<name>
|
||||||
|
RTSP GET_PARAMETER (Put/Heartbeat/Post)
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
rtsp://%HOSTIP:%RTSPPORT/572
|
||||||
|
</command>
|
||||||
|
# file written before test command runs
|
||||||
|
<file name="log/file572.txt">
|
||||||
|
scale
|
||||||
|
speed
|
||||||
|
</file>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
<verify>
|
||||||
|
<strip>
|
||||||
|
^If-Modified-Since:.*
|
||||||
|
</strip>
|
||||||
|
<protocol>
|
||||||
|
SETUP rtsp://%HOSTIP:%RTSPPORT/5720001 RTSP/1.0
|
||||||
|
CSeq: 1
|
||||||
|
Transport: Planes/Trains/Automobiles
|
||||||
|
|
||||||
|
GET_PARAMETER rtsp://%HOSTIP:%RTSPPORT/5720002 RTSP/1.0
|
||||||
|
CSeq: 2
|
||||||
|
Session: getparams-test
|
||||||
|
Content-Length: 12
|
||||||
|
Content-Type: text/parameters
|
||||||
|
|
||||||
|
scale
|
||||||
|
speed
|
||||||
|
GET_PARAMETER rtsp://%HOSTIP:%RTSPPORT/5720003 RTSP/1.0
|
||||||
|
CSeq: 3
|
||||||
|
Session: getparams-test
|
||||||
|
|
||||||
|
GET_PARAMETER rtsp://%HOSTIP:%RTSPPORT/5720004 RTSP/1.0
|
||||||
|
CSeq: 4
|
||||||
|
Session: getparams-test
|
||||||
|
Content-Length: 24
|
||||||
|
Content-Type: text/parameters
|
||||||
|
|
||||||
|
packets_received
|
||||||
|
jitter
|
||||||
|
OPTIONS rtsp://%HOSTIP:%RTSPPORT/5720005 RTSP/1.0
|
||||||
|
CSeq: 5
|
||||||
|
Session: getparams-test
|
||||||
|
|
||||||
|
</protocol>
|
||||||
|
</verify>
|
||||||
|
|
||||||
|
</testcase>
|
||||||
|
|
@@ -11,7 +11,7 @@ noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 \
|
|||||||
lib529 lib530 lib532 lib533 lib536 lib537 lib540 lib541 lib542 lib543 \
|
lib529 lib530 lib532 lib533 lib536 lib537 lib540 lib541 lib542 lib543 \
|
||||||
lib544 lib545 lib547 lib548 lib549 lib552 lib553 lib554 lib555 lib556 \
|
lib544 lib545 lib547 lib548 lib549 lib552 lib553 lib554 lib555 lib556 \
|
||||||
lib539 lib557 lib558 lib559 lib560 lib562 lib564 lib565 lib566 lib567 \
|
lib539 lib557 lib558 lib559 lib560 lib562 lib564 lib565 lib566 lib567 \
|
||||||
lib568 lib569 lib570 lib571
|
lib568 lib569 lib570 lib571 lib572
|
||||||
|
|
||||||
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
||||||
|
|
||||||
@@ -143,3 +143,5 @@ lib570_SOURCES = lib570.c $(SUPPORTFILES)
|
|||||||
|
|
||||||
lib571_SOURCES = lib571.c $(SUPPORTFILES)
|
lib571_SOURCES = lib571.c $(SUPPORTFILES)
|
||||||
|
|
||||||
|
lib572_SOURCES = lib572.c $(SUPPORTFILES)
|
||||||
|
|
||||||
|
177
tests/libtest/lib572.c
Normal file
177
tests/libtest/lib572.c
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_FCNTL_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
/* build request url */
|
||||||
|
static char *suburl(const char *base, int i)
|
||||||
|
{
|
||||||
|
return curl_maprintf("%s%.4d", base, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test GET_PARAMETER: PUT, HEARTBEAT, and POST
|
||||||
|
*/
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
CURL *curl;
|
||||||
|
int params;
|
||||||
|
FILE *paramsf = NULL;
|
||||||
|
struct_stat file_info;
|
||||||
|
char *stream_uri = NULL;
|
||||||
|
int request=1;
|
||||||
|
struct curl_slist *custom_headers=NULL;
|
||||||
|
|
||||||
|
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||||
|
fprintf(stderr, "curl_global_init() failed\n");
|
||||||
|
return TEST_ERR_MAJOR_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((curl = curl_easy_init()) == NULL) {
|
||||||
|
fprintf(stderr, "curl_easy_init() failed\n");
|
||||||
|
curl_global_cleanup();
|
||||||
|
return TEST_ERR_MAJOR_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_HEADERDATA, stdout);
|
||||||
|
test_setopt(curl, CURLOPT_WRITEDATA, stdout);
|
||||||
|
test_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_URL, URL);
|
||||||
|
|
||||||
|
/* SETUP */
|
||||||
|
if((stream_uri = suburl(URL, request++)) == NULL) {
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_STREAM_URI, stream_uri);
|
||||||
|
free(stream_uri);
|
||||||
|
stream_uri = NULL;
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_TRANSPORT, "Planes/Trains/Automobiles");
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP);
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
if(res)
|
||||||
|
goto test_cleanup;
|
||||||
|
|
||||||
|
if((stream_uri = suburl(URL, request++)) == NULL) {
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_STREAM_URI, stream_uri);
|
||||||
|
free(stream_uri);
|
||||||
|
stream_uri = NULL;
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
|
||||||
|
/* PUT style GET_PARAMETERS */
|
||||||
|
params = open("log/file572.txt", O_RDONLY);
|
||||||
|
fstat(params, &file_info);
|
||||||
|
close(params);
|
||||||
|
|
||||||
|
paramsf = fopen("log/file572.txt", "rb");
|
||||||
|
if(paramsf == NULL) {
|
||||||
|
fprintf(stderr, "can't open log/file572.txt\n");
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_GET_PARAMETER);
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_READDATA, paramsf);
|
||||||
|
test_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||||
|
test_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) file_info.st_size);
|
||||||
|
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if(res)
|
||||||
|
goto test_cleanup;
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_UPLOAD, 0L);
|
||||||
|
fclose(paramsf);
|
||||||
|
paramsf = NULL;
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
|
||||||
|
/* Heartbeat GET_PARAMETERS */
|
||||||
|
if((stream_uri = suburl(URL, request++)) == NULL) {
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_STREAM_URI, stream_uri);
|
||||||
|
free(stream_uri);
|
||||||
|
stream_uri = NULL;
|
||||||
|
|
||||||
|
fprintf(stderr, "CPC: %s:%d\n", __FILE__, __LINE__);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if(res)
|
||||||
|
goto test_cleanup;
|
||||||
|
|
||||||
|
/* POST GET_PARAMETERS */
|
||||||
|
|
||||||
|
if((stream_uri = suburl(URL, request++)) == NULL) {
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_STREAM_URI, stream_uri);
|
||||||
|
free(stream_uri);
|
||||||
|
stream_uri = NULL;
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_GET_PARAMETER);
|
||||||
|
test_setopt(curl, CURLOPT_POSTFIELDS, "packets_received\njitter\n");
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if(res)
|
||||||
|
goto test_cleanup;
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
||||||
|
|
||||||
|
/* Make sure we can do a normal request now */
|
||||||
|
if((stream_uri = suburl(URL, request++)) == NULL) {
|
||||||
|
res = TEST_ERR_MAJOR_BAD;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_STREAM_URI, stream_uri);
|
||||||
|
free(stream_uri);
|
||||||
|
stream_uri = NULL;
|
||||||
|
|
||||||
|
test_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
|
||||||
|
test_cleanup:
|
||||||
|
|
||||||
|
if(paramsf)
|
||||||
|
fclose(paramsf);
|
||||||
|
|
||||||
|
if(stream_uri)
|
||||||
|
free(stream_uri);
|
||||||
|
|
||||||
|
if(custom_headers)
|
||||||
|
curl_slist_free_all(custom_headers);
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user