Imported Upstream version 7.48.0
[platform/upstream/curl.git] / lib / rtsp.c
index 3dc1490..24bf801 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
 #include "progress.h"
 #include "rtsp.h"
 #include "rawstr.h"
-#include "curl_memory.h"
 #include "select.h"
 #include "connect.h"
+#include "curl_printf.h"
 
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
+/* The last #include files should be: */
+#include "curl_memory.h"
 #include "memdebug.h"
 
 /*
@@ -81,6 +79,8 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
                                    ssize_t *nread,
                                    bool *readmore);
 
+static CURLcode rtsp_setup_connection(struct connectdata *conn);
+
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we're always _sending_ a request and thus we wait for
@@ -104,7 +104,7 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
  */
 const struct Curl_handler Curl_handler_rtsp = {
   "RTSP",                               /* scheme */
-  ZERO_NULL,                            /* setup_connection */
+  rtsp_setup_connection,                /* setup_connection */
   rtsp_do,                              /* do_it */
   rtsp_done,                            /* done */
   ZERO_NULL,                            /* do_more */
@@ -122,6 +122,19 @@ const struct Curl_handler Curl_handler_rtsp = {
   PROTOPT_NONE                          /* flags */
 };
 
+
+static CURLcode rtsp_setup_connection(struct connectdata *conn)
+{
+  struct RTSP *rtsp;
+
+  conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
+  if(!rtsp)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+
 /*
  * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not
  * want to block the application forever while receiving a stream. Therefore,
@@ -185,7 +198,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
                           CURLcode status, bool premature)
 {
   struct SessionHandle *data = conn->data;
-  struct RTSP *rtsp = data->state.proto.rtsp;
+  struct RTSP *rtsp = data->req.protop;
   CURLcode httpStatus;
   long CSeq_sent;
   long CSeq_recv;
@@ -221,7 +234,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   struct SessionHandle *data = conn->data;
   CURLcode result=CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
-  struct RTSP *rtsp;
+  struct RTSP *rtsp = data->req.protop;
   struct HTTP *http;
   Curl_send_buffer *req_buffer;
   curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
@@ -236,23 +249,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   const char *p_stream_uri = NULL;
   const char *p_transport = NULL;
   const char *p_uagent = NULL;
+  const char *p_proxyuserpwd = NULL;
+  const char *p_userpwd = NULL;
 
   *done = TRUE;
 
-  Curl_reset_reqproto(conn);
-
-  if(!data->state.proto.rtsp) {
-    /* Only allocate this struct if we don't already have it! */
-
-    rtsp = calloc(1, sizeof(struct RTSP));
-    if(!rtsp)
-      return CURLE_OUT_OF_MEMORY;
-    data->state.proto.rtsp = rtsp;
-  }
-  else {
-    rtsp = data->state.proto.rtsp;
-  }
-
   http = &(rtsp->http_wrapper);
   /* Assert that no one has changed the RTSP struct in an evil way */
   DEBUGASSERT((void *)http == (void *)rtsp);
@@ -264,11 +265,10 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
    * Since all RTSP requests are included here, there is no need to
    * support custom requests like HTTP.
    **/
-  DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST));
   data->set.opt_no_body = TRUE; /* most requests don't contain a body */
   switch(rtspreq) {
-  case RTSPREQ_NONE:
-    failf(data, "Got invalid RTSP request: RTSPREQ_NONE");
+  default:
+    failf(data, "Got invalid RTSP request");
     return CURLE_BAD_FUNCTION_ARGUMENT;
   case RTSPREQ_OPTIONS:
     p_request = "OPTIONS";
@@ -324,11 +324,10 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   if(!p_session_id &&
      (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
     failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
-          p_request ? p_request : "");
+          p_request);
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
-  /* TODO: auth? */
   /* TODO: proxy? */
 
   /* Stream URI. Default to server '*' if not specified */
@@ -340,7 +339,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   }
 
   /* Transport Header for SETUP requests */
