. 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;
int reply_dont_free;
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 */
};
@ -658,22 +658,27 @@ static struct connection *new_connection(void)
conn->client = INADDR_ANY;
conn->last_active = time(NULL);
conn->request = NULL;
conn->request_length = 0;
conn->method = NULL;
conn->uri = NULL;
conn->referer = 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_sent = 0;
conn->header_length = 0;
conn->header_sent = 0;
conn->header_dont_free = 0;
conn->header_only = 0;
conn->http_code = 0;
conn->reply = NULL;
conn->reply_dont_free = 0;
conn->reply_file = NULL;
conn->reply_sent = 0;
conn->reply_start = 0;
conn->reply_length = 0;
conn->reply_sent = 0;
conn->total_sent = 0;
/* 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)
{
debugf("free_connection(%d)\n", conn->socket);
if (conn->socket != -1) close(conn->socket);
if (conn->request != NULL) free(conn->request);
if (conn->method != NULL) free(conn->method);
@ -930,7 +936,7 @@ static void parse_range_field(struct connection *conn)
for (bound1=bound2;
isdigit( (int)range[bound2] ) && bound2 < len;
bound2++)
; /* FIXME */
;
if (bound2 != len && range[bound2] != ',')
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 */
conn->referer = parse_field(conn, "Referer: ");
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_length = filestat.st_size;
(void) rfc1123_date(lastmod, filestat.st_mtime);
/* check for If-Modified-Since, may not have to send */
@ -1068,20 +1075,74 @@ static void process_get(struct connection *conn)
return;
}
conn->header_length = xasprintf(&(conn->header),
"HTTP/1.1 200 OK\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-Type: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n"
,
rfc1123_date(date, time(NULL)), pkgname, conn->reply_length,
mimetype, lastmod
);
conn->http_code = 200;
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),
"HTTP/1.1 200 OK\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-Type: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n"
,
rfc1123_date(date, time(NULL)), pkgname, conn->reply_length,
mimetype, lastmod
);
conn->http_code = 200;
}
}
@ -1223,7 +1284,8 @@ static void poll_send_reply(struct connection *conn)
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);
}
else
@ -1235,18 +1297,36 @@ static void poll_send_reply(struct connection *conn)
conn->reply_length - conn->reply_sent);
#undef BUFSIZE
if (fseek(conn->reply_file, (long)conn->reply_sent, SEEK_SET) == -1)
err(1, "fseek(%d)", conn->reply_sent);
if (fseek(conn->reply_file,
(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)
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);
}
conn->last_active = time(NULL);
debugf("poll_send_reply(%d) sent %d bytes [%d to %d]\n",
conn->socket, (int)sent, (int)conn->reply_sent,
(int)(conn->reply_sent + sent - 1));
debugf("poll_send_reply(%d) sent %d: %d+[%d-%d] of %d\n",
conn->socket, (int)sent, conn->reply_start,
(int)conn->reply_sent,
(int)(conn->reply_sent + sent - 1),
conn->reply_length);
/* handle any errors (-1) or closure (0) in send() */
if (sent < 1)