#include <time.h>
#include "rtmp.h"
+#include "http.h"
#include <openssl/sha.h>
#include <openssl/hmac.h>
struct info {
HMAC_CTX *ctx;
z_stream *zs;
- char *date;
int first;
int zlib;
int size;
#define AGENT "Mozilla/5.0"
-static int
-http_get(const char *url, struct info *in)
+HTTPResult
+http_get(struct http_ctx *http, const char *url, http_read_callback cb)
{
char *host, *path;
char *p1, *p2;
int port = 80;
int ssl = 0;
int hlen, flen = 0;
- int rc, i, ret = 0;
+ int rc, i;
+ int len_known;
+ HTTPResult ret = HTTPRES_OK;
struct sockaddr_in sa;
RTMPSockBuf sb;
+ http->status = -1;
+
memset(&sa, 0, sizeof(struct sockaddr_in));
sa.sin_family = AF_INET;
/* we only handle http here */
if (strncasecmp(url, "http", 4))
- return -1;
+ return HTTPRES_BAD_REQUEST;
if (url[4] == 's')
{
p1 = strchr(url+4, ':');
if (!p1 || strncmp(p1, "://", 3))
- return -1;
+ return HTTPRES_BAD_REQUEST;
host = p1+3;
path = strchr(host, '/');
{
struct hostent *hp = gethostbyname(host);
if (!hp || !hp->h_addr)
- return -1;
+ return HTTPRES_LOST_CONNECTION;
sa.sin_addr = *(struct in_addr *)hp->h_addr;
}
sa.sin_port = htons(port);
sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sb.sb_socket < 0)
- return -1;
+ return HTTPRES_LOST_CONNECTION;
i = sprintf(sb.sb_buf, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n",
path, AGENT, host, (int)(path-url+1), url);
- if (in->date[0])
- i += sprintf(sb.sb_buf+i, "If-Modified-Since: %s\r\n", in->date);
+ if (http->date[0])
+ i += sprintf(sb.sb_buf+i, "If-Modified-Since: %s\r\n", http->date);
i += sprintf(sb.sb_buf+i, "\r\n");
if (connect(sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0)
{
- ret = -1;
+ ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
send(sb.sb_socket, sb.sb_buf, i, 0);
sb.sb_timedout = false;
if (RTMPSockBuf_Fill(&sb) < 1)
{
- ret = -1;
+ ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
if (strncmp(sb.sb_buf, "HTTP/1", 6))
{
- ret = -1;
+ ret = HTTPRES_BAD_REQUEST;
goto leave;
}
p1 = strchr(sb.sb_buf, ' ');
rc = atoi(p1+1);
-
- /* not modified */
- if (rc == 304)
- goto leave;
+ http->status = rc;
+
+ if (rc >= 300) {
+ if (rc == 304)
+ {
+ ret = HTTPRES_OK_NOT_MODIFIED;
+ goto leave;
+ }
+ else if (rc == 404)
+ ret = HTTPRES_NOT_FOUND;
+ else if (rc >= 500)
+ ret = HTTPRES_SERVER_ERROR;
+ else if (rc >= 400)
+ ret = HTTPRES_BAD_REQUEST;
+ else
+ ret = HTTPRES_REDIRECTED;
+ }
p1 = memchr(sb.sb_buf, '\n', sb.sb_size);
if (!p1)
{
- ret = -1;
+ ret = HTTPRES_BAD_REQUEST;
goto leave;
}
sb.sb_start = p1+1;
else if (!strncasecmp(sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ")-1))
{
*p2 = '\0';
- strcpy(in->date, sb.sb_start+sizeof("Last-Modified: ")-1);
+ strcpy(http->date, sb.sb_start+sizeof("Last-Modified: ")-1);
}
p2 += 2;
sb.sb_size -= p2-sb.sb_start;
{
if (RTMPSockBuf_Fill(&sb) < 1)
{
- ret = -1;
+ ret = HTTPRES_LOST_CONNECTION;
goto leave;
}
}
}
- while (flen > 0 && (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
+ len_known = flen > 0;
+ while ((!len_known || flen > 0) &&
+ (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0))
{
- swfcrunch(sb.sb_start, 1, sb.sb_size, in);
- flen -= sb.sb_size;
+ cb(sb.sb_start, 1, sb.sb_size, http->data);
+ if (len_known)
+ flen -= sb.sb_size;
+ http->size += sb.sb_size;
sb.sb_size = 0;
}
+ if (flen > 0)
+ ret = HTTPRES_LOST_CONNECTION;
+
leave:
closesocket(sb.sb_socket);
return ret;
int i, got = 0, ret = 0;
unsigned int hlen;
struct info in = {0};
+ struct http_ctx http = {0};
+ HTTPResult httpres;
z_stream zs = {0};
HMAC_CTX ctx;
}
in.first = 1;
- in.date = date;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, "Genuine Adobe Flash Player 001", 30, EVP_sha256(), NULL);
inflateInit(&zs);
in.ctx = &ctx;
in.zs = &zs;
- ret = http_get(url, &in);
+ http.date = date;
+ http.data = ∈
+
+ httpres = http_get(&http, url, swfcrunch);
inflateEnd(&zs);
- if (ret)
+ if (httpres != HTTPRES_OK || httpres != HTTPRES_OK_NOT_MODIFIED)
{
- Log(LOGERROR, "%s: couldn't contact swfurl %s",
- __FUNCTION__, url);
+ ret = -1;
+ if (httpres == HTTPRES_LOST_CONNECTION)
+ Log(LOGERROR, "%s: connection lost while downloading swfurl %s",
+ __FUNCTION__, url);
+ else if (httpres == HTTPRES_NOT_FOUND)
+ Log(LOGERROR, "%s: swfurl %s not found",
+ __FUNCTION__, url);
+ else
+ Log(LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)",
+ __FUNCTION__, url, http.status);
}
else
{
--- /dev/null
+#ifndef __HTTP_H__
+#define __HTTP_H__
+/*
+ * Copyright (C) 2005-2008 Team XBMC
+ * http://www.xbmc.org
+ * Copyright (C) 2008-2009 Andrej Stepanchuk
+ * Copyright (C) 2009-2010 Howard Chu
+ * Copyright (C) 2010 Antti Ajanki
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RTMPDump; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+typedef enum {
+ HTTPRES_OK, /* result OK */
+ HTTPRES_OK_NOT_MODIFIED, /* not modified since last request */
+ HTTPRES_NOT_FOUND, /* not found */
+ HTTPRES_BAD_REQUEST, /* client error */
+ HTTPRES_SERVER_ERROR, /* server reported an error */
+ HTTPRES_REDIRECTED, /* resource has been moved */
+ HTTPRES_LOST_CONNECTION, /* connection lost while waiting for data */
+} HTTPResult;
+
+struct http_ctx {
+ char *date;
+ int size;
+ int status;
+ void *data;
+};
+
+typedef size_t (*http_read_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
+
+HTTPResult http_get(struct http_ctx *http, const char *url, http_read_callback cb);
+
+#endif