From 7434ba6d53b9a8858a6f965d9a4e60b5eb1316fe Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Fri, 10 May 2002 02:20:27 +0000 Subject: * 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 --- ffserver.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file 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, "\r\n"); + q += sprintf(q, "\r\n"); + q += sprintf(q, "\r\n", + hostbuf, filename, info); + q += sprintf(q, "\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"); -- cgit v1.2.3