* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * 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"
/*
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
*/
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 */
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,
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;
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 */
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);
* 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";
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 */
}
/* 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]) {
/* 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 =
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;
(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;
/*
* 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;
}
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;
"%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;
return result;
}
- result = Curl_add_custom_headers(conn, req_buffer);
+ result = Curl_add_custom_headers(conn, FALSE, req_buffer);
if(result)
return result;
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;
}
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;
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)
}
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)
/* 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 {
char *start;
/* Find the first non-space letter */
- start = header + 9;
+ start = header + 8;
while(*start && ISSPACE(*start))
start++;