-  p_transport = Curl_checkheaders(data, "Transport:");
+  p_transport = Curl_checkheaders(conn, "Transport:");
   if(rtspreq == RTSPREQ_SETUP && !p_transport) {
     /* New Transport: setting? */
     if(data->set.str[STRING_RTSP_TRANSPORT]) {
@@ -364,11 +363,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /* Accept Headers for DESCRIBE requests */
   if(rtspreq == RTSPREQ_DESCRIBE) {
     /* Accept Header */
-    p_accept = Curl_checkheaders(data, "Accept:")?
+    p_accept = Curl_checkheaders(conn, "Accept:")?
       NULL:"Accept: application/sdp\r\n";
 
     /* Accept-Encoding header */
-    if(!Curl_checkheaders(data, "Accept-Encoding:") &&
+    if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
        data->set.str[STRING_ENCODING]) {
       Curl_safefree(conn->allocptr.accept_encoding);
       conn->allocptr.accept_encoding =
@@ -385,18 +384,26 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
      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
      here. */
-  if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+  if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
     Curl_safefree(conn->allocptr.uagent);
     conn->allocptr.uagent = NULL;
   }
-  else if(!Curl_checkheaders(data, "User-Agent:") &&
+  else if(!Curl_checkheaders(conn, "User-Agent:") &&
           data->set.str[STRING_USERAGENT]) {
     p_uagent = conn->allocptr.uagent;
   }
 
+  /* setup the authentication headers */
+  result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE);
+  if(result)
+    return result;
+
+  p_proxyuserpwd = conn->allocptr.proxyuserpwd;
+  p_userpwd = conn->allocptr.userpwd;
+
   /* Referrer */
   Curl_safefree(conn->allocptr.ref);
-  if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
+  if(data->change.referer && !Curl_checkheaders(conn, "Referer:"))
     conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
   else
     conn->allocptr.ref = NULL;
@@ -413,7 +420,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
      (rtspreq  & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
 
     /* Check to see if there is a range set in the custom headers */
-    if(!Curl_checkheaders(data, "Range:") && data->state.range) {
+    if(!Curl_checkheaders(conn, "Range:") && data->state.range) {
       Curl_safefree(conn->allocptr.rangeline);
       conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
       p_range = conn->allocptr.rangeline;
@@ -423,11 +430,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /*
    * Sanity check the custom headers
    */
-  if(Curl_checkheaders(data, "CSeq:")) {
+  if(Curl_checkheaders(conn, "CSeq:")) {
     failf(data, "CSeq cannot be set as a custom header.");
     return CURLE_RTSP_CSEQ_ERROR;
   }
-  if(Curl_checkheaders(data, "Session:")) {
+  if(Curl_checkheaders(conn, "Session:")) {
     failf(data, "Session ID cannot be set as a custom header.");
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
@@ -442,8 +449,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     Curl_add_bufferf(req_buffer,
                      "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
                      "CSeq: %ld\r\n", /* CSeq */
-                     (p_request ? p_request : ""), p_stream_uri,
-                     rtsp->CSeq_sent);
+                     p_request, p_stream_uri, rtsp->CSeq_sent);
   if(result)
     return result;
 
@@ -467,13 +473,25 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
                             "%s" /* range */
                             "%s" /* referrer */
                             "%s" /* user-agent */
+                            "%s" /* proxyuserpwd */
+                            "%s" /* userpwd */
                             ,
                             p_transport ? p_transport : "",
                             p_accept ? p_accept : "",
                             p_accept_encoding ? p_accept_encoding : "",
                             p_range ? p_range : "",
                             p_referrer ? p_referrer : "",
-                            p_uagent ? p_uagent : "");
+                            p_uagent ? p_uagent : "",
+                            p_proxyuserpwd ? p_proxyuserpwd : "",
+                            p_userpwd ? p_userpwd : "");
+
+  /*
+   * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+   * with basic and digest, it will be freed anyway by the next request
+   */
+  Curl_safefree (conn->allocptr.userpwd);
+  conn->allocptr.userpwd = NULL;
+
   if(result)
     return result;
 
@@ -483,7 +501,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
       return result;
   }
 
-  result = Curl_add_custom_headers(conn, req_buffer);
+  result = Curl_add_custom_headers(conn, FALSE, req_buffer);
   if(result)
     return result;
 
@@ -492,13 +510,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
      rtspreq == RTSPREQ_GET_PARAMETER) {
 
     if(data->set.upload) {
-      putsize = data->set.infilesize;
+      putsize = data->state.infilesize;
       data->set.httpreq = HTTPREQ_PUT;
 
     }
     else {
-      postsize = (data->set.postfieldsize != -1)?
-        data->set.postfieldsize:
+      postsize = (data->state.infilesize != -1)?
+        data->state.infilesize:
         (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
       data->set.httpreq = HTTPREQ_POST;
     }
@@ -506,9 +524,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     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:")) {
+      if(!Curl_checkheaders(conn, "Content-Length:")) {
         result = Curl_add_bufferf(req_buffer,
-            "Content-Length: %" FORMAT_OFF_T"\r\n",
+            "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
             (data->set.upload ? putsize : postsize));
         if(result)
           return result;
@@ -516,7 +534,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 
       if(rtspreq == RTSPREQ_SET_PARAMETER ||
          rtspreq == RTSPREQ_GET_PARAMETER) {
-        if(!Curl_checkheaders(data, "Content-Type:")) {
+        if(!Curl_checkheaders(conn, "Content-Type:")) {
           result = Curl_add_bufferf(req_buffer,
               "Content-Type: text/parameters\r\n");
           if(result)
@@ -525,7 +543,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
       }
 
       if(rtspreq == RTSPREQ_ANNOUNCE) {
-        if(!Curl_checkheaders(data, "Content-Type:")) {
+        if(!Curl_checkheaders(conn, "Content-Type:")) {
           result = Curl_add_bufferf(req_buffer,
               "Content-Type: application/sdp\r\n");
           if(result)
@@ -749,7 +767,8 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
     /* Store the received CSeq. Match is verified in rtsp_done */
     int nc = sscanf(&header[4], ": %ld", &CSeq);
     if(nc == 1) {
-      data->state.proto.rtsp->CSeq_recv = CSeq; /* mark the request */
+      struct RTSP *rtsp = data->req.protop;
+      rtsp->CSeq_recv = CSeq; /* mark the request */
       data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
     }
     else {
@@ -761,7 +780,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
     char *start;
 
     /* Find the first non-space letter */
-    start = header + 9;
+    start = header + 8;
     while(*start && ISSPACE(*start))
       start++;