xref: /plan9/sys/src/cmd/ip/httpd/content.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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