CD001UTF8 9CD 00 &'"%%k !9VOLUMESET 9PUBLISHER DUMP9660 DUMP9660 2007091800330500200709180033050000000000000000000000000000000000ÿCD001#include #include #include #include #include <9p.h> #include #include "dat.h" #include "fns.h" Aux* new_aux(int type, void *data, void (*free)(void*)) { Aux *a = (Aux*)malloc(sizeof(Aux)); a->type = type; a->data = data; a->free = free; return a; } Host* new_host(char *name, char *owner) { Host *h = nil; if(name && owner) { h = (Host*)malloc(sizeof(Host)); if(h) { h->name = smprint("%s", name); h->owner = smprint("%s", owner); h->request_id = 0; h->requests = chancreate(sizeof(ulong), 0); } } return h; } void free_host(void *v) { Host *host = (Host*)v; if(host) { free(host->name); free(host->owner); free(host); } } ulong next_request_id(Host *h) { return h ? h->request_id++ : 0; // is ++ threadsafe ? } Response * new_response(int action, ulong datasize) { Response *r = (Response*)mallocz(sizeof(Response), 1); if(r && !(r->data = new_data(datasize))) r = free_response(r); if(r) r->action = action; return r; } Response * free_response(Response *r) { if(r) { free_data(r->data); free(r); } return nil; } Action * free_action(Action *a) { if(a) { free_data(a->data); free(a); } return nil; } Data * new_data(uint datasize) { Data *d = (Data*)mallocz(sizeof(Data), 1); if (d && datasize > 0) { d->bytes = (char*)mallocz(datasize, 1); if(d->bytes) d->length = datasize; else { free(d); d = nil; } } return d; } Data * free_data(Data *d) { if(d) free(d->bytes); free(d); return nil; } Header * free_header(Header *h) { if(h) free(h->_allocated); free(h); return nil; } Header * new_header(Header *parent, char *line, int length) { Header *h; char *split[2]; if(!line) return nil; if(length < 2) { free(line); return nil; } h = (Header*)mallocz(sizeof(Header), 1); if(!h) { free(line); return nil; } h->_allocated = line; if(line[0] == ' ' || line[0] == ' ') { // HTTP Continuation if(parent) { h->_allocated = smprint("%s%c%s %s", parent->name, 0, parent->value, line); free(parent->_allocated); parent->_allocated = h->_allocated; h->_allocated = nil; } free(h); free(line); return parent; } int fields = getfields(line, split, 2, 0, ":"); if(fields != 2) { free(line); free(h); return nil; } h->name = trim(line, split[1]); to_lower(h->name, split[1]); h->value = trim(split[1], &line[length]); if(parent) parent->next = h; return h; } int free_headers(Header *h) { int i =0; if(!h) return 0; i += free_headers(h->next); free_header(h); return i; } void destroy_request(void *v) { if(!v) return; Request *r = (Request*)v; free_data(r->content); free(r->method); free(r->uri_decoded); free_headers(r->headers); remove_tree(r->dir); free(r); } Request * new_request(int fd) { Request *r = (Request*)mallocz(sizeof(Request), 1); if(r) r->fd = fd; return r; } void free_datachain(void *v) { Data *d, *datachain = (Data*) v; while(datachain) { d = datachain->next; free(datachain); datachain = d; } } #define MAX_UPLOAD 100000000 enum { STACK = 16384, }; enum { QCtl, QHost, QRequestList, QRequest, QResponse, QClient, QValue, QUridecoded, }; enum { ANewRequest, ARead, AWrite, AProceed, AResponded, }; enum { XHost, XCtrl, XResponse, XRequest, XRequestList, XString, XClient, XUridecoded, }; typedef struct Aux Aux; typedef struct Host Host; typedef struct Header Header; typedef struct Data Data; typedef struct Action Action; typedef struct Request Request; typedef struct Response Response; struct Aux { int type; void *data; void (*free)(void*); }; struct Host { char *name; char *owner; Channel *requests; ulong request_id; File *dir; }; struct Action { int id; Data *data; }; struct Data { char *bytes; int length; Data *next; }; struct Header { char *name; char *value; Header *next; char *_allocated; }; struct Request { int fd; char *method; char *uri; char *uri_decoded; char *http_version; File *dir; Header *headers; Data *content; }; struct Response { int action; Data *data; }; extern Srv fs; #include #include #include #include #include <9p.h> #include #include "dat.h" #include "fns.h" Data * add_datablock(Data *parent, u32int datasize, char *src) { Data *d; if(parent && !parent->bytes) d = parent; else d = (Data*)mallocz(sizeof(Data), 1); if (d && datasize > 0) { d->bytes = (char*)mallocz(datasize, 1); if(d->bytes) d->length = datasize; else { free(d); d = nil; } } if(parent && d != parent) { Data *last = last_link(parent); last->next = d; } if(d && d->bytes && (datasize > 0) && src) memcpy(d->bytes, src, datasize); return d; } void print_data(void*v) { Data *d = (Data*)v; for(; d; d = d->next) { fprint(2, "Block %p %d '", d->bytes, d->length); fprint_nbytes(2, d->bytes, d->length); fprint(2, "'\n"); } } Data* last_link(Data *d) { while(d->bytes && d->next) d = d->next; return d; } Data * data_start(vlong *poffset, Data *d, u32int count, u32int *available) { vlong offset = *poffset; fprint(2, "offset %ld\n", (ulong)offset); fprint(2, " count %ld\n", (ulong)count); if(!d) { fprint(2, "d nil\n"); *available = 0; return nil; } if(offset >= d->length) return data_start(offset - d->length, d->next, count, available); if(count > (d->length - offset)) *available = d->length - offset; else *available = count; *poffset = offset; return d; } void compact_chain(Data *d, vlong offset) { // probably needs locks Data *dp; vlong p = 0; fprint(2, "compact_chain d->length %d offset %ld\n", d->length, (ulong)offset); for(p = d->length; p < offset && d->next; ) { dp = d->next; p += dp->length; if(p > offset) break; d->length += dp->length; free(dp->bytes); d->next = dp->next; free(dp); } } // dat.c Aux* new_aux(int type, void *data, void (*free)(void*)); Host* new_host(char *name, char *owner); ulong next_request_id(Host *h); // probably needs locking void free_host(void *v); Response *new_response(int action, ulong datasize); Response *free_response(Response *r); Action *free_action(Action *a); Data *new_data(uint datasize); Data *free_data(Data *d); Header *free_header(Header *h); Header *new_header(Header *parent, char *line, int length); int free_headers(Header *h); void destroy_request(void*v); void free_datachain(void *v); Request *new_request(int fd); // fs.c void fssend(Req *r); void initfs(void); static void fsthread(void*); static void fsread(Req *r); static void fswrite(Req *r); static void fsremove(Req *r); File *get_or_create_host(char *name, char *owner); File *host_dir(char *host); Host *host(File *hdir); void remove_tree(File *dir); ulong create_request(Request *r); int create_request_tree(File *dir); int create_header_files(File *dir, Request *r); // http.c void http_listener(void); void http_listen(void*v); void http_service(int fd); char* header_value(Header *header, char *key); int header_to_long(Header *header, char *key); int print_headers(Header *header); void parse_action(Request *r, Biobuf *b); Header* parse_headers(Biobuf *b); // utils.c char *trim(char *start, char *end); void to_lower(char *c, char *end); char *url_decode(char *encoded); void fprint_nbytes(int fd, char *bytes, int n); // datachain.c Data *add_datablock(Data *parent, u32int datasize, char *src); Data *data_start(Data *d, u32int count, u32int *available); Data *last_link(Data *d); void print_data(void*v); void compact_chain(Data *d, vlong offset); // probably needs locks#include #include #include #include #include <9p.h> #include #include "dat.h" #include "fns.h" Channel *creq; Channel *creqwait; Channel *http_requests; Channel *http_continue; Srv fs = { .read = fssend, .write = fssend, .remove = fssend, }; void fssend(Req *r) { sendp(creq, r); recvp(creqwait); } File * get_or_create_host(char *name, char *owner) { if(!fs.tree->root || !owner || !name) return nil; incref(fs.tree->root); File *host_dir = walkfile(fs.tree->root, name); if(!host_dir) { host_dir = createfile(fs.tree->root, name, owner, DMDIR|0500, new_aux(XHost, new_host(name, owner), free_host)); if(host_dir) { File *f = createfile(host_dir, "request_list", host_dir->uid, 0400, new_aux(XRequestList, add_datablock(nil, 0, nil), free_datachain)); if(!f) return 0; decref(f); } } return host_dir; } ulong create_request(Request *r) { ulong id = 0; File *rdir = nil; Host * h = nil; File *hdir = nil; if(r) hdir = host_dir(header_value(r->headers, "host")); if(hdir) h = host(hdir); if(h) { id = next_request_id(h); char *name = smprint("%uld", id); if(name) { rdir = createfile(hdir, name, hdir->uid, DMDIR|0600, new_aux(XRequest, (void*)r, destroy_request)); free(name); } } if(rdir) { create_request_tree(rdir); create_header_files(rdir, r); decref(rdir); } if(hdir) decref(hdir); sendul(http_requests, id); return id; } Host * host(File *hdir) { if(!hdir) return nil; Aux *a = (Aux*)hdir->aux; if(a && a->type == XHost) return a->data; } File * host_dir(char *name) { if(!fs.tree->root || !name) return nil; incref(fs.tree->root); File *host_dir = walkfile(fs.tree->root, name); if(!host_dir) { incref(fs.tree->root); host_dir = walkfile(fs.tree->root, "default"); } return host_dir; } void* find_X(File *f, int X) { if(!f) return nil; if(((Aux*)f->aux) && ((Aux*)f->aux)->type == X) return ((Aux*)f->aux)->data; if(f->parent && f != f->parent) return find_X(f->parent, X); return nil; } int create_request_tree(File *dir) { if(!dir) return 0; File *f = createfile(dir, ":response", dir->uid, DMEXCL|0200, new_aux(XResponse, nil, nil)); if(!f) return 0; decref(f); Request *r = (Request *)(((Aux*)dir->aux)->data); f = createfile(dir, ":method", dir->uid, 0400, new_aux(XString, r->method, free)); if(!f) return 0; decref(f); f = createfile(dir, ":uri", dir->uid, 0400, new_aux(XString, r->uri, nil)); if(!f) return 0; decref(f); f = createfile(dir, ":uri.decoded", dir->uid, 0400, new_aux(XUridecoded, nil, free)); if(!f) return 0; decref(f); f = createfile(dir, ":http_version", dir->uid, 0400, new_aux(XString, r->http_version, nil)); if(!f) return 0; decref(f); f = createfile(dir, ":request", dir->uid, DMEXCL|0400, new_aux(XClient, nil, free_datachain)); if(!f) return 0; decref(f); return 1; } int create_header_files(File *dir, Request *r) { Header *h; File *hf; int files=0; for(h = r->headers; h != nil; h = h->next) { if(h->name) { incref(dir); hf = walkfile(dir, h->name); if(hf) ((Aux*)hf->aux)->data = h->value; else { if(hf = createfile(dir, h->name, dir->uid, 0444, new_aux(XString, h->value, nil))) files++; } if(hf) decref(hf); } } return files; } void remove_tree(File *dir) { if(!dir) return; if(dir->qid.type & QTDIR) { File *f; Dir d; int i, k, u, n; uchar buf1[512]; char buf2[512]; Readdir *rd = opendirfile(dir); if(rd) { while(i = readdirfile(rd, &buf1[0], 512)) { n = 0; for(k = 0; k < i; k++) { u = convM2D(&buf1[n], i, &d, buf2); incref(dir); f = walkfile(dir, d.name); remove_tree(f); n += u; i -= u; } } closedirfile(rd); } } decref(dir); removefile(dir); } Data * read_content(Request *r) { if(!r || !r->headers) return nil; int content_length = header_to_long(r->headers, "content-length"); if(content_length < 1 || content_length > MAX_UPLOAD) return nil; Data *d = new_data(content_length); if(!d) return nil; int bytes_read = 0; char *read_pos = d->bytes; while(content_length && bytes_read != -1) { bytes_read = read(r->fd, read_pos, content_length); if(bytes_read > 0) { read_pos += bytes_read; content_length -= bytes_read; } } return d; } void send_bytes(Req *r, char *d, u32int i) { if(!r || !d) return; if(r->ifcall.offset < i) { r->ofcall.data = d + r->ifcall.offset; r->ofcall.count = i - r->ifcall.offset; if(r->ifcall.count < r->ofcall.count) r->ofcall.count = r->ifcall.count; } } void send_string(Req *req, char *s) { if(s) send_bytes(req, s, strlen(s)); } void send_data(Req *req, Data *d) { if(d) send_bytes(req, d->bytes, d->length); } void send_data_chain(Req *req, Data *d) { if(d) send_bytes(req, d->bytes, d->length); } static void fsread(Req *req) { File *f = req->fid->file; Aux *a = (Aux*)f->aux; Data *d, *e; u32int available; vlong offset; Request *r; switch(a->type) { case XUridecoded : if(!a->data && (r = (Request*)find_X(f, XRequest))) a->data = url_decode(r->uri); send_string(req, a->data); break; case XString : send_string(req, a->data); break; case XClient : if(!a->data) a->data = read_content((Request*)find_X(f, XRequest)); send_data(req, a->data); break; case XRequestList : fprint(2, "req->ifcall.offset %ld req->ifcall.count %ld\n", (long)req->ifcall.offset, (long)req->ifcall.count); d = (Data*)a->data; offset = req->ifcall.offset; // if(req->ifcall.offset < d->length && d->bytes==nil) { // respond(req, "Sorry, no seeking backwards"); // return; // } if(e = data_start(req->ifcall.offset, d, req->ifcall.count, &req->ofcall.count)) { send_data_chain(req, e); } else { fprint(2, "ok I'll wait\n"); ulong rid = recvul(http_requests); char *id = smprint("%ld\n", rid); if(id) { add_datablock(d, strlen(id), id); fprint(2, "added data\n"); print_data(d); free(id); sendp(creq, req); return; } } break; } respond(req, nil); } static void fswrite(Req *req) { File *f = req->fid->file; Aux *a = (Aux*)f->aux; Request *r; switch(a->type) { case XResponse : r = find_X(f, XRequest); req->ofcall.count = write(r->fd, req->ifcall.data, req->ifcall.count); break; } respond(req, nil); } static void fsremove(Req *req) { File *f = req->fid->file; Aux *a = (Aux*)f->aux; Request *r = nil; switch(a->type) { case XResponse : r = find_X(f, XRequest); break; } respond(req, nil); if(r) { close(r->fd); remove_tree(r->dir); } } void initfs(void) { File *f; http_requests = chancreate(sizeof(ulong), 10); http_continue = chancreate(sizeof(ulong), 10); creq = chancreate(sizeof(void*), 10); creqwait = chancreate(sizeof(void*), 10); fs.tree = alloctree("www", "www", DMDIR|0777, nil); f = createfile(fs.tree->root, "ctrl", "maht", 0600, new_aux(XCtrl, add_datablock(nil, 0, nil), free_datachain)); if(f) decref(f); f = get_or_create_host("default", "maht"); if(f) decref(f); procrfork(fsthread, nil, STACK, RFNAMEG); } static void fsthread(void*) { Req *req; threadsetname("fsthread"); proccreate(http_listen, nil, STACK); Alt a[3]; a[0].op = CHANRCV; a[0].c = creq; a[0].v = &req; a[1].op = CHANEND; for(;;){ switch(alt(a)){ case 1: break; case 0: if(req) switch(req->ifcall.type){ case Tread: fsread(req); break; case Twrite: fswrite(req); break; case Tremove: fsremove(req); break; default: respond(req, "bug in fsthread"); break; } sendp(creqwait, 0); break; } } } #include #include #include #include #include <9p.h> #include #include "dat.h" #include "fns.h" Channel *http_requests; Channel *http_continue; void http_service(int fd) { Biobuf b; Binit(&b, fd, OREAD); Request *request = new_request(fd); if(!request) return; parse_action(request, &b); request->headers = parse_headers(&b); Bterm(&b); create_request(request); } void http_listen(void*v) { ulong dfd; int acfd, lcfd; char adir[40], ldir[40]; acfd = announce("tcp!10.0.0.17!8110", adir); if(acfd < 0) { fprint(2, "Announce failed on tcp!10.0.0.17!8110\n"); threadexits(nil); } fprint(2, "Listening on tcp!10.0.0.17!8110 with pid %d\n", getpid()); for(;http_continue;) { lcfd = listen(adir, ldir); if(lcfd < 0) threadexits(nil); dfd = accept(lcfd, ldir); if(dfd < 0) threadexits(nil); http_service(dfd); close(lcfd); } } char* header_value(Header *header, char *key) { char *value=nil; char *next_value=nil; if(!header || !key) return nil; if(header->name && cistrcmp(header->name, key) == 0) value = header->value; if(header->next) { next_value = header_value(header->next, key); } return next_value ? next_value : value; } int header_to_long(Header *header, char *key) { char *h = header_value(header, key); if(h) return atol(h); return 0; } int print_headers(Header *header) { if(!header) return 0; if(header->name) fprint(2, "%s: ", header->name); else fprint(2, "REQUEST: "); if(header->value) fprint(2, "%s\n", header->value); else fprint(2, "\n"); fprint(2, "_a %p\n", header->_allocated); if(header->next) return 1 + print_headers(header->next); return 1; } void parse_action(Request *r, Biobuf *b) { int fields; char *split[3]; r->method = Brdstr(b, '\n', 1); if(!r->method) return; fields = getfields(r->method, split, 3, 0, " "); if(fields == 3) { *(split[1]-1) = '\0'; if(*(split[1]-2) == '\r') *(split[1]-2) = '\0'; r->uri = split[1]; *(split[2]-1) = '\0'; if(*(split[2]-2) == '\r') *(split[2]-2) = '\0'; r->http_version = split[2]; r->http_version[strlen(r->http_version)-1]= '\0'; } } Header* parse_headers(Biobuf *b) { Header *root, *h; root = new_header(nil, Brdstr(b, '\n', 1), Blinelen(b)); for(h = root; h; h = new_header(h, Brdstr(b, '\n', 1), Blinelen(b))); return root; } #!/bin/rc fn sendf { cat $1 > $response } fn requests { if(test -e /n/httpfs/default) for (r in `{ls /n/httpfs/default/*/:response >[2] /dev/null}) basename -d $r } fn httpok { echo 'HTTP 200 OK ' w = `{wc -c $1} echo 'Content-Length: ' $w(1) ^' ' echo 'Content-Type: ' ^`{file -m $1} ^' ' echo ' ' cat $1 echo ' ' } fn http404 { echo 'HTTP 404 NOT FOUND '' echo 'Content-Length: 10 '' echo 'Content-Type: text/plain ' echo ' ' echo 'Not found ' } fn respond { if(test -e $fname) httpok $fname if not http404 } while() { for(r in `{requests} ) { fname = /usr/maht/httpfs/www ^`{cat $r ^'/:uri' } echo $fname cat $r/:request respond > $r/:response rm $r/:response } sleep 5 } #!/bin/rc host = default host_dir = /n/httpfs/$host webroot = /usr/maht/httpfs/www fn requests { if(test -e $host_dir/request_list) { id = `{read $host_dir/request_list} builtin echo $id } } fn headers { for (e in $*) echo $e } fn httpok { w = `{wc -c $1} headers ('HTTP 200 OK' 'Content-Length: ' ^$w(1) 'Content-Type: ' ^`{file -m $1}) echo cat $1 } fn http404 { headers ('HTTP 404 NOT FOUND' 'Content-Length: 10' 'Content-Type: text/plain') echo echo Not found } fn respond { if(test -e $fname) httpok $fname if not http404 } cd $webroot while() { for(r in `{requests} ) { mk all fname = ^`{cat $host_dir/$r ^'/:uri' } respond > $host_dir/$r/:response rm $host_dir/$r/:response mk clean } } #!/bin/rc host = default host_dir = /n/httpfs/$host lib = /usr/maht/httpfs/lib webroot = /usr/maht/httpfs/www cacheroot = /usr/maht/httpfs/cache fn requests { if(test -e $host_dir/request_list) { id = `{read $host_dir/request_list} builtin echo $id } } fn headers { for (e in $*) echo $e } fn httpok { w = `{wc -c $1} headers ('HTTP 200 OK' 'Content-Length: ' ^$w(1) 'Content-Type: ' ^`{file -m $1}) echo cat $1 } fn http404 { headers ('HTTP 404 NOT FOUND' 'Content-Length: 10' 'Content-Type: text/plain') echo echo Not found } fn respond { if(test -e /n/www/$fname) httpok /n/www/$fname if not http404 } rm -rf $cacheroot/* bind $webroot /n/www bind $lib /n/lib bind -b -c $cacheroot /n/www cd /n/www while() { for(r in `{requests} ) { fname = `{cat $host_dir/$r ^'/:uri_decoded' | sed 's/^\///'} echo $fname echo $webroot/$fname if(! test -e $webroot/$fname) { fname = $fname.html mk $fname } respond > $host_dir/$r/:response rm $host_dir/$r/:response mk clean } } #include #include #include #include #include <9p.h> #include #include // mk ./8.out #include "dat.h" #include "fns.h" void threadmain(int argc, char *argv[]) { char *mtpt; initfs(); mtpt = "/n/httpfs"; threadpostmountsrv(&fs, "httpfs", mtpt, 0); threadexits(0); } Maht0x0r.net

