| #include "a.h" |
| |
| // This code is almost certainly wrong. |
| |
| typedef struct Icache Icache; |
| struct Icache |
| { |
| char *url; |
| HTTPHeader hdr; |
| char *tmpfile; |
| int fd; |
| Icache *next; |
| Icache *prev; |
| Icache *hash; |
| }; |
| |
| enum { |
| NHASH = 128, |
| MAXCACHE = 128, |
| }; |
| static struct { |
| Icache *hash[NHASH]; |
| Icache *head; |
| Icache *tail; |
| int n; |
| } icache; |
| |
| static Icache* |
| icachefind(char *url) |
| { |
| int h; |
| Icache *ic; |
| |
| h = hash(url) % NHASH; |
| for(ic=icache.hash[h]; ic; ic=ic->hash){ |
| if(strcmp(ic->url, url) == 0){ |
| /* move to front */ |
| if(ic->prev) { |
| ic->prev->next = ic->next; |
| if(ic->next) |
| ic->next->prev = ic->prev; |
| else |
| icache.tail = ic->prev; |
| ic->prev = nil; |
| ic->next = icache.head; |
| icache.head->prev = ic; |
| icache.head = ic; |
| } |
| return ic; |
| } |
| } |
| return nil; |
| } |
| |
| static Icache* |
| icacheinsert(char *url, HTTPHeader *hdr, char *file, int fd) |
| { |
| int h; |
| Icache *ic, **l; |
| |
| if(icache.n == MAXCACHE){ |
| ic = icache.tail; |
| icache.tail = ic->prev; |
| if(ic->prev) |
| ic->prev->next = nil; |
| else |
| icache.head = ic->prev; |
| h = hash(ic->url) % NHASH; |
| for(l=&icache.hash[h]; *l; l=&(*l)->hash){ |
| if(*l == ic){ |
| *l = ic->hash; |
| goto removed; |
| } |
| } |
| sysfatal("cannot find ic in cache"); |
| removed: |
| free(ic->url); |
| close(ic->fd); |
| remove(ic->file); |
| free(ic->file); |
| }else{ |
| ic = emalloc(sizeof *ic); |
| icache.n++; |
| } |
| |
| ic->url = estrdup(url); |
| ic->fd = dup(fd, -1); |
| ic->file = estrdup(file); |
| ic->hdr = *hdr; |
| h = hash(url) % NHASH; |
| ic->hash = icache.hash[h]; |
| icache.hash[h] = ic; |
| ic->prev = nil; |
| ic->next = icache.head; |
| if(ic->next) |
| ic->next->prev = ic; |
| else |
| icache.tail = ic; |
| return ic; |
| } |
| |
| void |
| icacheflush(char *substr) |
| { |
| Icache **l, *ic; |
| |
| for(l=&icache.head; (ic=*l); ) { |
| if(substr == nil || strstr(ic->url, substr)) { |
| icache.n--; |
| *l = ic->next; |
| free(ic->url); |
| close(ic->fd); |
| remove(ic->file); |
| free(ic->file); |
| free(ic); |
| }else |
| l = &ic->next; |
| } |
| |
| if(icache.head) { |
| icache.head->prev = nil; |
| for(ic=icache.head; ic; ic=ic->next){ |
| if(ic->next) |
| ic->next->prev = ic; |
| else |
| icache.tail = ic; |
| } |
| }else |
| icache.tail = nil; |
| } |
| |
| int |
| urlfetch(char *url, HTTPHeader hdr) |
| { |
| Icache *ic; |
| char buf[50], *host, *path, *p; |
| int fd, len; |
| |
| ic = icachefind(url); |
| if(ic != nil){ |
| *hdr = ic->hdr; |
| return dup(ic->fd, -1); |
| } |
| |
| if(memcmp(url, "http://", 7) != 0){ |
| werrstr("non-http url"); |
| return -1; |
| } |
| p = strchr(url+7, '/'); |
| if(p == nil) |
| p = url+strlen(url); |
| len = p - (url+7); |
| host = emalloc(len+1); |
| memmove(host, url+7, len); |
| host[len] = 0; |
| if(*p == 0) |
| p = "/"; |
| |
| strcpy(buf, "/var/tmp/smugfs.XXXXXX"); |
| fd = opentemp(buf, ORDWR|ORCLOSE); |
| if(fd < 0) |
| return -1; |
| if(httptofile(http, host, req, &hdr, fd) < 0){ |
| free(host); |
| return -1; |
| } |
| free(host); |
| icacheinsert(url, &hdr, buf, fd); |
| return fd; |
| } |
| |