* 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:
Philip Gladstone 2002-05-10 02:20:27 +00:00
parent 8d1335ea2b
commit 7434ba6d53

View File

@ -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");