httpd.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. #include "httpd.h"
  5. #include "xml.h"
  6. typedef struct HttpObj HttpObj;
  7. enum
  8. {
  9. ObjNameSize = 64,
  10. MaxObjs = 16
  11. };
  12. struct HttpObj
  13. {
  14. char name[ObjNameSize];
  15. int (*f)(HConnect*);
  16. };
  17. static HttpObj objs[MaxObjs];
  18. static void dolisten(void*);
  19. static int estats(HConnect *c);
  20. static int dindex(HConnect *c);
  21. static int xindex(HConnect *c);
  22. static int sindex(HConnect *c);
  23. static int notfound(HConnect *c);
  24. static int httpdObj(char *name, int (*f)(HConnect*));
  25. int
  26. httpdInit(char *address)
  27. {
  28. fmtinstall('D', hdatefmt);
  29. fmtinstall('H', httpfmt);
  30. fmtinstall('U', hurlfmt);
  31. if(address == nil)
  32. address = "tcp!*!http";
  33. httpdObj("/stats", estats);
  34. httpdObj("/index", dindex);
  35. httpdObj("/storage", sindex);
  36. httpdObj("/xindex", xindex);
  37. if(vtThread(dolisten, address) < 0)
  38. return 0;
  39. return 1;
  40. }
  41. static int
  42. httpdObj(char *name, int (*f)(HConnect*))
  43. {
  44. int i;
  45. if(name == nil || strlen(name) >= ObjNameSize)
  46. return 0;
  47. for(i = 0; i < MaxObjs; i++){
  48. if(objs[i].name[0] == '\0'){
  49. strcpy(objs[i].name, name);
  50. objs[i].f = f;
  51. return 1;
  52. }
  53. if(strcmp(objs[i].name, name) == 0)
  54. return 0;
  55. }
  56. return 0;
  57. }
  58. static HConnect*
  59. mkconnect(void)
  60. {
  61. HConnect *c;
  62. c = mallocz(sizeof(HConnect), 1);
  63. if(c == nil)
  64. sysfatal("out of memory");
  65. c->replog = nil;
  66. c->hpos = c->header;
  67. c->hstop = c->header;
  68. return c;
  69. }
  70. static void
  71. dolisten(void *vaddress)
  72. {
  73. HConnect *c;
  74. char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
  75. int ctl, nctl, data, ok, t, i;
  76. address = vaddress;
  77. ctl = announce(address, dir);
  78. if(ctl < 0){
  79. fprint(2, "venti: httpd can't announce on %s: %r\n", address);
  80. return;
  81. }
  82. for(;;){
  83. /*
  84. * wait for a call (or an error)
  85. */
  86. nctl = listen(dir, ndir);
  87. if(nctl < 0){
  88. fprint(2, "venti: httpd can't listen on %s: %r\n", address);
  89. return;
  90. }
  91. /*
  92. * start a process for the service
  93. */
  94. switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFNAMEG|RFMEM)){
  95. case -1:
  96. close(nctl);
  97. continue;
  98. case 0:
  99. /*
  100. * see if we know the service requested
  101. */
  102. data = accept(ctl, ndir);
  103. if(data < 0){
  104. fprint(2, "venti: httpd can't open %s/data: %r", ndir);
  105. exits(nil);
  106. }
  107. close(ctl);
  108. close(nctl);
  109. c = mkconnect();
  110. hinit(&c->hin, data, Hread);
  111. hinit(&c->hout, data, Hwrite);
  112. for(t = 15*60*1000; ; t = 15*1000){
  113. if(hparsereq(c, t) <= 0)
  114. break;
  115. ok = -1;
  116. for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
  117. if(strcmp(c->req.uri, objs[i].name) == 0){
  118. ok = (*objs[i].f)(c);
  119. break;
  120. }
  121. }
  122. if(i == MaxObjs)
  123. ok = notfound(c);
  124. if(c->head.closeit)
  125. ok = -1;
  126. hreqcleanup(c);
  127. if(ok < 0)
  128. break;
  129. }
  130. hreqcleanup(c);
  131. free(c);
  132. exits(nil);
  133. default:
  134. close(nctl);
  135. break;
  136. }
  137. }
  138. }
  139. static int
  140. percent(long v, long total)
  141. {
  142. if(total == 0)
  143. total = 1;
  144. if(v < 1000*1000)
  145. return (v * 100) / total;
  146. total /= 100;
  147. if(total == 0)
  148. total = 1;
  149. return v / total;
  150. }
  151. static int
  152. preq(HConnect *c)
  153. {
  154. if(hparseheaders(c, 15*60*1000) < 0)
  155. return -1;
  156. if(strcmp(c->req.meth, "GET") != 0
  157. && strcmp(c->req.meth, "HEAD") != 0)
  158. return hunallowed(c, "GET, HEAD");
  159. if(c->head.expectother || c->head.expectcont)
  160. return hfail(c, HExpectFail, nil);
  161. return 1;
  162. }
  163. static int
  164. preqtext(HConnect *c)
  165. {
  166. Hio *hout;
  167. int r;
  168. r = preq(c);
  169. if(r <= 0)
  170. return r;
  171. hout = &c->hout;
  172. if(c->req.vermaj){
  173. hokheaders(c);
  174. hprint(hout, "Content-type: text/plain\r\n");
  175. if(http11(c))
  176. hprint(hout, "Transfer-Encoding: chunked\r\n");
  177. hprint(hout, "\r\n");
  178. }
  179. if(http11(c))
  180. hxferenc(hout, 1);
  181. else
  182. c->head.closeit = 1;
  183. return 1;
  184. }
  185. static int
  186. notfound(HConnect *c)
  187. {
  188. int r;
  189. r = preq(c);
  190. if(r <= 0)
  191. return r;
  192. return hfail(c, HNotFound, c->req.uri);
  193. }
  194. static int
  195. estats(HConnect *c)
  196. {
  197. Hio *hout;
  198. int r;
  199. r = preqtext(c);
  200. if(r <= 0)
  201. return r;
  202. hout = &c->hout;
  203. hprint(hout, "lump writes=%,ld\n", stats.lumpWrites);
  204. hprint(hout, "lump reads=%,ld\n", stats.lumpReads);
  205. hprint(hout, "lump cache read hits=%,ld\n", stats.lumpHit);
  206. hprint(hout, "lump cache read misses=%,ld\n", stats.lumpMiss);
  207. hprint(hout, "clump disk writes=%,ld\n", stats.clumpWrites);
  208. hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpBWrites);
  209. hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpBComp);
  210. hprint(hout, "clump disk reads=%,ld\n", stats.clumpReads);
  211. hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpBReads);
  212. hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpBUncomp);
  213. hprint(hout, "clump directory disk writes=%,ld\n", stats.ciWrites);
  214. hprint(hout, "clump directory disk reads=%,ld\n", stats.ciReads);
  215. hprint(hout, "index disk writes=%,ld\n", stats.indexWrites);
  216. hprint(hout, "index disk reads=%,ld\n", stats.indexReads);
  217. hprint(hout, "index disk reads for modify=%,ld\n", stats.indexWReads);
  218. hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexAReads);
  219. hprint(hout, "index cache lookups=%,ld\n", stats.icLookups);
  220. hprint(hout, "index cache hits=%,ld %d%%\n", stats.icHits,
  221. percent(stats.icHits, stats.icLookups));
  222. hprint(hout, "index cache fills=%,ld %d%%\n", stats.icFills,
  223. percent(stats.icFills, stats.icLookups));
  224. hprint(hout, "index cache inserts=%,ld\n", stats.icInserts);
  225. hprint(hout, "disk cache hits=%,ld\n", stats.pcHit);
  226. hprint(hout, "disk cache misses=%,ld\n", stats.pcMiss);
  227. hprint(hout, "disk cache reads=%,ld\n", stats.pcReads);
  228. hprint(hout, "disk cache bytes read=%,lld\n", stats.pcBReads);
  229. hprint(hout, "disk writes=%,ld\n", stats.diskWrites);
  230. hprint(hout, "disk bytes written=%,lld\n", stats.diskBWrites);
  231. hprint(hout, "disk reads=%,ld\n", stats.diskReads);
  232. hprint(hout, "disk bytes read=%,lld\n", stats.diskBReads);
  233. hflush(hout);
  234. return 1;
  235. }
  236. static int
  237. sindex(HConnect *c)
  238. {
  239. Hio *hout;
  240. Index *ix;
  241. Arena *arena;
  242. vlong clumps, cclumps, uncsize, used, size;
  243. int i, r, active;
  244. r = preqtext(c);
  245. if(r <= 0)
  246. return r;
  247. hout = &c->hout;
  248. ix = mainIndex;
  249. hprint(hout, "index=%s\n", ix->name);
  250. active = 0;
  251. clumps = 0;
  252. cclumps = 0;
  253. uncsize = 0;
  254. used = 0;
  255. size = 0;
  256. for(i = 0; i < ix->narenas; i++){
  257. arena = ix->arenas[i];
  258. if(arena != nil && arena->clumps != 0){
  259. active++;
  260. clumps += arena->clumps;
  261. cclumps += arena->cclumps;
  262. uncsize += arena->uncsize;
  263. used += arena->used;
  264. }
  265. size += arena->size;
  266. }
  267. hprint(hout, "total arenas=%d active=%d\n", ix->narenas, active);
  268. hprint(hout, "total space=%lld used=%lld\n", size, used + clumps * ClumpInfoSize);
  269. hprint(hout, "clumps=%lld compressed clumps=%lld data=%lld compressed data=%lld\n",
  270. clumps, cclumps, uncsize, used - clumps * ClumpSize);
  271. hflush(hout);
  272. return 1;
  273. }
  274. static void
  275. dArena(Hio *hout, Arena *arena)
  276. {
  277. hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
  278. arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blockSize,
  279. arena->version, arena->ctime, arena->wtime);
  280. if(arena->sealed)
  281. hprint(hout, " sealed\n");
  282. else
  283. hprint(hout, "\n");
  284. if(!scoreEq(zeroScore, arena->score))
  285. hprint(hout, "\tscore=%V\n", arena->score);
  286. hprint(hout, "\tclumps=%d compressed clumps=%d data=%lld compressed data=%lld disk storage=%lld\n",
  287. arena->clumps, arena->cclumps, arena->uncsize,
  288. arena->used - arena->clumps * ClumpSize,
  289. arena->used + arena->clumps * ClumpInfoSize);
  290. }
  291. static int
  292. dindex(HConnect *c)
  293. {
  294. Hio *hout;
  295. Index *ix;
  296. int i, r;
  297. r = preqtext(c);
  298. if(r <= 0)
  299. return r;
  300. hout = &c->hout;
  301. ix = mainIndex;
  302. hprint(hout, "index=%s version=%d blockSize=%d tabSize=%d\n",
  303. ix->name, ix->version, ix->blockSize, ix->tabSize);
  304. hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
  305. for(i = 0; i < ix->nsects; i++)
  306. hprint(hout, "\tsect=%s for buckets [%lld,%lld)\n", ix->smap[i].name, ix->smap[i].start, ix->smap[i].stop);
  307. for(i = 0; i < ix->narenas; i++){
  308. if(ix->arenas[i] != nil && ix->arenas[i]->clumps != 0){
  309. hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
  310. dArena(hout, ix->arenas[i]);
  311. }
  312. }
  313. hflush(hout);
  314. return 1;
  315. }
  316. static int
  317. xindex(HConnect *c)
  318. {
  319. Hio *hout;
  320. int r;
  321. r = preq(c);
  322. if(r <= 0)
  323. return r;
  324. hout = &c->hout;
  325. if(c->req.vermaj){
  326. hokheaders(c);
  327. hprint(hout, "Content-type: text/xml\r\n");
  328. if(http11(c))
  329. hprint(hout, "Transfer-Encoding: chunked\r\n");
  330. hprint(hout, "\r\n");
  331. }
  332. if(http11(c))
  333. hxferenc(hout, 1);
  334. else
  335. c->head.closeit = 1;
  336. xmlIndex(hout, mainIndex, "index", 0);
  337. hflush(hout);
  338. return 1;
  339. }
  340. void
  341. xmlIndent(Hio *hout, int indent)
  342. {
  343. int i;
  344. for(i = 0; i < indent; i++)
  345. hputc(hout, '\t');
  346. }
  347. void
  348. xmlAName(Hio *hout, char *v, char *tag)
  349. {
  350. hprint(hout, " %s=\"%s\"", tag, v);
  351. }
  352. void
  353. xmlScore(Hio *hout, u8int *v, char *tag)
  354. {
  355. if(scoreEq(zeroScore, v))
  356. return;
  357. hprint(hout, " %s=\"%V\"", tag, v);
  358. }
  359. void
  360. xmlSealed(Hio *hout, int v, char *tag)
  361. {
  362. if(!v)
  363. return;
  364. hprint(hout, " %s=\"yes\"", tag);
  365. }
  366. void
  367. xmlU32int(Hio *hout, u32int v, char *tag)
  368. {
  369. hprint(hout, " %s=\"%ud\"", tag, v);
  370. }
  371. void
  372. xmlU64int(Hio *hout, u64int v, char *tag)
  373. {
  374. hprint(hout, " %s=\"%llud\"", tag, v);
  375. }