Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "httpd.h"
5 #include "xml.h"
7 typedef struct HttpObj HttpObj;
9 enum
10 {
11 ObjNameSize = 64,
12 MaxObjs = 16
13 };
15 struct HttpObj
16 {
17 char name[ObjNameSize];
18 int (*f)(HConnect*);
19 };
21 static HttpObj objs[MaxObjs];
23 static void listenproc(void*);
24 static int estats(HConnect *c);
25 static int dindex(HConnect *c);
26 static int xindex(HConnect *c);
27 static int sindex(HConnect *c);
28 static int notfound(HConnect *c);
29 static int httpdobj(char *name, int (*f)(HConnect*));
31 int
32 httpdinit(char *address)
33 {
34 fmtinstall('D', hdatefmt);
35 fmtinstall('H', httpfmt);
36 fmtinstall('U', hurlfmt);
38 if(address == nil)
39 address = "tcp!*!http";
41 httpdobj("/stats", estats);
42 httpdobj("/index", dindex);
43 httpdobj("/storage", sindex);
44 httpdobj("/xindex", xindex);
46 if(vtproc(listenproc, address) < 0)
47 return -1;
48 return 0;
49 }
51 static int
52 httpdobj(char *name, int (*f)(HConnect*))
53 {
54 int i;
56 if(name == nil || strlen(name) >= ObjNameSize)
57 return -1;
58 for(i = 0; i < MaxObjs; i++){
59 if(objs[i].name[0] == '\0'){
60 strcpy(objs[i].name, name);
61 objs[i].f = f;
62 return 0;
63 }
64 if(strcmp(objs[i].name, name) == 0)
65 return -1;
66 }
67 return -1;
68 }
70 static HConnect*
71 mkconnect(void)
72 {
73 HConnect *c;
75 c = mallocz(sizeof(HConnect), 1);
76 if(c == nil)
77 sysfatal("out of memory");
78 c->replog = nil;
79 c->hpos = c->header;
80 c->hstop = c->header;
81 return c;
82 }
84 void httpproc(void*);
86 static void
87 listenproc(void *vaddress)
88 {
89 HConnect *c;
90 char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
91 int ctl, nctl, data;
93 //sleep(1000); /* let strace find us */
95 address = vaddress;
96 ctl = announce(address, dir);
97 if(ctl < 0){
98 fprint(2, "venti: httpd can't announce on %s: %r\n", address);
99 return;
102 print("announce ctl %d dir %s\n", ctl, dir);
103 for(;;){
104 /*
105 * wait for a call (or an error)
106 */
107 nctl = listen(dir, ndir);
108 print("httpd listen %d %s...\n", nctl, ndir);
109 if(nctl < 0){
110 fprint(2, "venti: httpd can't listen on %s: %r\n", address);
111 return;
114 data = accept(ctl, ndir);
115 print("httpd accept %d...\n", data);
116 if(data < 0){
117 fprint(2, "venti: httpd accept: %r\n");
118 close(nctl);
119 continue;
121 print("httpd close nctl %d\n", nctl);
122 close(nctl);
123 c = mkconnect();
124 hinit(&c->hin, data, Hread);
125 hinit(&c->hout, data, Hwrite);
126 vtproc(httpproc, c);
130 void
131 httpproc(void *v)
133 HConnect *c;
134 int ok, t, i;
136 //sleep(1000); /* let strace find us */
137 c = v;
139 for(t = 15*60*1000; ; t = 15*1000){
140 if(hparsereq(c, t) <= 0)
141 break;
143 ok = -1;
144 for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
145 if(strcmp(c->req.uri, objs[i].name) == 0){
146 ok = (*objs[i].f)(c);
147 break;
150 if(i == MaxObjs)
151 ok = notfound(c);
152 if(c->head.closeit)
153 ok = -1;
154 hreqcleanup(c);
156 if(ok < 0)
157 break;
159 print("httpd cleanup %d\n", c->hin.fd);
160 hreqcleanup(c);
161 print("close %d\n", c->hin.fd);
162 close(c->hin.fd);
163 free(c);
166 static int
167 percent(long v, long total)
169 if(total == 0)
170 total = 1;
171 if(v < 1000*1000)
172 return (v * 100) / total;
173 total /= 100;
174 if(total == 0)
175 total = 1;
176 return v / total;
179 static int
180 preq(HConnect *c)
182 if(hparseheaders(c, 15*60*1000) < 0)
183 return -1;
184 if(strcmp(c->req.meth, "GET") != 0
185 && strcmp(c->req.meth, "HEAD") != 0)
186 return hunallowed(c, "GET, HEAD");
187 if(c->head.expectother || c->head.expectcont)
188 return hfail(c, HExpectFail, nil);
189 return 0;
192 static int
193 preqtext(HConnect *c)
195 Hio *hout;
196 int r;
198 r = preq(c);
199 if(r <= 0)
200 return r;
202 hout = &c->hout;
203 if(c->req.vermaj){
204 hokheaders(c);
205 hprint(hout, "Content-type: text/plain\r\n");
206 if(http11(c))
207 hprint(hout, "Transfer-Encoding: chunked\r\n");
208 hprint(hout, "\r\n");
211 if(http11(c))
212 hxferenc(hout, 1);
213 else
214 c->head.closeit = 1;
215 return 0;
218 static int
219 notfound(HConnect *c)
221 int r;
223 r = preq(c);
224 if(r <= 0)
225 return r;
226 return hfail(c, HNotFound, c->req.uri);
229 static int
230 estats(HConnect *c)
232 Hio *hout;
233 int r;
235 r = preqtext(c);
236 if(r <= 0)
237 return r;
239 hout = &c->hout;
240 hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
241 hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
242 hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
243 hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
245 hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
246 hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
247 hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
248 hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
249 hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
250 hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
252 hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
253 hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
255 hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
256 hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
257 hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
258 hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
260 hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
261 hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
262 percent(stats.ichits, stats.iclookups));
263 hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
264 percent(stats.icfills, stats.iclookups));
265 hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
267 hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
268 hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
269 hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
270 hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
272 hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
273 hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
274 hprint(hout, "disk reads=%,ld\n", stats.diskreads);
275 hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
277 hflush(hout);
278 return 0;
281 static int
282 sindex(HConnect *c)
284 Hio *hout;
285 Index *ix;
286 Arena *arena;
287 vlong clumps, cclumps, uncsize, used, size;
288 int i, r, active;
290 r = preqtext(c);
291 if(r <= 0)
292 return r;
293 hout = &c->hout;
295 ix = mainindex;
297 hprint(hout, "index=%s\n", ix->name);
299 active = 0;
300 clumps = 0;
301 cclumps = 0;
302 uncsize = 0;
303 used = 0;
304 size = 0;
305 for(i = 0; i < ix->narenas; i++){
306 arena = ix->arenas[i];
307 if(arena != nil && arena->clumps != 0){
308 active++;
309 clumps += arena->clumps;
310 cclumps += arena->cclumps;
311 uncsize += arena->uncsize;
312 used += arena->used;
314 size += arena->size;
316 hprint(hout, "total arenas=%d active=%d\n", ix->narenas, active);
317 hprint(hout, "total space=%lld used=%lld\n", size, used + clumps * ClumpInfoSize);
318 hprint(hout, "clumps=%lld compressed clumps=%lld data=%lld compressed data=%lld\n",
319 clumps, cclumps, uncsize, used - clumps * ClumpSize);
320 hflush(hout);
321 return 0;
324 static void
325 darena(Hio *hout, Arena *arena)
327 hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
328 arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
329 arena->version, arena->ctime, arena->wtime);
330 if(arena->sealed)
331 hprint(hout, " sealed\n");
332 else
333 hprint(hout, "\n");
334 if(scorecmp(zeroscore, arena->score) != 0)
335 hprint(hout, "\tscore=%V\n", arena->score);
337 hprint(hout, "\tclumps=%d compressed clumps=%d data=%lld compressed data=%lld disk storage=%lld\n",
338 arena->clumps, arena->cclumps, arena->uncsize,
339 arena->used - arena->clumps * ClumpSize,
340 arena->used + arena->clumps * ClumpInfoSize);
343 static int
344 dindex(HConnect *c)
346 Hio *hout;
347 Index *ix;
348 int i, r;
350 r = preqtext(c);
351 if(r <= 0)
352 return r;
353 hout = &c->hout;
356 ix = mainindex;
357 hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
358 ix->name, ix->version, ix->blocksize, ix->tabsize);
359 hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
360 for(i = 0; i < ix->nsects; i++)
361 hprint(hout, "\tsect=%s for buckets [%lld,%lld)\n", ix->smap[i].name, ix->smap[i].start, ix->smap[i].stop);
362 for(i = 0; i < ix->narenas; i++){
363 if(ix->arenas[i] != nil && ix->arenas[i]->clumps != 0){
364 hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
365 darena(hout, ix->arenas[i]);
368 hflush(hout);
369 return 0;
372 static int
373 xindex(HConnect *c)
375 Hio *hout;
376 int r;
378 r = preq(c);
379 if(r <= 0)
380 return r;
382 hout = &c->hout;
383 if(c->req.vermaj){
384 hokheaders(c);
385 hprint(hout, "Content-type: text/xml\r\n");
386 if(http11(c))
387 hprint(hout, "Transfer-Encoding: chunked\r\n");
388 hprint(hout, "\r\n");
391 if(http11(c))
392 hxferenc(hout, 1);
393 else
394 c->head.closeit = 1;
395 xmlindex(hout, mainindex, "index", 0);
396 hflush(hout);
397 return 0;
400 void
401 xmlindent(Hio *hout, int indent)
403 int i;
405 for(i = 0; i < indent; i++)
406 hputc(hout, '\t');
409 void
410 xmlaname(Hio *hout, char *v, char *tag)
412 hprint(hout, " %s=\"%s\"", tag, v);
415 void
416 xmlscore(Hio *hout, u8int *v, char *tag)
418 if(scorecmp(zeroscore, v) == 0)
419 return;
420 hprint(hout, " %s=\"%V\"", tag, v);
423 void
424 xmlsealed(Hio *hout, int v, char *tag)
426 if(!v)
427 return;
428 hprint(hout, " %s=\"yes\"", tag);
431 void
432 xmlu32int(Hio *hout, u32int v, char *tag)
434 hprint(hout, " %s=\"%ud\"", tag, v);
437 void
438 xmlu64int(Hio *hout, u64int v, char *tag)
440 hprint(hout, " %s=\"%llud\"", tag, v);