. Initialise range_* in struct connection.

. Added reply_start to struct connection.
. Added debugf() to free_connection().
. Construct HTTP 206 reply if Range specified.
. Take reply_start into consideration in poll_send_reply().
. Added fread() error handling - eof is non-fatal.
This commit is contained in:
Emil Mikulic 2003-06-27 06:42:42 +00:00
parent 295cd40bbb
commit 67604878ec

View File

@ -85,7 +85,7 @@ struct connection
char *reply; char *reply;
int reply_dont_free; int reply_dont_free;
FILE *reply_file; FILE *reply_file;
size_t reply_length, reply_sent; size_t reply_start, reply_length, reply_sent;
unsigned int total_sent; /* header + body = total, for logging */ unsigned int total_sent; /* header + body = total, for logging */
}; };
@ -658,22 +658,27 @@ static struct connection *new_connection(void)
conn->client = INADDR_ANY; conn->client = INADDR_ANY;
conn->last_active = time(NULL); conn->last_active = time(NULL);
conn->request = NULL; conn->request = NULL;
conn->request_length = 0;
conn->method = NULL; conn->method = NULL;
conn->uri = NULL; conn->uri = NULL;
conn->referer = NULL; conn->referer = NULL;
conn->user_agent = NULL; conn->user_agent = NULL;
conn->request_length = 0; conn->range_begin = 0;
conn->range_end = 0;
conn->range_begin_given = 0;
conn->range_end_given = 0;
conn->header = NULL; conn->header = NULL;
conn->header_sent = 0;
conn->header_length = 0; conn->header_length = 0;
conn->header_sent = 0;
conn->header_dont_free = 0; conn->header_dont_free = 0;
conn->header_only = 0; conn->header_only = 0;
conn->http_code = 0; conn->http_code = 0;
conn->reply = NULL; conn->reply = NULL;
conn->reply_dont_free = 0; conn->reply_dont_free = 0;
conn->reply_file = NULL; conn->reply_file = NULL;
conn->reply_sent = 0; conn->reply_start = 0;
conn->reply_length = 0; conn->reply_length = 0;
conn->reply_sent = 0;
conn->total_sent = 0; conn->total_sent = 0;
/* Make it harmless so it gets garbage-collected if it should, for some /* Make it harmless so it gets garbage-collected if it should, for some
@ -721,6 +726,7 @@ static void accept_connection(void)
*/ */
static void free_connection(struct connection *conn) static void free_connection(struct connection *conn)
{ {
debugf("free_connection(%d)\n", conn->socket);
if (conn->socket != -1) close(conn->socket); if (conn->socket != -1) close(conn->socket);
if (conn->request != NULL) free(conn->request); if (conn->request != NULL) free(conn->request);
if (conn->method != NULL) free(conn->method); if (conn->method != NULL) free(conn->method);
@ -930,7 +936,7 @@ static void parse_range_field(struct connection *conn)
for (bound1=bound2; for (bound1=bound2;
isdigit( (int)range[bound2] ) && bound2 < len; isdigit( (int)range[bound2] ) && bound2 < len;
bound2++) bound2++)
; /* FIXME */ ;
if (bound2 != len && range[bound2] != ',') if (bound2 != len && range[bound2] != ',')
break; /* must be end of string or a list to be valid */ break; /* must be end of string or a list to be valid */
@ -982,6 +988,8 @@ static void parse_request(struct connection *conn)
/* parse referer, user_agent */ /* parse referer, user_agent */
conn->referer = parse_field(conn, "Referer: "); conn->referer = parse_field(conn, "Referer: ");
conn->user_agent = parse_field(conn, "User-Agent: "); conn->user_agent = parse_field(conn, "User-Agent: ");
parse_range_field(conn);
} }
@ -1054,7 +1062,6 @@ static void process_get(struct connection *conn)
} }
conn->reply_type = REPLY_FROMFILE; conn->reply_type = REPLY_FROMFILE;
conn->reply_length = filestat.st_size;
(void) rfc1123_date(lastmod, filestat.st_mtime); (void) rfc1123_date(lastmod, filestat.st_mtime);
/* check for If-Modified-Since, may not have to send */ /* check for If-Modified-Since, may not have to send */
@ -1068,6 +1075,59 @@ static void process_get(struct connection *conn)
return; return;
} }
if (conn->range_begin_given || conn->range_end_given)
{
size_t from, to;
if (conn->range_begin_given && conn->range_end_given)
{
/* 100-200 */
from = conn->range_begin;
to = conn->range_end;
/* clamp [to] to filestat.st_size-1 */
if (to > (filestat.st_size-1)) to = filestat.st_size-1;
}
else if (conn->range_begin_given && !conn->range_end_given)
{
/* 100- :: yields 100 to end */
from = conn->range_begin;
to = filestat.st_size-1;
}
else if (!conn->range_begin_given && conn->range_end_given)
{
/* -200 :: yields last 200 */
to = filestat.st_size-1;
from = to - conn->range_end + 1;
/* check for wrapping */
if (from < 0 || from > to) from = 0;
}
conn->reply_start = from;
conn->reply_length = to - from + 1;
conn->header_length = xasprintf(&(conn->header),
"HTTP/1.1 206 Partial Content\r\n"
"Date: %s\r\n"
"Server: %s\r\n"
"Connection: close\r\n" /* FIXME: remove this for keepalive */
"Content-Length: %d\r\n"
"Content-Range: bytes %d-%d/%d\r\n"
"Content-Type: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n"
,
rfc1123_date(date, time(NULL)), pkgname, conn->reply_length,
from, to, filestat.st_size, mimetype, lastmod
);
conn->http_code = 206;
debugf("sending %d-%d/%d\n", from, to, (int)filestat.st_size);
}
else /* no range stuff */
{
conn->reply_length = filestat.st_size;
conn->header_length = xasprintf(&(conn->header), conn->header_length = xasprintf(&(conn->header),
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Date: %s\r\n" "Date: %s\r\n"
@ -1082,6 +1142,7 @@ static void process_get(struct connection *conn)
mimetype, lastmod mimetype, lastmod
); );
conn->http_code = 200; conn->http_code = 200;
}
} }
@ -1223,7 +1284,8 @@ static void poll_send_reply(struct connection *conn)
if (conn->reply_type == REPLY_GENERATED) if (conn->reply_type == REPLY_GENERATED)
{ {
sent = send(conn->socket, conn->reply + conn->reply_sent, sent = send(conn->socket,
conn->reply + conn->reply_start + conn->reply_sent,
conn->reply_length - conn->reply_sent, 0); conn->reply_length - conn->reply_sent, 0);
} }
else else
@ -1235,18 +1297,36 @@ static void poll_send_reply(struct connection *conn)
conn->reply_length - conn->reply_sent); conn->reply_length - conn->reply_sent);
#undef BUFSIZE #undef BUFSIZE
if (fseek(conn->reply_file, (long)conn->reply_sent, SEEK_SET) == -1) if (fseek(conn->reply_file,
err(1, "fseek(%d)", conn->reply_sent); (long)(conn->reply_start + conn->reply_sent), SEEK_SET) == -1)
err(1, "fseek(%d)", conn->reply_start + conn->reply_sent);
debugf("start=%d, sent=%d, length=%d\n",
conn->reply_start,
conn->reply_sent, conn->reply_length);
if (fread(buf, amount, 1, conn->reply_file) != 1) if (fread(buf, amount, 1, conn->reply_file) != 1)
err(1, "fread()"); {
if (feof(conn->reply_file))
{
conn->state = DONE;
fprintf(stderr, "(%d) premature end of file\n",
conn->socket);
return;
}
fprintf(stderr, "error: %s\n",
strerror( ferror(conn->reply_file) ));
errx(1, "fread()");
}
sent = send(conn->socket, buf, amount, 0); sent = send(conn->socket, buf, amount, 0);
} }
conn->last_active = time(NULL); conn->last_active = time(NULL);
debugf("poll_send_reply(%d) sent %d bytes [%d to %d]\n", debugf("poll_send_reply(%d) sent %d: %d+[%d-%d] of %d\n",
conn->socket, (int)sent, (int)conn->reply_sent, conn->socket, (int)sent, conn->reply_start,
(int)(conn->reply_sent + sent - 1)); (int)conn->reply_sent,
(int)(conn->reply_sent + sent - 1),
conn->reply_length);
/* handle any errors (-1) or closure (0) in send() */ /* handle any errors (-1) or closure (0) in send() */
if (sent < 1) if (sent < 1)