Source: rtmpdump
Version: 2.4~20110711.gitc28f1bab-1
Severity: wishlist
Tags: patch
Hi!
On Launchpad [1] there's a patch from Daniel Burr which adds the support for
HTTP proxies.
I'm attaching here the diff file, we might consider to refresh and apply it
against the latest 2.4~20110711.gitc28f1bab release with our next upload.
Cheers!
[1] https://launchpad.net/bugs/747517
-- System Information:
Debian Release: wheezy/sid
APT prefers testing
APT policy: (990, 'testing'), (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 3.0.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=it_IT.utf8, LC_CTYPE=it_IT.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Index: rtmpsuck.c
===================================================================
--- rtmpsuck.c (revision 550)
+++ rtmpsuck.c (working copy)
@@ -249,18 +249,18 @@
r2 = malloc(len+1);
memcpy(r2, r1, len);
r2[len] = '\0';
- server->rc.Link.hostname.av_val = r2;
+ server->rc.Link.server.host.av_val = r2;
r1 = strrchr(r2, ':');
if (r1)
{
- server->rc.Link.hostname.av_len = r1 - r2;
+ server->rc.Link.server.host.av_len = r1 - r2;
*r1++ = '\0';
- server->rc.Link.port = atoi(r1);
+ server->rc.Link.server.port = atoi(r1);
}
else
{
- server->rc.Link.hostname.av_len = len;
- server->rc.Link.port = 1935;
+ server->rc.Link.server.host.av_len = len;
+ server->rc.Link.server.port = 1935;
}
}
pval.av_val = NULL;
@@ -977,7 +977,7 @@
server->f_cur = NULL;
free(buf);
/* Should probably be done by RTMP_Close() ... */
- server->rc.Link.hostname.av_val = NULL;
+ server->rc.Link.server.host.av_val = NULL;
server->rc.Link.tcUrl.av_val = NULL;
server->rc.Link.swfUrl.av_val = NULL;
server->rc.Link.pageUrl.av_val = NULL;
Index: rtmpgw.c
===================================================================
--- rtmpgw.c (revision 550)
+++ rtmpgw.c (working copy)
@@ -944,6 +944,7 @@
break;
case 'S':
STR2AVAL(req->sockshost, arg);
+ break;
case 'q':
RTMP_debuglevel = RTMP_LOGCRIT;
break;
Index: librtmp/rtmp.c
===================================================================
--- librtmp/rtmp.c (revision 550)
+++ librtmp/rtmp.c (working copy)
@@ -85,6 +85,12 @@
RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
} RTMPTCmd;
+typedef enum {
+ RTMP_HTTP_WRONG_CODE = -2,
+ RTMP_HTTP_BAD = -1,
+ RTMP_HTTP_OK = 0
+} RTMPHTTPstatus;
+
static int DumpMetaData(AMFObject *obj);
static int HandShake(RTMP *r, int FP9HandShake);
static int SocksNegotiate(RTMP *r);
@@ -116,7 +122,7 @@
static void DecodeTEA(AVal *key, AVal *text);
static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
-static int HTTP_read(RTMP *r, int fill);
+static RTMPHTTPstatus HTTP_read(RTMP *r, int fill);
#ifndef _WIN32
static int clk_tck;
@@ -338,6 +344,8 @@
int dStart,
int dStop, int bLiveStream, long int timeout)
{
+ char* http_proxy = getenv("http_proxy");
+
RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
@@ -387,20 +395,45 @@
if (socksport)
hostname[socksport - sockshost->av_val] = '\0';
- r->Link.sockshost.av_val = hostname;
- r->Link.sockshost.av_len = strlen(hostname);
+ r->Link.socksProxy.host.av_val = hostname;
+ r->Link.socksProxy.host.av_len = strlen(hostname);
- r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
- RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
- r->Link.socksport);
+ r->Link.socksProxy.port = socksport ? atoi(socksport + 1) : 1080;
+ RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.socksProxy.host.av_val,
+ r->Link.socksProxy.port);
}
else
{
- r->Link.sockshost.av_val = NULL;
- r->Link.sockshost.av_len = 0;
- r->Link.socksport = 0;
+ r->Link.socksProxy.host.av_val = NULL;
+ r->Link.socksProxy.host.av_len = 0;
+ r->Link.socksProxy.port = 0;
}
+ if(http_proxy)
+ {
+ /* skip protocol, e.g. http:// */
+ char* str = strstr(http_proxy, "://");
+ if(str) http_proxy = str + 3;
+
+ const char *httpport = strchr(http_proxy, ':');
+ char *hostname = strdup(http_proxy);
+
+ if (httpport)
+ hostname[httpport - http_proxy] = '\0';
+ r->Link.httpProxy.host.av_val = hostname;
+ r->Link.httpProxy.host.av_len = strlen(hostname);
+
+ r->Link.httpProxy.port = httpport ? atoi(httpport + 1) : 80;
+ RTMP_Log(RTMP_LOGDEBUG, "Connecting via HTTP proxy: %s:%d", r->Link.httpProxy.host.av_val,
+ r->Link.httpProxy.port);
+ }
+ else
+ {
+ r->Link.httpProxy.host.av_val = NULL;
+ r->Link.httpProxy.host.av_len = 0;
+ r->Link.httpProxy.port = 0;
+ }
+
if (tcUrl && tcUrl->av_len)
r->Link.tcUrl = *tcUrl;
if (swfUrl && swfUrl->av_len)
@@ -427,18 +460,18 @@
r->Link.timeout = timeout;
r->Link.protocol = protocol;
- r->Link.hostname = *host;
- r->Link.port = port;
+ r->Link.server.host = *host;
+ r->Link.server.port = port;
r->Link.playpath = *playpath;
- if (r->Link.port == 0)
+ if (r->Link.server.port == 0)
{
if (protocol & RTMP_FEATURE_SSL)
- r->Link.port = 443;
+ r->Link.server.port = 443;
else if (protocol & RTMP_FEATURE_HTTP)
- r->Link.port = 80;
+ r->Link.server.port = 80;
else
- r->Link.port = 1935;
+ r->Link.server.port = 1935;
}
}
@@ -455,7 +488,7 @@
int omisc;
char *use;
} options[] = {
- { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
+ { AVC("socks"), OFF(Link.socksProxy.host), OPT_STR, 0,
"Use the specified SOCKS proxy" },
{ AVC("app"), OFF(Link.app), OPT_STR, 0,
"Name of target app on server" },
@@ -661,11 +694,11 @@
*ptr = '\0';
len = strlen(url);
- ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
+ ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.server.host,
&port, &r->Link.playpath0, &r->Link.app);
if (!ret)
return ret;
- r->Link.port = port;
+ r->Link.server.port = port;
r->Link.playpath = r->Link.playpath0;
while (ptr) {
@@ -724,14 +757,14 @@
}
else
{
- len = r->Link.hostname.av_len + r->Link.app.av_len +
+ len = r->Link.server.host.av_len + r->Link.app.av_len +
sizeof("rtmpte://:65535/");
r->Link.tcUrl.av_val = malloc(len);
r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
"%s://%.*s:%d/%.*s",
RTMPProtocolStringsLower[r->Link.protocol],
- r->Link.hostname.av_len, r->Link.hostname.av_val,
- r->Link.port,
+ r->Link.server.host.av_len, r->Link.server.host.av_val,
+ r->Link.server.port,
r->Link.app.av_len, r->Link.app.av_val);
r->Link.lFlags |= RTMP_LF_FTCU;
}
@@ -748,14 +781,14 @@
(unsigned char *)r->Link.SWFHash, r->Link.swfAge);
#endif
- if (r->Link.port == 0)
+ if (r->Link.server.port == 0)
{
if (r->Link.protocol & RTMP_FEATURE_SSL)
- r->Link.port = 443;
+ r->Link.server.port = 443;
else if (r->Link.protocol & RTMP_FEATURE_HTTP)
- r->Link.port = 80;
+ r->Link.server.port = 80;
else
- r->Link.port = 1935;
+ r->Link.server.port = 1935;
}
return TRUE;
}
@@ -816,7 +849,7 @@
return FALSE;
}
- if (r->Link.socksport)
+ if (r->Link.socksProxy.port)
{
RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
if (!SocksNegotiate(r))
@@ -902,24 +935,26 @@
RTMP_Connect(RTMP *r, RTMPPacket *cp)
{
struct sockaddr_in service;
- if (!r->Link.hostname.av_len)
+ RTMPSockInfo* sock;
+
+ if (!r->Link.server.host.av_len)
return FALSE;
memset(&service, 0, sizeof(struct sockaddr_in));
service.sin_family = AF_INET;
- if (r->Link.socksport)
- {
+ if (r->Link.socksProxy.port)
/* Connect via SOCKS */
- if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
- return FALSE;
- }
+ sock = &r->Link.socksProxy;
+ else if (r->Link.httpProxy.port)
+ /* Connect via HTTP proxy */
+ sock = &r->Link.httpProxy;
else
- {
/* Connect directly */
- if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
+ sock = &r->Link.server;
+
+ if (!add_addr_info(&service, &sock->host, sock->port))
return FALSE;
- }
if (!RTMP_Connect0(r, (struct sockaddr *)&service))
return FALSE;
@@ -936,14 +971,14 @@
struct sockaddr_in service;
memset(&service, 0, sizeof(struct sockaddr_in));
- add_addr_info(&service, &r->Link.hostname, r->Link.port);
+ add_addr_info(&service, &r->Link.server.host, r->Link.server.port);
addr = htonl(service.sin_addr.s_addr);
{
char packet[] = {
4, 1, /* SOCKS 4, connect */
- (r->Link.port >> 8) & 0xFF,
- (r->Link.port) & 0xFF,
+ (r->Link.server.port >> 8) & 0xFF,
+ (r->Link.server.port) & 0xFF,
(char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
(char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
0
@@ -1281,7 +1319,10 @@
return 0;
}
}
- HTTP_read(r, 0);
+ if(HTTP_read(r, 0) == RTMP_HTTP_WRONG_CODE) {
+ RTMP_Close(r);
+ return 0;
+ }
}
if (r->m_resplen && !r->m_sb.sb_size)
RTMPSockBuf_Fill(&r->m_sb);
@@ -3634,17 +3675,32 @@
HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
{
char hbuf[512];
- int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
+ char sbuf[512];
+
+ if(r->Link.httpProxy.port) {
+ /* Provide HTTP URL when using proxy */
+ snprintf(sbuf, sizeof(sbuf), "http://%.*s:%d",
+ r->Link.server.host.av_len, r->Link.server.host.av_val,
+ r->Link.server.port);
+ } else {
+ sbuf[0] = '\0';
+ }
+
+ int hlen = snprintf(hbuf, sizeof(hbuf), "POST %s/%s%s/%d HTTP/1.1\r\n"
"Host: %.*s:%d\r\n"
"Accept: */*\r\n"
"User-Agent: Shockwave Flash\n"
"Connection: Keep-Alive\n"
"Cache-Control: no-cache\r\n"
"Content-type: application/x-fcs\r\n"
- "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
+ "Content-length: %d\r\n\r\n",
+ sbuf,
+ RTMPT_cmds[cmd],
r->m_clientID.av_val ? r->m_clientID.av_val : "",
- r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
- r->Link.port, len);
+ r->m_msgCounter,
+ r->Link.server.host.av_len, r->Link.server.host.av_val,
+ r->Link.server.port,
+ len);
RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
r->m_msgCounter++;
@@ -3652,29 +3708,42 @@
return hlen;
}
-static int
+static RTMPHTTPstatus
HTTP_read(RTMP *r, int fill)
{
char *ptr;
int hlen;
+ int type;
if (fill)
RTMPSockBuf_Fill(&r->m_sb);
if (r->m_sb.sb_size < 144)
- return -1;
- if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
- return -1;
- ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
+ return RTMP_HTTP_BAD;
+ if (strncmp(r->m_sb.sb_start, "HTTP/1.1 ", 9)) {
+ return RTMP_HTTP_BAD;
+ }
+ ptr = r->m_sb.sb_start + 9;
+ if(!((ptr[0] & 0xf0) == 0x30 &&
+ (ptr[1] & 0xf0) == 0x30 &&
+ (ptr[2] & 0xf0) == 0x30 &&
+ ptr[3] == ' ')) {
+ return RTMP_HTTP_BAD;
+ }
+ type = atoi(ptr);
+ if(type != 200) { /* 200 is HTTP OK */
+ RTMP_Log(RTMP_LOGDEBUG, "Wrong HTTP code (got %i expected 200):\n%.*s", type, r->m_sb.sb_size, r->m_sb.sb_start);
+ return RTMP_HTTP_WRONG_CODE;
+ }
while ((ptr = strstr(ptr, "Content-"))) {
if (!strncasecmp(ptr+8, "length:", 7)) break;
ptr += 8;
}
if (!ptr)
- return -1;
+ return RTMP_HTTP_BAD;
hlen = atoi(ptr+16);
ptr = strstr(ptr+16, "\r\n\r\n");
if (!ptr)
- return -1;
+ return RTMP_HTTP_BAD;
ptr += 4;
r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
r->m_sb.sb_start = ptr;
@@ -3685,7 +3754,7 @@
r->m_clientID.av_len = hlen;
r->m_clientID.av_val = malloc(hlen+1);
if (!r->m_clientID.av_val)
- return -1;
+ return RTMP_HTTP_BAD;
r->m_clientID.av_val[0] = '/';
memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
r->m_clientID.av_val[hlen] = 0;
@@ -3698,7 +3767,7 @@
r->m_sb.sb_start++;
r->m_sb.sb_size--;
}
- return 0;
+ return RTMP_HTTP_OK;
}
#define MAX_IGNORED_FRAMES 50
Index: librtmp/rtmp.h
===================================================================
--- librtmp/rtmp.h (revision 550)
+++ librtmp/rtmp.h (working copy)
@@ -114,6 +114,12 @@
void *sb_ssl;
} RTMPSockBuf;
+ typedef struct RTMPSockInfo
+ {
+ AVal host;
+ unsigned short port;
+ } RTMPSockInfo;
+
void RTMPPacket_Reset(RTMPPacket *p);
void RTMPPacket_Dump(RTMPPacket *p);
int RTMPPacket_Alloc(RTMPPacket *p, int nSize);
@@ -123,8 +129,9 @@
typedef struct RTMP_LNK
{
- AVal hostname;
- AVal sockshost;
+ RTMPSockInfo server;
+ RTMPSockInfo socksProxy;
+ RTMPSockInfo httpProxy;
AVal playpath0; /* parsed from URL */
AVal playpath; /* passed in explicitly */
@@ -155,9 +162,6 @@
int protocol;
int timeout; /* connection timeout in seconds */
- unsigned short socksport;
- unsigned short port;
-
#ifdef CRYPTO
#define RTMP_SWF_HASHLEN 32
void *dh; /* for encryption */