Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "httpd.h"
#include "httpsrv.h"

typedef struct Suffix   Suffix;
struct Suffix 
{
        Suffix  *next;
        char    *suffix;
        char    *generic;
        char    *specific;
        char    *encoding;
};

Suffix  *suffixes = nil;

static  Suffix*                 parsesuffix(char*, Suffix*);
static  char*                   skipwhite(char*);
static  HContents               suffixclass(char*);
static  char*                   towhite(char*);

int
updateQid(int fd, Qid *q)
{
        Dir *dir;
        Qid dq;

        dir = dirfstat(fd);
        if(dir == nil)
                sysfatal("can't dirfstat");
        dq = dir->qid;
        free(dir);
        if(q->path == dq.path && q->vers == dq.vers && q->type == dq.type)
                return 0;
        *q = dq;
        return 1;
}

void
contentinit(void)
{
        static Biobuf *b = nil;
        static Qid qid;
        char *file, *s;
        Suffix *this;

        file = "/sys/lib/mimetype";
        if(b == nil){ /* first time */
                b = Bopen(file, OREAD);
                if(b == nil)
                        sysfatal("can't read from %s", file);
        }
        if(updateQid(Bfildes(b), &qid) == 0)
                return;
        Bseek(b, 0, 0);
        while(suffixes!=nil){
                this = suffixes;
                suffixes = suffixes->next;
                free(this->suffix);
                free(this->generic);
                free(this->specific);
                free(this->encoding);
                free(this);
        }

        while((s = Brdline(b, '\n')) != nil){
                s[Blinelen(b) - 1] = 0;
                suffixes = parsesuffix(s, suffixes);
        }
}

static Suffix*
parsesuffix(char *line, Suffix *suffix)
{
        Suffix *s;
        char *p, *fields[5];
        int i, nf;

        p = strchr(line, '#');
        if(p != nil)
                *p = '\0';
        nf = tokenize(line, fields, 5);
        for(i = 0; i < 4; i++)
                if(i >= nf || fields[i][0] == '-')
                        fields[i] = nil;

        if(fields[2] == nil)
                fields[1] = nil;
        if(fields[1] == nil && fields[3] == nil)
                return suffix;
        if(fields[0] == nil)
                return suffix;

        s = ezalloc(sizeof *s);
        s->next = suffix;
        s->suffix = estrdup(fields[0]);
        if(fields[1] != nil){
                s->generic = estrdup(fields[1]);
                s->specific = estrdup(fields[2]);
        }
        if(fields[3] != nil)
                s->encoding = estrdup(fields[3]);
        return s;
}

/*
 * classify by file name extensions
 */
HContents
uriclass(HConnect *hc, char *name)
{
        HContents conts;
        Suffix *s;
        HContent *type, *enc;
        char *buf, *p;

        type = nil;
        enc = nil;
        if((p = strrchr(name, '/')) != nil)
                name = p + 1;
        buf = hstrdup(hc, name);
        while((p = strrchr(buf, '.')) != nil){
                for(s = suffixes; s; s = s->next){
                        if(strcmp(p, s->suffix) == 0){
                                if(s->generic != nil && type == nil)
                                        type = hmkcontent(hc, s->generic, s->specific, nil);
                                if(s->encoding != nil && enc == nil)
                                        enc = hmkcontent(hc, s->encoding, nil, nil);
                        }
                }
                *p = 0;
        }
        conts.type = type;
        conts.encoding = enc;
        return conts;
}

/*
 * classify by initial contents of file
 */
HContents
dataclass(HConnect *hc, char *buf, int n)
{
        HContents conts;
        Rune r;
        int c, m;

        for(; n > 0; n -= m){
                c = *buf;
                if(c < Runeself){
                        if(c < 32 && c != '\n' && c != '\r' && c != '\t' && c != '\v'){
                                conts.type = nil;
                                conts.encoding = nil;
                                return conts;
                        }
                        m = 1;
                }else{
                        m = chartorune(&r, buf);
                        if(r == Runeerror){
                                conts.type = nil;
                                conts.encoding = nil;
                                return conts;
                        }
                }
                buf += m;
        }
        conts.type = hmkcontent(hc, "text", "plain", nil);
        conts.encoding = nil;
        return conts;
}