/* * check time and entity tag conditions. */ int checkreq(HConnect *c, HContent *type, HContent *enc, long mtime, char *etag) { Hio *hout; int m; hout = &c->hout; if(c->req.vermaj >= 1 && c->req.vermin >= 1 && !hcheckcontent(type, c->head.oktype, "Content-Type", 0)) return notaccept(c, type, enc, "Content-Type"); if(c->req.vermaj >= 1 && c->req.vermin >= 1 && !hcheckcontent(enc, c->head.okencode, "Content-Encoding", 0)) return notaccept(c, type, enc, "Content-Encoding"); /* * can use weak match only with get or head; * this always uses strong matches */ m = etagmatch(1, c->head.ifnomatch, etag); if(m && strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0 || c->head.ifunmodsince && c->head.ifunmodsince < mtime || c->head.ifmatch != nil && !etagmatch(1, c->head.ifmatch, etag)){ hprint(hout, "%s 412 Precondition Failed\r\n", hversion); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "Content-Type: text/html\r\n"); hprint(hout, "Content-Length: %d\r\n", STRLEN(UNMATCHED)); if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); if(strcmp(c->req.meth, "HEAD") != 0) hprint(hout, "%s", UNMATCHED); writelog(c, "Reply: 412 Precondition Failed\n"); return hflush(hout); } if(c->head.ifmodsince >= mtime && (m || c->head.ifnomatch == nil)){ /* * can only send back Date, ETag, Content-Location, * Expires, Cache-Control, and Vary entity-headers */ hprint(hout, "%s 304 Not Modified\r\n", hversion); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "ETag: %s\r\n", etag); if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); writelog(c, "Reply: 304 Not Modified\n"); return hflush(hout); } return 1; }
void error(char *title, char *fmt, ...) { va_list arg; char buf[1024], *out; va_start(arg, fmt); out = vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); *out = 0; hprint(hout, "%s 404 %s\r\n", hversion, title); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Content-type: text/html\r\n"); hprint(hout, "\r\n"); doctype(); hprint(hout, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"); hprint(hout, "<head><title>%s</title></head>\n", title); hprint(hout, "<body>\n"); hprint(hout, "<h1>%s</h1>\n", title); hprint(hout, "%s\n", buf); hprint(hout, "</body>\n"); hprint(hout, "</html>\n"); hflush(hout); writelog(connect, "Reply: 404\nReason: %s\n", title); exits(nil); }
static int dindex(HConnect *c) { Hio *hout; Index *ix; int i, r; r = hsettext(c); if(r < 0) return r; hout = &c->hout; ix = mainindex; hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n", ix->name, ix->version, ix->blocksize, ix->tabsize); hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div); for(i = 0; i < ix->nsects; i++) hprint(hout, "\tsect=%s for buckets [%lld,%lld) buckmax=%d\n", ix->smap[i].name, ix->smap[i].start, ix->smap[i].stop, ix->sects[i]->buckmax); for(i = 0; i < ix->narenas; i++){ if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){ hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop); darena(hout, ix->arenas[i]); } } hflush(hout); return 0; }
static int xindex(HConnect *c) { if(hsettype(c, "text/xml") < 0) return -1; xmlindex(&c->hout, mainindex, "index", 0); hflush(&c->hout); return 0; }
static int xloglist(HConnect *c) { if(hsettype(c, "text/html") < 0) return -1; vtloghlist(&c->hout); hflush(&c->hout); return 0; }
/////////////////////////////////////////////////////////////////////////////// // hprintf static void hprintf(HANDLE LogFile, LPCTSTR Format, ...) { hflush(LogFile, (HPRINTF_BUFFER_SIZE-1024)); va_list arglist; va_start( arglist, Format); hprintf_index += wvsprintf(&hprintf_buffer[hprintf_index], Format, arglist); va_end( arglist); }
static int fromwebdir(HConnect *c) { char buf[4096], *p, *ext, *type; int i, fd, n, defaulted; Dir *d; if(webroot == nil || strstr(c->req.uri, "..")) return hnotfound(c); snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1); defaulted = 0; reopen: if((fd = open(buf, OREAD)) < 0) return hnotfound(c); d = dirfstat(fd); if(d == nil){ close(fd); return hnotfound(c); } if(d->mode&DMDIR){ if(!defaulted){ defaulted = 1; strcat(buf, "/index.html"); free(d); close(fd); goto reopen; } free(d); return hnotfound(c); } free(d); p = buf+strlen(buf); type = "application/octet-stream"; for(i=0; exttab[i].ext; i++){ ext = exttab[i].ext; if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){ type = exttab[i].type; break; } } if(hsettype(c, type) < 0){ close(fd); return 0; } while((n = read(fd, buf, sizeof buf)) > 0) if(hwrite(&c->hout, buf, n) < 0) break; close(fd); hflush(&c->hout); return 0; }
int hclose(hFILE *fp) { int err = fp->has_errno; if (writebuffer_is_nonempty(fp) && hflush(fp) < 0) err = fp->has_errno; if (fp->backend->close(fp) < 0) err = errno; hfile_destroy(fp); if (err) { errno = err; return EOF; } else return 0; }
static int xset(HConnect *c) { int i, old; char *name, *value; if(hsettext(c) < 0) return -1; if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){ for(i=0; namedints[i].name; i++) hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p); hflush(&c->hout); return 0; } for(i=0; namedints[i].name; i++) if(strcmp(name, namedints[i].name) == 0) break; if(!namedints[i].name){ hprint(&c->hout, "%s not found\n", name); hflush(&c->hout); return 0; } if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){ hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p); hflush(&c->hout); return 0; } old = *namedints[i].p; *namedints[i].p = atoll(value); hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old); hflush(&c->hout); return 0; }
static int hmanager(HConnect *c) { Hio *hout; int r; int i, k; Job *j; VtLog *l; VtLogChunk *ch; r = hsethtml(c); if(r < 0) return r; hout = &c->hout; hprint(hout, "<html><head><title>venti mgr status</title></head>\n"); hprint(hout, "<body><h2>venti mgr status</h2>\n"); for(i=0; i<njob; i++) { j = &job[i]; hprint(hout, "<b>"); if(j->nrun == 0) hprint(hout, "----/--/-- --:--:--"); else hprint(hout, "%+T", (long)(j->runstart + time0)); hprint(hout, " %s", j->name); if(j->nrun > 0) { if(j->newok == -1) { hprint(hout, " (running)"); } else if(!j->newok) { hprint(hout, " <font color=\"#cc0000\">(FAILED)</font>"); } } hprint(hout, "</b>\n"); hprint(hout, "<font size=-1><pre>\n"); l = j->newlog; ch = l->w; for(k=0; k<l->nchunk; k++){ if(++ch == l->chunk+l->nchunk) ch = l->chunk; hwrite(hout, ch->p, ch->wp-ch->p); } hprint(hout, "</pre></font>\n"); hprint(hout, "\n"); } hprint(hout, "</body></html>\n"); hflush(hout); return 0; }
static int hicacheempty(HConnect *c) { Hio *hout; int r; r = hsettext(c); if(r < 0) return r; hout = &c->hout; emptyicache(); hprint(hout, "emptied icache\n"); hflush(hout); return 0; }
static int hicachekick(HConnect *c) { Hio *hout; int r; r = hsettext(c); if(r < 0) return r; hout = &c->hout; kickicache(); hprint(hout, "kicked icache\n"); hflush(hout); return 0; }
static int hdcacheflush(HConnect *c) { Hio *hout; int r; r = hsettext(c); if(r < 0) return r; hout = &c->hout; flushdcache(); hprint(hout, "flushed dcache\n"); hflush(hout); return 0; }
void t_push(void) /* begin a new block */ { hflush(); statep->ssize = size; statep->sfont = font; statep->shorig = horig; statep->svorig = vorig; statep->shpos = hpos; statep->svpos = vpos; horig = hpos; vorig = vpos; hpos = vpos = 0; if (statep++ >= state+MAXSTATE) error(FATAL, "{ nested too deep"); hpos = vpos = 0; }
void main(int argc, char **argv) { fmtinstall('H', httpfmt); fmtinstall('U', hurlfmt); fmtinstall('M', dirmodefmt); aio = Bopen("/sys/lib/webls.allowed", OREAD); dio = Bopen("/sys/lib/webls.denied", OREAD); if(argc == 2){ hinit(&houtb, 1, Hwrite); hout = &houtb; dols(argv[1]); exits(nil); } close(2); connect = init(argc, argv); hout = &connect->hout; vermaj = connect->req.vermaj; if(hparseheaders(connect, HSTIMEOUT) < 0) exits("failed"); if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0){ hunallowed(connect, "GET, HEAD"); exits("not allowed"); } if(connect->head.expectother || connect->head.expectcont){ hfail(connect, HExpectFail, nil); exits("failed"); } bind("/usr/web", "/", MREPL); if(connect->req.search != nil) dosearch(connect->req.search); else error("Bad argument", "<p>Need a search argument</p>"); hflush(hout); writelog(connect, "200 webls %ld %ld\n", hout->seek, hout->seek); exits(nil); }
static int sindex(HConnect *c) { Hio *hout; Index *ix; Arena *arena; vlong clumps, cclumps, uncsize, used, size; int i, r, active; r = hsettext(c); if(r < 0) return r; hout = &c->hout; ix = mainindex; hprint(hout, "index=%s\n", ix->name); active = 0; clumps = 0; cclumps = 0; uncsize = 0; used = 0; size = 0; for(i = 0; i < ix->narenas; i++){ arena = ix->arenas[i]; if(arena != nil && arena->memstats.clumps != 0){ active++; clumps += arena->memstats.clumps; cclumps += arena->memstats.cclumps; uncsize += arena->memstats.uncsize; used += arena->memstats.used; } size += arena->size; } hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active); hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize); hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n", clumps, cclumps, uncsize, used - clumps * ClumpSize); hflush(hout); return 0; }
static int xlog(HConnect *c) { char *name; VtLog *l; name = hargstr(c, "log", ""); if(!name[0]) return xloglist(c); l = vtlogopen(name, 0); if(l == nil) return hnotfound(c); if(hsettype(c, "text/html") < 0){ vtlogclose(l); return -1; } vtloghdump(&c->hout, l); vtlogclose(l); hflush(&c->hout); return 0; }
void main(int argc, char **argv) { fmtinstall('H', httpfmt); fmtinstall('U', hurlfmt); if(argc == 2){ hinit(&houtb, 1, Hwrite); hout = &houtb; doconvert(argv[1], 0); exits(nil); } close(2); connect = init(argc, argv); hout = &connect->hout; if(hparseheaders(connect, HSTIMEOUT) < 0) exits("failed"); if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0){ hunallowed(connect, "GET, HEAD"); exits("not allowed"); } if(connect->head.expectother || connect->head.expectcont){ hfail(connect, HExpectFail, nil); exits("failed"); } bind("/usr/web/sys/man", "/sys/man", MREPL); if(connect->req.search != nil) dosearch(connect->req.vermaj, connect->req.search); else doconvert(connect->req.uri, connect->req.vermaj); hflush(hout); writelog(connect, "200 man2html %ld %ld\n", hout->seek, hout->seek); exits(nil); }
void httpproc(void *v) { HConnect *c; int ok, i, n; c = v; for(;;){ /* * No timeout because the signal appears to hit every * proc, not just us. */ if(hparsereq(c, 0) < 0) break; for(i = 0; i < MaxObjs && objs[i].name[0]; i++){ n = strlen(objs[i].name); if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0) || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){ ok = (*objs[i].f)(c); goto found; } } ok = fromwebdir(c); found: hflush(&c->hout); if(c->head.closeit) ok = -1; hreqcleanup(c); if(ok < 0) break; } hreqcleanup(c); close(c->hin.fd); free(c); }
/* * send back a nice error message if the content is unacceptable * to get this message in ie, go to tools, internet options, advanced, * and turn off Show Friendly HTTP Error Messages under the Browsing category */ static int notaccept(HConnect *c, HContent *type, HContent *enc, char *which) { Hio *hout; char *s, *e; hout = &c->hout; e = &c->xferbuf[HBufSize]; s = c->xferbuf; s = seprint(s, e, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"); s = seprint(s, e, "<html>\n<title>Unacceptable %s</title>\n<body>\n", which); s = seprint(s, e, "Your browser will not accept this data, %H, because of its %s.<br>\n", c->req.uri, which); s = seprint(s, e, "Its Content-Type is %s/%s", type->generic, type->specific); if(enc != nil) s = seprint(s, e, ", and Content-Encoding is %s", enc->generic); s = seprint(s, e, ".<br>\n\n"); s = acceptcont(s, e, c->head.oktype, "Content-Type"); s = acceptcont(s, e, c->head.okencode, "Content-Encoding"); s = seprint(s, e, "</body>\n</html>\n"); hprint(hout, "%s 406 Not Acceptable\r\n", hversion); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "Content-Type: text/html\r\n"); hprint(hout, "Content-Length: %lud\r\n", s - c->xferbuf); if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); if(strcmp(c->req.meth, "HEAD") != 0) hwrite(hout, c->xferbuf, s - c->xferbuf); writelog(c, "Reply: 406 Not Acceptable\nReason: %s\n", which); return hflush(hout); }
static int herror(HConnect *c) { int n; Hio *hout; hout = &c->hout; n = snprint(c->xferbuf, HBufSize, "<html><head><title>Error</title></head>\n<body><h1>Error</h1>\n<pre>%r</pre>\n</body></html>"); hprint(hout, "%s %s\r\n", hversion, "400 Bad Request"); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "Server: Venti\r\n"); hprint(hout, "Content-Type: text/html\r\n"); hprint(hout, "Content-Length: %d\r\n", n); if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0) hwrite(hout, c->xferbuf, n); return hflush(hout); }
/* * convert a man page to html and output */ void doconvert(char *uri, int vermaj) { char *p; char file[256]; char title[256]; char err[ERRMAX]; int pfd[2]; Dir *d; Waitmsg *w; int x; if(strstr(uri, "..")) error("bad URI", "man page URI cannot contain .."); p = strstr(uri, "/intro"); if(p == nil){ while(*uri == '/') uri++; /* redirect section requests */ snprint(file, sizeof(file), "/sys/man/%s", uri); d = dirstat(file); if(d == nil){ strlwr(file); if(dirstat(file) != nil){ snprint(file, sizeof(file), "/magic/man2html/%s", uri); strlwr(file); redirectto(file); } error(uri, "man page not found"); } x = d->qid.type; free(d); if(x & QTDIR){ if(*uri == 0 || strcmp(uri, "/") == 0) redirectto("/sys/man/index.html"); else { snprint(file, sizeof(file), "/sys/man/%s/INDEX.html", uri+1); redirectto(file); } return; } } else { /* rewrite the name intro */ *p = 0; snprint(file, sizeof(file), "/sys/man/%s/0intro", uri); d = dirstat(file); free(d); if(d == nil) error(uri, "man page not found"); } if(vermaj){ hokheaders(connect); hprint(hout, "Content-type: text/html\r\n"); hprint(hout, "\r\n"); } hflush(hout); if(pipe(pfd) < 0) error("out of resources", "pipe failed"); /* troff -manhtml <file> | troff2html -t '' */ switch(fork()){ case -1: error("out of resources", "fork failed"); case 0: snprint(title, sizeof(title), "Plan 9 %s", file); close(0); dup(pfd[0], 0); close(pfd[0]); close(pfd[1]); execl("/bin/troff2html", "troff2html", "-t", title, nil); errstr(err, sizeof err); exits(err); } switch(fork()){ case -1: error("out of resources", "fork failed"); case 0: snprint(title, sizeof(title), "Plan 9 %s", file); close(0); close(1); dup(pfd[1], 1); close(pfd[0]); close(pfd[1]); execl("/bin/troff", "troff", "-manhtml", file, nil); errstr(err, sizeof err); exits(err); } close(pfd[0]); close(pfd[1]); /* wait for completion */ for(;;){ w = wait(); if(w == nil) break; if(w->msg[0] != 0) print("whoops %s\n", w->msg); free(w); } }
int main(void) { static const int size[] = { 1, 13, 403, 999, 30000 }; char buffer[40000]; char *original; int c, i; ssize_t n; off_t off; reopen("vcf.c", "test/hfile1.tmp"); while ((c = hgetc(fin)) != EOF) { if (hputc(c, fout) == EOF) fail("hputc"); } if (herrno(fin)) { errno = herrno(fin); fail("hgetc"); } reopen("test/hfile1.tmp", "test/hfile2.tmp"); if (hpeek(fin, buffer, 50) < 0) fail("hpeek"); while ((n = hread(fin, buffer, 17)) > 0) { if (hwrite(fout, buffer, n) != n) fail("hwrite"); } if (n < 0) fail("hread"); reopen("test/hfile2.tmp", "test/hfile3.tmp"); while ((n = hread(fin, buffer, sizeof buffer)) > 0) { if (hwrite(fout, buffer, n) != n) fail("hwrite"); if (hpeek(fin, buffer, 700) < 0) fail("hpeek"); } if (n < 0) fail("hread"); reopen("test/hfile3.tmp", "test/hfile4.tmp"); i = 0; off = 0; while ((n = hread(fin, buffer, size[i++ % 5])) > 0) { off += n; buffer[n] = '\0'; check_offset(fin, off, "pre-peek"); if (hputs(buffer, fout) == EOF) fail("hputs"); if ((n = hpeek(fin, buffer, size[(i+3) % 5])) < 0) fail("hpeek"); check_offset(fin, off, "post-peek"); } if (n < 0) fail("hread"); reopen("test/hfile4.tmp", "test/hfile5.tmp"); n = hread(fin, buffer, 200); if (n < 0) fail("hread"); else if (n != 200) fail("hread only got %d", (int)n); if (hwrite(fout, buffer, 1000) != 1000) fail("hwrite"); check_offset(fin, 200, "input/first200"); check_offset(fout, 1000, "output/first200"); if (hseek(fin, 800, SEEK_CUR) < 0) fail("hseek/cur"); check_offset(fin, 1000, "input/seek"); for (off = 1000; (n = hread(fin, buffer, sizeof buffer)) > 0; off += n) if (hwrite(fout, buffer, n) != n) fail("hwrite"); if (n < 0) fail("hread"); check_offset(fin, off, "input/eof"); check_offset(fout, off, "output/eof"); if (hseek(fin, 200, SEEK_SET) < 0) fail("hseek/set"); if (hseek(fout, 200, SEEK_SET) < 0) fail("hseek(output)"); check_offset(fin, 200, "input/backto200"); check_offset(fout, 200, "output/backto200"); n = hread(fin, buffer, 800); if (n < 0) fail("hread"); else if (n != 800) fail("hread only got %d", (int)n); if (hwrite(fout, buffer, 800) != 800) fail("hwrite"); check_offset(fin, 1000, "input/wrote800"); check_offset(fout, 1000, "output/wrote800"); if (hflush(fout) == EOF) fail("hflush"); original = slurp("vcf.c"); for (i = 1; i <= 5; i++) { char *text; sprintf(buffer, "test/hfile%d.tmp", i); text = slurp(buffer); if (strcmp(original, text) != 0) { fprintf(stderr, "%s differs from vcf.c\n", buffer); return EXIT_FAILURE; } free(text); } free(original); if (hclose(fin) != 0) fail("hclose(input)"); if (hclose(fout) != 0) fail("hclose(output)"); fout = hopen("test/hfile_chars.tmp", "w"); if (fout == NULL) fail("hopen(\"test/hfile_chars.tmp\")"); for (i = 0; i < 256; i++) if (hputc(i, fout) != i) fail("chars: hputc (%d)", i); if (hclose(fout) != 0) fail("hclose(test/hfile_chars.tmp)"); fin = hopen("test/hfile_chars.tmp", "r"); if (fin == NULL) fail("hopen(\"test/hfile_chars.tmp\") for reading"); for (i = 0; i < 256; i++) if ((c = hgetc(fin)) != i) fail("chars: hgetc (%d = 0x%x) returned %d = 0x%x", i, i, c, c); if ((c = hgetc(fin)) != EOF) fail("chars: hgetc (EOF) returned %d", c); if (hclose(fin) != 0) fail("hclose(test/hfile_chars.tmp) for reading"); fin = hopen("data:hello, world!\n", "r"); if (fin == NULL) fail("hopen(\"data:...\")"); n = hread(fin, buffer, 300); if (n < 0) fail("hread"); buffer[n] = '\0'; if (strcmp(buffer, "hello, world!\n") != 0) fail("hread result"); if (hclose(fin) != 0) fail("hclose(\"data:...\")"); return EXIT_SUCCESS; }
static int xgraph(HConnect *c) { char *name; Hio *hout; Memimage *m; int dotext; Graph g; Arg arg; char *graph, *a; name = hargstr(c, "arg", ""); if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){ werrstr("unknown name %s", name); goto error; } a = hargstr(c, "arg2", ""); if(a[0] && (arg.index2 = findname(a)) == -1){ werrstr("unknown name %s", a); goto error; } g.arg = &arg; g.t0 = hargint(c, "t0", -120); g.t1 = hargint(c, "t1", 0); g.min = hargint(c, "min", -1); g.max = hargint(c, "max", -1); g.wid = hargint(c, "wid", -1); g.ht = hargint(c, "ht", -1); dotext = hargstr(c, "text", "")[0] != 0; g.fill = hargint(c, "fill", -1); graph = hargstr(c, "graph", "raw"); if(strcmp(graph, "raw") == 0) g.fn = rawgraph; else if(strcmp(graph, "diskbw") == 0) g.fn = diskgraph; else if(strcmp(graph, "iobw") == 0) g.fn = iograph; else if(strcmp(graph, "netbw") == 0) g.fn = netgraph; else if(strcmp(graph, "diff") == 0) g.fn = diffgraph; else if(strcmp(graph, "pct") == 0) g.fn = pctgraph; else if(strcmp(graph, "pctdiff") == 0) g.fn = pctdiffgraph; else if(strcmp(graph, "divdiff") == 0) g.fn = divdiffgraph; else{ werrstr("unknown graph %s", graph); goto error; } if(dotext){ hsettype(c, "text/plain"); dotextbin(&c->hout, &g); hflush(&c->hout); return 0; } m = statgraph(&g); if(m == nil) goto error; if(hsettype(c, "image/png") < 0) return -1; hout = &c->hout; writepng(hout, m); qlock(&memdrawlock); freememimage(m); qunlock(&memdrawlock); hflush(hout); return 0; error: return herror(c); }
static void debugread(HConnect *c, u8int *score) { int type; Lump *u; IAddr ia; IEntry ie; int i; Arena *arena; u64int aa; ZBlock *zb; Clump cl; vlong off; u8int sc[VtScoreSize]; if(scorecmp(score, zeroscore) == 0){ hprint(&c->hout, "zero score\n"); return; } hprint(&c->hout, "<h2>index search %V</h2><pre>\n", score); if(icachelookup(score, -1, &ia) < 0) hprint(&c->hout, " icache: not found\n"); else hprint(&c->hout, " icache: addr=%#llx size=%d type=%d blocks=%d\n", ia.addr, ia.size, ia.type, ia.blocks); if(loadientry(mainindex, score, -1, &ie) < 0) hprint(&c->hout, " idisk: not found\n"); else hprint(&c->hout, " idisk: addr=%#llx size=%d type=%d blocks=%d\n", ie.ia.addr, ie.ia.size, ie.ia.type, ie.ia.blocks); hprint(&c->hout, "</pre><h2>lookup %V</h2>\n", score); hprint(&c->hout, "<pre>\n"); for(type=0; type < VtMaxType; type++){ hprint(&c->hout, "%V type %d:", score, type); u = lookuplump(score, type); if(u->data != nil) hprint(&c->hout, " +cache"); else hprint(&c->hout, " -cache"); putlump(u); if(lookupscore(score, type, &ia) < 0){ hprint(&c->hout, " -lookup\n"); continue; } hprint(&c->hout, "\n lookupscore: addr=%#llx size=%d blocks=%d\n", ia.addr, ia.size, ia.blocks); arena = amapitoa(mainindex, ia.addr, &aa); if(arena == nil){ hprint(&c->hout, " amapitoa failed: %r\n"); continue; } hprint(&c->hout, " amapitoa: aa=%#llx arena=" "<a href=\"/disk?disk=%s&type=a&arena=%s&score=%V\">%s</a>\n", aa, arena->part->name, arena->name, score, arena->name); zb = loadclump(arena, aa, ia.blocks, &cl, sc, 1); if(zb == nil){ hprint(&c->hout, " loadclump failed: %r\n"); continue; } hprint(&c->hout, " loadclump: uncsize=%d type=%d score=%V\n", cl.info.uncsize, cl.info.type, sc); if(ia.size != cl.info.uncsize || ia.type != cl.info.type || scorecmp(score, sc) != 0){ hprint(&c->hout, " clump info mismatch\n"); continue; } } if(hargstr(c, "brute", "")[0] == 'y'){ hprint(&c->hout, "</pre>\n"); hprint(&c->hout, "<h2>brute force arena search %V</h2>\n", score); hprint(&c->hout, "<pre>\n"); for(i=0; i<mainindex->narenas; i++){ arena = mainindex->arenas[i]; hprint(&c->hout, "%s...\n", arena->name); hflush(&c->hout); off = findintoc(nil, arena, score); if(off >= 0) hprint(&c->hout, "%s %#llx (%#llx)\n", arena->name, off, mainindex->amap[i].start + off); } } hprint(&c->hout, "</pre>\n"); }
/* * fd references a file which has been authorized & checked for relocations. * send back the headers & its contents. * includes checks for conditional requests & ranges. */ int sendfd(HConnect *c, int fd, Dir *dir, HContent *type, HContent *enc) { Qid qid; HRange *r; HContents conts; Hio *hout; char *boundary, etag[32]; long mtime; ulong tr; int n, nw, multir, ok; vlong wrote, length; hout = &c->hout; length = dir->length; mtime = dir->mtime; qid = dir->qid; free(dir); /* * figure out the type of file and send headers */ n = -1; r = nil; multir = 0; boundary = nil; if(c->req.vermaj){ if(type == nil && enc == nil){ conts = uriclass(c, c->req.uri); type = conts.type; enc = conts.encoding; if(type == nil && enc == nil){ n = read(fd, c->xferbuf, HBufSize-1); if(n > 0){ c->xferbuf[n] = '\0'; conts = dataclass(c, c->xferbuf, n); type = conts.type; enc = conts.encoding; } } } if(type == nil) type = hmkcontent(c, "application", "octet-stream", nil); snprint(etag, sizeof(etag), "\"%lluxv%lux\"", qid.path, qid.vers); ok = checkreq(c, type, enc, mtime, etag); if(ok <= 0){ close(fd); return ok; } /* * check for if-range requests */ if(c->head.range == nil || c->head.ifrangeetag != nil && !etagmatch(1, c->head.ifrangeetag, etag) || c->head.ifrangedate != 0 && c->head.ifrangedate != mtime){ c->head.range = nil; c->head.ifrangeetag = nil; c->head.ifrangedate = 0; } if(c->head.range != nil){ c->head.range = fixrange(c->head.range, length); if(c->head.range == nil){ if(c->head.ifrangeetag == nil && c->head.ifrangedate == 0){ hprint(hout, "%s 416 Request range not satisfiable\r\n", hversion); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Content-Range: bytes */%lld\r\n", length); hprint(hout, "Content-Length: %d\r\n", STRLEN(BADRANGE)); hprint(hout, "Content-Type: text/html\r\n"); if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); if(strcmp(c->req.meth, "HEAD") != 0) hprint(hout, "%s", BADRANGE); hflush(hout); writelog(c, "Reply: 416 Request range not satisfiable\n"); close(fd); return 1; } c->head.ifrangeetag = nil; c->head.ifrangedate = 0; } } if(c->head.range == nil) hprint(hout, "%s 200 OK\r\n", hversion); else hprint(hout, "%s 206 Partial Content\r\n", hversion); hprint(hout, "Server: Plan9\r\n"); hprint(hout, "Date: %D\r\n", time(nil)); hprint(hout, "ETag: %s\r\n", etag); /* * can't send some entity headers if partially responding * to an if-range: etag request */ r = c->head.range; if(r == nil) hprint(hout, "Content-Length: %lld\r\n", length); else if(r->next == nil){ hprint(hout, "Content-Range: bytes %ld-%ld/%lld\r\n", r->start, r->stop, length); hprint(hout, "Content-Length: %ld\r\n", r->stop - r->start); }else{ multir = 1; boundary = hmkmimeboundary(c); hprint(hout, "Content-Type: multipart/byteranges; boundary=%s\r\n", boundary); } if(c->head.ifrangeetag == nil){ hprint(hout, "Last-Modified: %D\r\n", mtime); if(!multir) printtype(hout, type, enc); if(c->head.fresh_thresh) hintprint(c, hout, c->req.uri, c->head.fresh_thresh, c->head.fresh_have); } if(c->head.closeit) hprint(hout, "Connection: close\r\n"); else if(!http11(c)) hprint(hout, "Connection: Keep-Alive\r\n"); hprint(hout, "\r\n"); } if(strcmp(c->req.meth, "HEAD") == 0){ if(c->head.range == nil) writelog(c, "Reply: 200 file 0\n"); else writelog(c, "Reply: 206 file 0\n"); hflush(hout); close(fd); return 1; } /* * send the file if it's a normal file */ if(r == nil){ hflush(hout); wrote = 0; if(n > 0) wrote = write(hout->fd, c->xferbuf, n); if(n <= 0 || wrote == n){ while((n = read(fd, c->xferbuf, HBufSize)) > 0){ nw = write(hout->fd, c->xferbuf, n); if(nw != n){ if(nw > 0) wrote += nw; break; } wrote += nw; } } writelog(c, "Reply: 200 file %lld %lld\n", length, wrote); close(fd); if(length == wrote) return 1; return -1; } /* * for multipart/byterange messages, * it is not ok for the boundary string to appear within a message part. * however, it probably doesn't matter, since there are lengths for every part. */ wrote = 0; ok = 1; for(; r != nil; r = r->next){ if(multir){ hprint(hout, "\r\n--%s\r\n", boundary); printtype(hout, type, enc); hprint(hout, "Content-Range: bytes %ld-%ld/%lld\r\n", r->start, r->stop, length); hprint(hout, "Content-Length: %ld\r\n", r->stop - r->start); hprint(hout, "\r\n"); } hflush(hout); if(seek(fd, r->start, 0) != r->start){ ok = -1; break; } for(tr = r->stop - r->start + 1; tr; tr -= n){ n = tr; if(n > HBufSize) n = HBufSize; if(read(fd, c->xferbuf, n) != n){ ok = -1; goto breakout; } nw = write(hout->fd, c->xferbuf, n); if(nw != n){ if(nw > 0) wrote += nw; ok = -1; goto breakout; } wrote += nw; } } breakout:; if(r == nil){ if(multir){ hprint(hout, "--%s--\r\n", boundary); hflush(hout); } writelog(c, "Reply: 206 partial content %lld %lld\n", length, wrote); }else writelog(c, "Reply: 206 partial content, early termination %lld %lld\n", length, wrote); close(fd); return ok; }
static void dols(char *dir) { Dir *d; char *f, *p,*nm; long i, n; int fd; cleanname(dir); // expands "" to "."; ``dir+1'' access below depends on that if (!allowed(dir)) { error("Permission denied", "<p>Cannot list directory %s: Access prohibited</p>", dir); return; } fd = open(dir, OREAD); if (fd < 0) { error("Cannot read directory", "<p>Cannot read directory %s: %r</p>", dir); return; } if (vermaj) { hokheaders(connect); hprint(hout, "Content-type: text/html\r\n"); hprint(hout, "\r\n"); } doctype(); hprint(hout, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"); hprint(hout, "<head><title>Index of %s</title></head>\n", dir); hprint(hout, "<body>\n"); hprint(hout, "<h1>Index of "); nm = dir; while((p = strchr(nm, '/')) != nil){ *p = '\0'; f = (*dir == '\0') ? "/" : dir; if (!(*dir == '\0' && *(dir+1) == '\0') && allowed(f)) hprint(hout, "<a href=\"/magic/webls?dir=%H\">%s/</a>", f, nm); else hprint(hout, "%s/", nm); *p = '/'; nm = p+1; } hprint(hout, "%s</h1>\n", nm); n = dirreadall(fd, &d); close(fd); maxwidths(d, n); qsort(d, n, sizeof(Dir), (int (*)(void *, void *))compar); hprint(hout, "<pre>\n"); for (i = 0; i < n; i++) { f = smprint("%s/%s", dir, d[i].name); cleanname(f); if (d[i].mode & DMDIR) { p = smprint("/magic/webls?dir=%H", f); free(f); f = p; } hprint(hout, "%M %C %*ud %-*s %-*s %*lld %s <a href=\"%s\">%s</a>\n", d[i].mode, d[i].type, devwidth, d[i].dev, uidwidth, d[i].uid, gidwidth, d[i].gid, lenwidth, d[i].length, asciitime(d[i].mtime), f, d[i].name); free(f); } f = smprint("%s/..", dir); cleanname(f); if (strcmp(f, dir) != 0 && allowed(f)) hprint(hout, "\nGo to <a href=\"/magic/webls?dir=%H\">parent</a> directory\n", f); else hprint(hout, "\nEnd of directory listing\n"); free(f); hprint(hout, "</pre>\n</body>\n</html>\n"); hflush(hout); free(d); }
void main(int argc, char **argv) { HConnect *c; Dir *dir; Hio *hin, *hout; char *s, *t, *fn; int n, nfn, datafd, htmlfd; c = init(argc, argv); if(dangerous(c->req.uri)){ hfail(c, HSyntax); exits("failed"); } if(hparseheaders(c, HSTIMEOUT) < 0) exits("failed"); hout = &c->hout; if(c->head.expectother){ hfail(c, HExpectFail, nil); exits("failed"); } if(c->head.expectcont){ hprint(hout, "100 Continue\r\n"); hprint(hout, "\r\n"); hflush(hout); } s = nil; if(strcmp(c->req.meth, "POST") == 0){ hin = hbodypush(&c->hin, c->head.contlen, c->head.transenc); if(hin != nil){ alarm(HSTIMEOUT); s = hreadbuf(hin, hin->pos); alarm(0); } if(s == nil){ hfail(c, HBadReq, nil); exits("failed"); } t = strchr(s, '\n'); if(t != nil) *t = '\0'; }else if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0){ hunallowed(c, "GET, HEAD, PUT"); exits("unallowed"); }else s = c->req.search; if(s == nil){ hfail(c, HNoData, "save"); exits("failed"); } if(strlen(s) > MaxLog) s[MaxLog] = '\0'; n = snprint(c->xferbuf, HBufSize, "at %ld %s\n", time(0), s); nfn = strlen(c->req.uri) + 64; fn = halloc(c, nfn); /* * open file descriptors & write log line */ snprint(fn, nfn, "/usr/web/save/%s.html", c->req.uri); htmlfd = open(fn, OREAD); if(htmlfd < 0 || (dir = dirfstat(htmlfd)) == nil){ hfail(c, HNotFound, c->req.uri); exits("failed"); return; } snprint(fn, nfn, "/usr/web/save/%s.data", c->req.uri); datafd = openLocked(fn, OWRITE); if(datafd < 0){ errstr(c->xferbuf, sizeof c->xferbuf); if(strstr(c->xferbuf, "locked") != nil) hfail(c, HTempFail, c->req.uri); else hfail(c, HNotFound, c->req.uri); exits("failed"); } seek(datafd, 0, 2); write(datafd, c->xferbuf, n); close(datafd); sendfd(c, htmlfd, dir, hmkcontent(c, "text", "html", nil), nil); exits(nil); }
static int estats(HConnect *c) { Hio *hout; int r; r = hsettext(c); if(r < 0) return r; hout = &c->hout; /* hprint(hout, "lump writes=%,ld\n", stats.lumpwrites); hprint(hout, "lump reads=%,ld\n", stats.lumpreads); hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit); hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss); hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites); hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites); hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp); hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads); hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads); hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp); hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites); hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads); hprint(hout, "index disk writes=%,ld\n", stats.indexwrites); hprint(hout, "index disk reads=%,ld\n", stats.indexreads); hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n", stats.indexbloomhits, percent(stats.indexbloomhits, stats.indexreads), stats.indexbloomfalsemisses, percent(stats.indexbloomfalsemisses, stats.indexreads)); hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n", stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits)); hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads); hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads); hprint(hout, "index block splits=%,ld\n", stats.indexsplits); hprint(hout, "index cache lookups=%,ld\n", stats.iclookups); hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits, percent(stats.ichits, stats.iclookups)); hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills, percent(stats.icfills, stats.iclookups)); hprint(hout, "index cache inserts=%,ld\n", stats.icinserts); hprint(hout, "disk cache hits=%,ld\n", stats.pchit); hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss); hprint(hout, "disk cache reads=%,ld\n", stats.pcreads); hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads); hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks); hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites, percent(stats.absorbedwrites, stats.dirtydblocks)); hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes); hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n", stats.dcacheflushwrites, stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1)); hprint(hout, "disk writes=%,ld\n", stats.diskwrites); hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites); hprint(hout, "disk reads=%,ld\n", stats.diskreads); hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads); */ hflush(hout); return 0; }