plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

icache.c (2808B)


      1 #include "a.h"
      2 
      3 // This code is almost certainly wrong.
      4 
      5 typedef struct Icache Icache;
      6 struct Icache
      7 {
      8 	char *url;
      9 	HTTPHeader hdr;
     10 	char *tmpfile;
     11 	int fd;
     12 	Icache *next;
     13 	Icache *prev;
     14 	Icache *hash;
     15 };
     16 
     17 enum {
     18 	NHASH = 128,
     19 	MAXCACHE = 128,
     20 };
     21 static struct {
     22 	Icache *hash[NHASH];
     23 	Icache *head;
     24 	Icache *tail;
     25 	int n;
     26 } icache;
     27 
     28 static Icache*
     29 icachefind(char *url)
     30 {
     31 	int h;
     32 	Icache *ic;
     33 
     34 	h = hash(url) % NHASH;
     35 	for(ic=icache.hash[h]; ic; ic=ic->hash){
     36 		if(strcmp(ic->url, url) == 0){
     37 			/* move to front */
     38 			if(ic->prev) {
     39 				ic->prev->next = ic->next;
     40 				if(ic->next)
     41 					ic->next->prev = ic->prev;
     42 				else
     43 					icache.tail = ic->prev;
     44 				ic->prev = nil;
     45 				ic->next = icache.head;
     46 				icache.head->prev = ic;
     47 				icache.head = ic;
     48 			}
     49 			return ic;
     50 		}
     51 	}
     52 	return nil;
     53 }
     54 
     55 static Icache*
     56 icacheinsert(char *url, HTTPHeader *hdr, char *file, int fd)
     57 {
     58 	int h;
     59 	Icache *ic, **l;
     60 
     61 	if(icache.n == MAXCACHE){
     62 		ic = icache.tail;
     63 		icache.tail = ic->prev;
     64 		if(ic->prev)
     65 			ic->prev->next = nil;
     66 		else
     67 			icache.head = ic->prev;
     68 		h = hash(ic->url) % NHASH;
     69 		for(l=&icache.hash[h]; *l; l=&(*l)->hash){
     70 			if(*l == ic){
     71 				*l = ic->hash;
     72 				goto removed;
     73 			}
     74 		}
     75 		sysfatal("cannot find ic in cache");
     76 	removed:
     77 		free(ic->url);
     78 		close(ic->fd);
     79 		remove(ic->file);
     80 		free(ic->file);
     81 	}else{
     82 		ic = emalloc(sizeof *ic);
     83 		icache.n++;
     84 	}
     85 
     86 	ic->url = estrdup(url);
     87 	ic->fd = dup(fd, -1);
     88 	ic->file = estrdup(file);
     89 	ic->hdr = *hdr;
     90 	h = hash(url) % NHASH;
     91 	ic->hash = icache.hash[h];
     92 	icache.hash[h] = ic;
     93 	ic->prev = nil;
     94 	ic->next = icache.head;
     95 	if(ic->next)
     96 		ic->next->prev = ic;
     97 	else
     98 		icache.tail = ic;
     99 	return ic;
    100 }
    101 
    102 void
    103 icacheflush(char *substr)
    104 {
    105 	Icache **l, *ic;
    106 
    107 	for(l=&icache.head; (ic=*l); ) {
    108 		if(substr == nil || strstr(ic->url, substr)) {
    109 			icache.n--;
    110 			*l = ic->next;
    111 			free(ic->url);
    112 			close(ic->fd);
    113 			remove(ic->file);
    114 			free(ic->file);
    115 			free(ic);
    116 		}else
    117 			l = &ic->next;
    118 	}
    119 
    120 	if(icache.head) {
    121 		icache.head->prev = nil;
    122 		for(ic=icache.head; ic; ic=ic->next){
    123 			if(ic->next)
    124 				ic->next->prev = ic;
    125 			else
    126 				icache.tail = ic;
    127 		}
    128 	}else
    129 		icache.tail = nil;
    130 }
    131 
    132 int
    133 urlfetch(char *url, HTTPHeader hdr)
    134 {
    135 	Icache *ic;
    136 	char buf[50], *host, *path, *p;
    137 	int fd, len;
    138 
    139 	ic = icachefind(url);
    140 	if(ic != nil){
    141 		*hdr = ic->hdr;
    142 		return dup(ic->fd, -1);
    143 	}
    144 
    145 	if(memcmp(url, "http://", 7) != 0){
    146 		werrstr("non-http url");
    147 		return -1;
    148 	}
    149 	p = strchr(url+7, '/');
    150 	if(p == nil)
    151 		p = url+strlen(url);
    152 	len = p - (url+7);
    153 	host = emalloc(len+1);
    154 	memmove(host, url+7, len);
    155 	host[len] = 0;
    156 	if(*p == 0)
    157 		p = "/";
    158 
    159 	strcpy(buf, "/var/tmp/smugfs.XXXXXX");
    160 	fd = opentemp(buf, ORDWR|ORCLOSE);
    161 	if(fd < 0)
    162 		return -1;
    163 	if(httptofile(http, host, req, &hdr, fd) < 0){
    164 		free(host);
    165 		return -1;
    166 	}
    167 	free(host);
    168 	icacheinsert(url, &hdr, buf, fd);
    169 	return fd;
    170 }