* 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
This commit is contained in:
parent
8d1335ea2b
commit
7434ba6d53
154
ffserver.c
154
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");
|
||||
|
Loading…
Reference in New Issue
Block a user