/*
* these should be done better; see the reponse codes in /lib/rfc/rfc2616 for
* more info on what should be included.
*/
#define UNAUTHED "You are not authorized to see this area.\n"
#define NOCONTENT "No acceptable type of data is available.\n"
#define NOENCODE "No acceptable encoding of the contents is available.\n"
#define UNMATCHED "The entity requested does not match the existing entity.\n"
#define BADRANGE "No bytes are avaible for the range you requested.\n"
/*
* fd references a file which has been authorized & checked for relocations.
* send back the headers & its contents.
* includes checks for conditional requests & ranges.
*/
int
sendfd(HConnect *c, int fd, Dir *dir, HContent *type, HContent *enc)
{
Qid qid;
HRange *r;
HContents conts;
Hio *hout;
char *boundary, etag[32];
long mtime;
ulong tr;
int n, nw, multir, ok;
vlong wrote, length;
/*
* for multipart/byterange messages,
* it is not ok for the boundary string to appear within a message part.
* however, it probably doesn't matter, since there are lengths for every part.
*/
wrote = 0;
ok = 1;
for(; r != nil; r = r->next){
if(multir){
hprint(hout, "\r\n--%s\r\n", boundary);
printtype(hout, type, enc);
hprint(hout, "Content-Range: bytes %ld-%ld/%lld\r\n", r->start, r->stop, length);
hprint(hout, "Content-Length: %ld\r\n", 1 + r->stop - r->start);
hprint(hout, "\r\n");
}
hflush(hout);
if(ok == nil)
return seprint(s, e, "Your browser accepts any %s.<br>\n", which);
s = seprint(s, e, "Your browser accepts %s: ", which);
sep = "";
for(; ok != nil; ok = ok->next){
if(ok->specific)
s = seprint(s, e, "%s%s/%s", sep, ok->generic, ok->specific);
else
s = seprint(s, e, "%s%s", sep, ok->generic);
sep = ", ";
}
return seprint(s, e, ".<br>\n");
}
/*
* send back a nice error message if the content is unacceptable
* to get this message in ie, go to tools, internet options, advanced,
* and turn off Show Friendly HTTP Error Messages under the Browsing category
*/
static int
notaccept(HConnect *c, HContent *type, HContent *enc, char *which)
{
Hio *hout;
char *s, *e;
hout = &c->hout;
e = &c->xferbuf[HBufSize];
s = c->xferbuf;
s = seprint(s, e, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
s = seprint(s, e, "<html>\n<title>Unacceptable %s</title>\n<body>\n", which);
s = seprint(s, e, "Your browser will not accept this data, %H, because of its %s.<br>\n", c->req.uri, which);
s = seprint(s, e, "Its Content-Type is %s/%s", type->generic, type->specific);
if(enc != nil)
s = seprint(s, e, ", and Content-Encoding is %s", enc->generic);
s = seprint(s, e, ".<br>\n\n");
s = acceptcont(s, e, c->head.oktype, "Content-Type");
s = acceptcont(s, e, c->head.okencode, "Content-Encoding");
s = seprint(s, e, "</body>\n</html>\n");
/*
* length is the actual length of the entity requested.
* discard any range requests which are invalid,
* ie start after the end, or have stop before start.
* rewrite suffix requests
*/
HRange*
fixrange(HRange *h, long length)
{
HRange *r, *rr;
if(length == 0)
return nil;
/*
* rewrite each range to reflect the actual length of the file
* toss out any invalid ranges
*/
rr = nil;
for(r = h; r != nil; r = r->next){
if(r->suffix){
/*
* for suffix, r->stop is a byte *length*
* not the byte *offset* of last byte!
*/
r->start = length - r->stop;
if(r->start >= length)
r->start = 0;
r->stop = length - 1;
r->suffix = 0;
}
if(r->stop >= length)
r->stop = length - 1;
if(r->start > r->stop){
if(rr == nil)
h = r->next;
else
rr->next = r->next;
}else
rr = r;
}
/*
* merge consecutive overlapping or abutting ranges
*
* not clear from rfc2616 how much merging needs to be done.
* this code merges only if a range is adjacent to a later starting,
* over overlapping or abutting range. this allows a client
* to request wanted data first, followed by other data.
* this may be useful then fetching part of a page, then the adjacent regions.
*/
if(h == nil)
return h;
r = h;
for(;;){
rr = r->next;
if(rr == nil)
break;
if(r->start <= rr->start && r->stop + 1 >= rr->start){
if(r->stop < rr->stop)
r->stop = rr->stop;
r->next = rr->next;
}else
r = rr;
}
return h;
}