ktnxbye

{ echo 'HEAD / HTTP/1.1 host: k '} | tcpcat tcp!10.0.0.17!8110 man webfs mk clean hget http://10.0.0.17:8110/index.html ; slay 8.out | rc ; cd; cd httpfs ; ./8.out ; cruft/httpd_listen ; ; telnet tcp!10.0.0.17!8110 GET /index.html HTTP/1.1 host: p #include #include #include char * trim(char *start, char *end) { char *c; for(; start && start < end && *start == ' '; start++); for(c = end - 1; c && c >= start && (*c=='\r' || *c=='\n'); *(c--)=0); return start; } void to_lower(char *c, char *end) { for(; c && c < end; c++) *c = tolower(*c); } char * url_decode(char *encoded) { if(!encoded) return nil; char *decoded = strdup(encoded); if(!decoded) return nil; char *d, *e; d = decoded; for(e = encoded; *e; e++, d++) { if(*e == '%') { if(*(e+1) && *(e+1) =='%') { *d = '%'; e++; } else if(*(e+1) && *(e+2) && isxdigit(*(e+1)) && isxdigit(*(e+2))) { *d = *(e+2) + *(e+1) << 4; e += 2; } else { return nil; } } else { *d = *e; } } *d = 0; return decoded; } void fprint_nbytes(int fd, char *bytes, uint n) { if(!bytes || !n) { fprint(fd, "nil"); return; }; int pagesize = 64000; char buff[64000 + 1]; int i; char *p; int pages = n / 64000; for(p = bytes, i = 0; i < pages; i++, p += pagesize) { memcpy(buff, p, pagesize); buff[pagesize+1] = 0; fprint(fd, "%s", buff); } pagesize = n - (pages * i); memcpy(buff, p, pagesize); buff[pagesize+1] = 0; fprint(fd, "%s", buff); }"%%k !"%%k !&á ák dat.c&..k dat.h,ÜÜk  datachain.c&¯¯k fns.h&©©k  fs.c(= =k  http.c*ÒÒk5httpd.rc.ççk5 httpd_listen0k5httpd_mk_listen( JJk  main.c(!!bbk  mkfile.""k5 response.http&##þþk test($$ØØk  utils.c%%