aboutsummaryrefslogtreecommitdiffstats
path: root/ffserver.c
diff options
context:
space:
mode:
authorPhilip Gladstone <philipjsg@users.sourceforge.net>2002-05-10 02:20:27 +0000
committerPhilip Gladstone <philipjsg@users.sourceforge.net>2002-05-10 02:20:27 +0000
commit7434ba6d53b9a8858a6f965d9a4e60b5eb1316fe (patch)
treea03fff81df1846e130f6b404867629779578a844 /ffserver.c
parent8d1335ea2b77d71a7f17db47f65b43758ea56a2f (diff)
downloadffmpeg-7434ba6d53b9a8858a6f965d9a4e60b5eb1316fe.tar.gz
* Improve logging -- now actually gives you the number of bytes sent
* Print out the logging information that comes from WMP (you'd be suprised what it sends! * Fix a remotely exploitable buffer overflow (argh!) * Add support for automatically serving up .asx files. It generates an automatic redirect to the associated .asf file (with the same parameters). I guess that someone who understands the realaudio equivalent could hack that it as well. Originally committed as revision 482 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'ffserver.c')
-rw-r--r--ffserver.c154
1 files changed, 134 insertions, 20 deletions
diff --git a/ffserver.c b/ffserver.c
index c5397b1834..5567fe11e7 100644
--- a/ffserver.c
+++ b/ffserver.c
@@ -93,6 +93,10 @@ typedef struct HTTPContext {
struct FFStream *stream;
AVFormatContext fmt_ctx;
int last_packet_sent; /* true if last data packet was sent */
+ int suppress_log;
+ char protocol[16];
+ char method[16];
+ char url[128];
UINT8 buffer[IOBUFFER_MAX_SIZE];
UINT8 pbuffer[PACKET_MAX_SIZE];
} HTTPContext;
@@ -161,11 +165,34 @@ static void http_log(char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- if (logfile)
+ if (logfile) {
vfprintf(logfile, fmt, ap);
+ fflush(logfile);
+ }
va_end(ap);
}
+static void log_connection(HTTPContext *c)
+{
+ char buf1[32], buf2[32], *p;
+ time_t ti;
+
+ if (c->suppress_log)
+ return;
+
+ /* XXX: reentrant function ? */
+ p = inet_ntoa(c->from_addr.sin_addr);
+ strcpy(buf1, p);
+ ti = time(NULL);
+ p = ctime(&ti);
+ strcpy(buf2, p);
+ p = buf2 + strlen(p) - 1;
+ if (*p == '\n')
+ *p = '\0';
+ http_log("%s - - [%s] \"%s %s %s\" %d %lld\n",
+ buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
+}
+
/* main loop of the http server */
static int http_server(struct sockaddr_in my_addr)
{
@@ -264,6 +291,7 @@ static int http_server(struct sockaddr_in my_addr)
c = *cp;
if (handle_http (c, cur_time) < 0) {
/* close and free the connection */
+ log_connection(c);
close(c->fd);
if (c->fmt_in)
av_close_input_file(c->fmt_in);
@@ -408,11 +436,13 @@ static int handle_http(HTTPContext *c, long cur_time)
return 0;
}
+
/* parse http request and prepare header */
static int http_parse_request(HTTPContext *c)
{
char *p;
int post;
+ int doing_asx;
char cmd[32];
char info[1024], *filename;
char url[1024], *q;
@@ -429,6 +459,9 @@ static int http_parse_request(HTTPContext *c)
p++;
}
*q = '\0';
+
+ strlcpy(c->method, cmd, sizeof(c->method));
+
if (!strcmp(cmd, "GET"))
post = 0;
else if (!strcmp(cmd, "POST"))
@@ -445,6 +478,8 @@ static int http_parse_request(HTTPContext *c)
}
*q = '\0';
+ strlcpy(c->url, url, sizeof(c->url));
+
while (isspace(*p)) p++;
q = protocol;
while (!isspace(*p) && *p != '\0') {
@@ -455,6 +490,8 @@ static int http_parse_request(HTTPContext *c)
*q = '\0';
if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
return -1;
+
+ strlcpy(c->protocol, protocol, sizeof(c->protocol));
/* find the filename and the optional info string in the request */
p = url;
@@ -463,12 +500,19 @@ static int http_parse_request(HTTPContext *c)
filename = p;
p = strchr(p, '?');
if (p) {
- strcpy(info, p);
+ strlcpy(info, p, sizeof(info));
*p = '\0';
} else {
info[0] = '\0';
}
+ if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
+ doing_asx = 1;
+ filename[strlen(filename)-1] = 'f';
+ } else {
+ doing_asx = 0;
+ }
+
stream = first_stream;
while (stream != NULL) {
if (!strcmp(stream->filename, filename))
@@ -479,30 +523,98 @@ static int http_parse_request(HTTPContext *c)
sprintf(msg, "File '%s' not found", url);
goto send_error;
}
- c->stream = stream;
-
- /* should do it after so that the size can be computed */
- {
- char buf1[32], buf2[32], *p;
- time_t ti;
- /* XXX: reentrant function ? */
- p = inet_ntoa(c->from_addr.sin_addr);
- strcpy(buf1, p);
- ti = time(NULL);
- p = ctime(&ti);
- strcpy(buf2, p);
- p = buf2 + strlen(p) - 1;
- if (*p == '\n')
- *p = '\0';
- http_log("%s - - [%s] \"%s %s %s\" %d %d\n",
- buf1, buf2, cmd, url, protocol, 200, 1024);
+ if (doing_asx) {
+ char *hostinfo = 0;
+
+ for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
+ if (strncasecmp(p, "Host:", 5) == 0) {
+ hostinfo = p + 5;
+ break;
+ }
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ if (hostinfo) {
+ char *eoh;
+ char hostbuf[260];
+
+ while (isspace(*hostinfo))
+ hostinfo++;
+
+ eoh = strchr(hostinfo, '\n');
+ if (eoh) {
+ if (eoh[-1] == '\r')
+ eoh--;
+
+ if (eoh - hostinfo < sizeof(hostbuf) - 1) {
+ memcpy(hostbuf, hostinfo, eoh - hostinfo);
+ hostbuf[eoh - hostinfo] = 0;
+
+ c->http_error = 200;
+ q = c->buffer;
+ q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
+ q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
+ q += sprintf(q, "\r\n");
+ q += sprintf(q, "<ASX Version=\"3\">\r\n");
+ q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
+ q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
+ hostbuf, filename, info);
+ q += sprintf(q, "</ASX>\r\n");
+
+ /* prepare output buffer */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ }
+ }
+ }
+
+ sprintf(msg, "ASX file not handled");
+ goto send_error;
}
+ c->stream = stream;
+
/* XXX: add there authenticate and IP match */
if (post) {
/* if post, it means a feed is being sent */
if (!stream->is_feed) {
+ /* However it might be a status report from WMP! Lets log the data
+ * as it might come in handy one day
+ */
+ char *logline = 0;
+
+ for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
+ if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
+ logline = p;
+ break;
+ }
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ if (logline) {
+ char *eol = strchr(logline, '\n');
+
+ logline += 17;
+
+ if (eol) {
+ if (eol[-1] == '\r')
+ eol--;
+ http_log("%.*s\n", eol - logline, logline);
+ c->suppress_log = 1;
+ }
+ }
+
sprintf(msg, "POST command not handled");
goto send_error;
}
@@ -535,7 +647,9 @@ static int http_parse_request(HTTPContext *c)
/* for asf, we need extra headers */
if (!strcmp(c->stream->fmt->name,"asf")) {
q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=1234\r\nPragma: features=\"broadcast\"\r\n");
- mime_type = "application/octet-stream";
+ /* mime_type = "application/octet-stream"; */
+ /* video/x-ms-asf seems better -- netscape doesn't crash any more! */
+ mime_type = "video/x-ms-asf";
}
q += sprintf(q, "Content-Type: %s\r\n", mime_type);
q += sprintf(q, "\r\n");