1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "httpd.h"
5 #include "httpsrv.h"
6
7 typedef struct Suffix Suffix;
8 struct Suffix
9 {
10 Suffix *next;
11 char *suffix;
12 char *generic;
13 char *specific;
14 char *encoding;
15 };
16
17 Suffix *suffixes = nil;
18
19 static Suffix* parsesuffix(char*, Suffix*);
20 static char* skipwhite(char*);
21 static HContents suffixclass(char*);
22 static char* towhite(char*);
23
24 int
updateQid(int fd,Qid * q)25 updateQid(int fd, Qid *q)
26 {
27 Dir *dir;
28 Qid dq;
29
30 dir = dirfstat(fd);
31 if(dir == nil)
32 sysfatal("can't dirfstat");
33 dq = dir->qid;
34 free(dir);
35 if(q->path == dq.path && q->vers == dq.vers && q->type == dq.type)
36 return 0;
37 *q = dq;
38 return 1;
39 }
40
41 void
contentinit(void)42 contentinit(void)
43 {
44 static Biobuf *b = nil;
45 static Qid qid;
46 char *file, *s;
47 Suffix *this;
48
49 file = "/sys/lib/mimetype";
50 if(b == nil){ /* first time */
51 b = Bopen(file, OREAD);
52 if(b == nil)
53 sysfatal("can't read from %s", file);
54 }
55 if(updateQid(Bfildes(b), &qid) == 0)
56 return;
57 Bseek(b, 0, 0);
58 while(suffixes!=nil){
59 this = suffixes;
60 suffixes = suffixes->next;
61 free(this->suffix);
62 free(this->generic);
63 free(this->specific);
64 free(this->encoding);
65 free(this);
66 }
67
68 while((s = Brdline(b, '\n')) != nil){
69 s[Blinelen(b) - 1] = 0;
70 suffixes = parsesuffix(s, suffixes);
71 }
72 }
73
74 static Suffix*
parsesuffix(char * line,Suffix * suffix)75 parsesuffix(char *line, Suffix *suffix)
76 {
77 Suffix *s;
78 char *p, *fields[5];
79 int i, nf;
80
81 p = strchr(line, '#');
82 if(p != nil)
83 *p = '\0';
84 nf = tokenize(line, fields, 5);
85 for(i = 0; i < 4; i++)
86 if(i >= nf || fields[i][0] == '-')
87 fields[i] = nil;
88
89 if(fields[2] == nil)
90 fields[1] = nil;
91 if(fields[1] == nil && fields[3] == nil)
92 return suffix;
93 if(fields[0] == nil)
94 return suffix;
95
96 s = ezalloc(sizeof *s);
97 s->next = suffix;
98 s->suffix = estrdup(fields[0]);
99 if(fields[1] != nil){
100 s->generic = estrdup(fields[1]);
101 s->specific = estrdup(fields[2]);
102 }
103 if(fields[3] != nil)
104 s->encoding = estrdup(fields[3]);
105 return s;
106 }
107
108 /*
109 * classify by file name extensions
110 */
111 HContents
uriclass(HConnect * hc,char * name)112 uriclass(HConnect *hc, char *name)
113 {
114 HContents conts;
115 Suffix *s;
116 HContent *type, *enc;
117 char *buf, *p;
118
119 type = nil;
120 enc = nil;
121 if((p = strrchr(name, '/')) != nil)
122 name = p + 1;
123 buf = hstrdup(hc, name);
124 while((p = strrchr(buf, '.')) != nil){
125 for(s = suffixes; s; s = s->next){
126 if(strcmp(p, s->suffix) == 0){
127 if(s->generic != nil && type == nil)
128 type = hmkcontent(hc, s->generic, s->specific, nil);
129 if(s->encoding != nil && enc == nil)
130 enc = hmkcontent(hc, s->encoding, nil, nil);
131 }
132 }
133 *p = 0;
134 }
135 conts.type = type;
136 conts.encoding = enc;
137 return conts;
138 }
139
140 /*
141 * classify by initial contents of file
142 */
143 HContents
dataclass(HConnect * hc,char * buf,int n)144 dataclass(HConnect *hc, char *buf, int n)
145 {
146 HContents conts;
147 Rune r;
148 int c, m;
149
150 for(; n > 0; n -= m){
151 c = *buf;
152 if(c < Runeself){
153 if(c < 32 && c != '\n' && c != '\r' && c != '\t' && c != '\v'){
154 conts.type = nil;
155 conts.encoding = nil;
156 return conts;
157 }
158 m = 1;
159 }else{
160 m = chartorune(&r, buf);
161 if(r == Runeerror){
162 conts.type = nil;
163 conts.encoding = nil;
164 return conts;
165 }
166 }
167 buf += m;
168 }
169 conts.type = hmkcontent(hc, "text", "plain", nil);
170 conts.encoding = nil;
171 return conts;
172 }
173