httpd.c 8.9 KB

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