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 */

Reply via email to