cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: CURL_RTSPREQ_GET_PARAMETER timeout

From: Christopher Conroy <cconroy_at_gmail.com>
Date: Wed, 24 Mar 2010 01:41:17 -0400

On Tue, Mar 23, 2010 at 12:26 PM, Massimo Callegari
<massimocallegari_at_yahoo.it> wrote:
> Hello Christopher,
> I've written a small program for you to reproduce the mentioned issue.
> Just download and compile the latest live555 version and test this with it.
> It seems that libcurl always expect a body from a GET_PARAMETER request, but
> usually an empty GP should work as keepalive for a RTSP connection.
> Please let me know if you need anything else.
>
> Many thanks !
> Massimo

I believe I have the code fixed now. GET_PARAMETER was all sorts of
wrong. Now you should be able to do empty and non empty GET_PARAMETER
requests. Your test works with my local live555 server with this
patch. libtest572 adds coverage for this.

Subject: [PATCH] Fix GET_PARAMETER empty and non-empty operation. Test
coverage included. Thanks to Massimo Callegari for the bug report

---
 docs/libcurl/curl_easy_setopt.3 |    4 +-
 lib/rtsp.c                      |   63 +++++++-------
 tests/data/Makefile.am          |    2 +-
 tests/data/test572              |  121 ++++++++++++++++++++++++++
 tests/libtest/Makefile.inc      |    4 +-
 tests/libtest/lib572.c          |  177 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 338 insertions(+), 33 deletions(-)
 create mode 100644 tests/data/test572
 create mode 100644 tests/libtest/lib572.c
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index a9d8ad4..7981e7a 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1346,7 +1346,9 @@ terminate the RTSP session since it is valid to
control an RTSP session over
 different connections.  (Added in 7.20.0)
 .IP CURL_RTSPREQ_GET_PARAMETER
 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
 server-specified timeout) should send use an empty GET_PARAMETER request.
 (Added in 7.20.0)
diff --git a/lib/rtsp.c b/lib/rtsp.c
index 8aaac89..961d064 100644
--- a/lib/rtsp.c
+++ b/lib/rtsp.c
@@ -235,8 +235,8 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
     p_request = "TEARDOWN";
     break;
   case RTSPREQ_GET_PARAMETER:
+    /* GET_PARAMETER's no_body status is determined later */
     p_request = "GET_PARAMETER";
-    data->set.opt_no_body = FALSE;
     break;
   case RTSPREQ_SET_PARAMETER:
     p_request = "SET_PARAMETER";
@@ -322,12 +322,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
      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
@@ -434,7 +428,10 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
   if(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) {
       putsize = data->set.infilesize;
       data->set.httpreq = HTTPREQ_PUT;
@@ -447,38 +444,44 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
       data->set.httpreq = HTTPREQ_POST;
     }
-    /* As stated in the http comments, it is probably not wise to
-     * actually set a custom Content-Length in the headers */
-    if(!Curl_checkheaders(data, "Content-Length:")) {
-      result = Curl_add_bufferf(req_buffer,
-                                "Content-Length: %" FORMAT_OFF_T"\r\n",
-                                (data->set.upload ? putsize : postsize));
-      if(result)
-        return result;
-    }
-
-    if(rtspreq == RTSPREQ_SET_PARAMETER) {
-      if(!Curl_checkheaders(data, "Content-Type:")) {
+    if(putsize > 0 || postsize > 0) {
+      /* As stated in the http comments, it is probably not wise to
+       * actually set a custom Content-Length in the headers */
+      if(!Curl_checkheaders(data, "Content-Length:")) {
         result = Curl_add_bufferf(req_buffer,
-                                  "Content-Type: text/parameters\r\n");
+            "Content-Length: %" FORMAT_OFF_T"\r\n",
+            (data->set.upload ? putsize : postsize));
         if(result)
           return result;
       }
-    }
-    if(rtspreq == RTSPREQ_ANNOUNCE) {
-      if(!Curl_checkheaders(data, "Content-Type:")) {
-        result = Curl_add_bufferf(req_buffer,
-                                  "Content-Type: application/sdp\r\n");
-        if(result)
-          return result;
+      if(rtspreq == RTSPREQ_SET_PARAMETER ||
+         rtspreq == RTSPREQ_GET_PARAMETER) {
+        if(!Curl_checkheaders(data, "Content-Type:")) {
+          result = Curl_add_bufferf(req_buffer,
+              "Content-Type: text/parameters\r\n");
+          if(result)
+            return result;
+        }
+      }
+
+      if(rtspreq == RTSPREQ_ANNOUNCE) {
+        if(!Curl_checkheaders(data, "Content-Type:")) {
+          result = Curl_add_bufferf(req_buffer,
+              "Content-Type: application/sdp\r\n");
+          if(result)
+            return result;
+        }
       }
-    }
     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 */
   data->req.forbidchunk = TRUE;
   /* Finish the request buffer */
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 1878e01..6f2c090 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -65,7 +65,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20
test27 test34 test46	   \
  test564 test1101 test1102 test1103 test1104 test299 test310 test311       \
  test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
  test1107 test1108 test1109 test1110 test1111 test1112 test129 test567     \
- test568 test569 test570 test571 test804
+ test568 test569 test570 test571 test804 test572
 filecheck:
 	@mkdir test-place; \
diff --git a/tests/data/test572 b/tests/data/test572
new file mode 100644
index 0000000..c06e531
--- /dev/null
+++ b/tests/data/test572
@@ -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>
+
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 5a5a0ea..4dc8615 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -11,7 +11,7 @@ noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504
lib505 lib506	\
   lib529 lib530 lib532 lib533 lib536 lib537 lib540 lib541 lib542 lib543 \
   lib544 lib545 lib547 lib548 lib549 lib552 lib553 lib554 lib555 lib556 \
   lib539 lib557 lib558 lib559 lib560 lib562 lib564 lib565 lib566 lib567 \
-  lib568 lib569 lib570 lib571
+  lib568 lib569 lib570 lib571 lib572
 lib500_SOURCES = lib500.c $(SUPPORTFILES)
@@ -143,3 +143,5 @@ lib570_SOURCES = lib570.c $(SUPPORTFILES)
 lib571_SOURCES = lib571.c $(SUPPORTFILES)
+lib572_SOURCES = lib572.c $(SUPPORTFILES)
+
diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c
new file mode 100644
index 0000000..8286487
--- /dev/null
+++ b/tests/libtest/lib572.c
@@ -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;
+}
+
-- 
1.6.0.4


-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html

Received on 2010-03-24