ref: 90c504faca71f76b88c48b9cec8c0783b88c5564
parent: b3e7ba80c79140db8d2b869a14415687544e6ebb
author: Ori Bernstein <ori@eigenstate.org>
date: Sat May 31 17:24:48 EDT 2025
httpd: nuke from orbit nobody uses it, as far as I know.
--- a/sys/src/cmd/ip/httpd/anonymous.c
+++ /dev/null
@@ -1,14 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-void
-anonymous(HConnect *c)
-{- if(bind(webroot, "/", MREPL) < 0){- hfail(c, HInternal);
- exits(nil);
- }
- chdir("/");-}
--- a/sys/src/cmd/ip/httpd/authorize.c
+++ /dev/null
@@ -1,116 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-static char* readfile(char*);
-
-/*
- * these should be done better; see the response codes in /lib/rfc/rfc2616 for
- * more info on what should be included.
- */
-#define UNAUTHED "You are not authorized to see this area.\n"
-
-/*
- * check for authorization for some parts of the server tree.
- * the user name supplied with the authorization request is ignored;
- * instead, we authenticate as the realm's user.
- *
- * authorization should be done before opening any files so that
- * unauthorized users don't get to validate file names.
- *
- * returns 1 if authorized, 0 if unauthorized, -1 for io failure.
- */
-int
-authorize(HConnect *c, char *file)
-{- char *p, *p0;
- Hio *hout;
- char *buf;
- int i, n;
- char *t[257];
-
- p0 = halloc(c, strlen(file)+STRLEN("/.httplogin")+1);- strcpy(p0, file);
- for(;;){- p = strrchr(p0, '/');
- if(p == nil)
- return hfail(c, HInternal);
- if(*(p+1) != 0)
- break;
-
- /* ignore trailing '/'s */
- *p = 0;
- }
- strcpy(p, "/.httplogin");
-
- buf = readfile(p0);
- if(buf == nil){- return 1;
- }
- n = tokenize(buf, t, nelem(t));
-
- if(c->head.authuser != nil && c->head.authpass != 0){- for(i = 1; i+1 < n; i += 2){- if(strcmp(t[i], c->head.authuser) == 0
- && strcmp(t[i+1], c->head.authpass) == 0){- free(buf);
- return 1;
- }
- }
- }
-
- hout = &c->hout;
- hprint(hout, "%s 401 Unauthorized\r\n", hversion);
- hprint(hout, "Server: Plan9\r\n");
- hprint(hout, "Date: %D\r\n", time(nil));
- hprint(hout, "WWW-Authenticate: Basic realm=\"%s\"\r\n", t[0]);
- hprint(hout, "Content-Type: text/html\r\n");
- hprint(hout, "Content-Length: %d\r\n", STRLEN(UNAUTHED));
- 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", UNAUTHED);
- writelog(c, "Reply: 401 Unauthorized\n");
- free(buf);
- return hflush(hout);
-}
-
-static char*
-readfile(char *file)
-{- Dir *d;
- int fd;
- char *buf;
- int n, len;
-
- fd = open(file, OREAD);
- if(fd < 0)
- return nil;
- d = dirfstat(fd);
- if(d == nil){ /* shouldn't happen */- close(fd);
- return nil;
- }
- len = d->length;
- free(d);
-
- buf = malloc(len+1);
- if(buf == 0){- close(fd);
- return nil;
- }
-
- n = readn(fd, buf, len);
- close(fd);
- if(n <= 0){- free(buf);
- return nil;
- }
- buf[n] = '\0';
- return buf;
-}
--- a/sys/src/cmd/ip/httpd/classify.c
+++ /dev/null
@@ -1,427 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ndb.h>
-#include "whois.h"
-
-typedef struct Country Country;
-
-struct Country
-{- char *code;
- char *name;
-};
-
-Country badc[] =
-{- {"af", "afghanistan"},- {"cu", "cuba"},- {"ir", "iran"},- {"iq", "iraq"},- {"ly", "libya"},- {"kp", "north korea"},- {"sd", "sudan"},- {"sy", "syria"},- { 0, 0 }-};
-
-Country goodc[] =
-{- // the original, us and canada
- {"us", "united states of america"},- {"ca", "canada"},- {"gov", "gov"},- {"mil", "mil"},-
- // the european union
- { "eu", "european union" },- { "be", "belgium" },- { "de", "germany" },- { "fr", "france" },- { "it", "italy" },- { "lu", "luxembourg" },- { "nl", "netherlands" },- { "dk", "denmark" },- { "ie", "ireland" },- { "gb", "great britain" },- { "uk", "united kingdom" },- { "gr", "greece" },- { "es", "spain" },- { "pt", "portugal" },- { "at", "austria" },- { "fi", "finland" },- { "se", "sweden" },-
- // the rest
- {"au", "australia"},- {"no", "norway"},- {"cz", "czech republic"},- {"hu", "hungary"},- {"pl", "poland"},- {"jp", "japan"},- {"ch", "switzerland"},- {"nz", "new zealand"},- { 0, 0 }-};
-
-char *gov[] =
-{- "gov",
- "gouv",
- "mil",
- "government",
- 0,
-};
-
-Country allc[] =
-{- { "ad", "andorra" },- { "ae", "united arab emirates" },- { "af", "afghanistan" },- { "ag", "antigua and barbuda" },- { "ai", "anguilla" },- { "al", "albania" },- { "am", "armenia" },- { "an", "netherlands antilles" },- { "ao", "angola" },- { "aq", "antarctica" },- { "ar", "argentina" },- { "as", "american samoa" },- { "at", "austria" },- { "au", "australia" },- { "aw", "aruba" },- { "az", "azerbaijan" },- { "ba", "bosnia and herzegovina" },- { "bb", "barbados" },- { "bd", "bangladesh" },- { "be", "belgium" },- { "bf", "burkina faso" },- { "bg", "bulgaria" },- { "bh", "bahrain" },- { "bi", "burundi" },- { "bj", "benin" },- { "bm", "bermuda" },- { "bn", "brunei darussalam" },- { "bo", "bolivia" },- { "br", "brazil" },- { "bs", "bahamas" },- { "bt", "bhutan" },- { "bu", "burma" },- { "bv", "bouvet island" },- { "bw", "botswana" },- { "by", "belarus" },- { "bz", "belize" },- { "ca", "canada" },- { "cc", "cocos (keeling) islands" },- { "cf", "central african republic" },- { "cg", "congo" },- { "ch", "switzerland" },- { "ci", "cote d'ivoire (ivory coast)" },- { "ck", "cook islands" },- { "cl", "chile" },- { "cm", "cameroon" },- { "cn", "china" },- { "co", "colombia" },- { "cr", "costa rica" },- { "cs", "czechoslovakia (former)" },- { "ct", "canton and enderbury island" },- { "cu", "cuba" },- { "cv", "cape verde" },- { "cx", "christmas island" },- { "cy", "cyprus" },- { "cz", "czech republic" },- { "dd", "german democratic republic" },- { "de", "germany" },- { "dj", "djibouti" },- { "dk", "denmark" },- { "dm", "dominica" },- { "do", "dominican republic" },- { "dz", "algeria" },- { "ec", "ecuador" },- { "ee", "estonia" },- { "eg", "egypt" },- { "eh", "western sahara" },- { "er", "eritrea" },- { "es", "spain" },- { "et", "ethiopia" },- { "eu", "european union" },- { "fi", "finland" },- { "fj", "fiji" },- { "fk", "falkland islands (malvinas)" },- { "fm", "micronesia" },- { "fo", "faroe islands" },- { "fr", "france" },- { "fx", "france, metropolitan" },- { "ga", "gabon" },- { "gb", "great britain (uk)" },- { "gd", "grenada" },- { "ge", "georgia" },- { "gf", "french guiana" },- { "gh", "ghana" },- { "gi", "gibraltar" },- { "gl", "greenland" },- { "gm", "gambia" },- { "gn", "guinea" },- { "gp", "guadeloupe" },- { "gq", "equatorial guinea" },- { "gr", "greece" },- { "gs", "s. georgia and s. sandwich isls." },- { "gt", "guatemala" },- { "gu", "guam" },- { "gw", "guinea-bissau" },- { "gy", "guyana" },- { "hk", "hong kong" },- { "hm", "heard and mcdonald islands" },- { "hn", "honduras" },- { "hr", "croatia (hrvatska)" },- { "ht", "haiti" },- { "hu", "hungary" },- { "id", "indonesia" },- { "ie", "ireland" },- { "il", "israel" },- { "in", "india" },- { "io", "british indian ocean territory" },- { "iq", "iraq" },- { "ir", "iran" },- { "is", "iceland" },- { "it", "italy" },- { "jm", "jamaica" },- { "jo", "jordan" },- { "jp", "japan" },- { "jt", "johnston island" },- { "ke", "kenya" },- { "kg", "kyrgyzstan" },- { "kh", "cambodia (democratic kampuchea)" },- { "ki", "kiribati" },- { "km", "comoros" },- { "kn", "saint kitts and nevis" },- { "kp", "korea (north)" },- { "kr", "korea (south)" },- { "kw", "kuwait" },- { "ky", "cayman islands" },- { "kz", "kazakhstan" },- { "la", "laos" },- { "lb", "lebanon" },- { "lc", "saint lucia" },- { "li", "liechtenstein" },- { "lk", "sri lanka" },- { "lr", "liberia" },- { "ls", "lesotho" },- { "lt", "lithuania" },- { "lu", "luxembourg" },- { "lv", "latvia" },- { "ly", "libya" },- { "ma", "morocco" },- { "mc", "monaco" },- { "md", "moldova" },- { "mg", "madagascar" },- { "mh", "marshall islands" },- { "mi", "midway islands" },- { "mk", "macedonia" },- { "ml", "mali" },- { "mm", "myanmar" },- { "mn", "mongolia" },- { "mo", "macau" },- { "mp", "northern mariana islands" },- { "mq", "martinique" },- { "mr", "mauritania" },- { "ms", "montserrat" },- { "mt", "malta" },- { "mu", "mauritius" },- { "mv", "maldives" },- { "mw", "malawi" },- { "mx", "mexico" },- { "my", "malaysia" },- { "mz", "mozambique" },- { "na", "namibia" },- { "nc", "new caledonia" },- { "ne", "niger" },- { "nf", "norfolk island" },- { "ng", "nigeria" },- { "ni", "nicaragua" },- { "nl", "netherlands" },- { "no", "norway" },- { "np", "nepal" },- { "nq", "dronning maud land" },- { "nr", "nauru" },- { "nt", "neutral zone" },- { "nu", "niue" },- { "nz", "new zealand (aotearoa)" },- { "om", "oman" },- { "pa", "panama" },- { "pc", "pacific islands" },- { "pe", "peru" },- { "pf", "french polynesia" },- { "pg", "papua new guinea" },- { "ph", "philippines" },- { "pk", "pakistan" },- { "pl", "poland" },- { "pm", "st. pierre and miquelon" },- { "pn", "pitcairn" },- { "pr", "puerto rico" },- { "pu", "united states misc. pacific islands" },- { "pt", "portugal" },- { "pw", "palau" },- { "py", "paraguay" },- { "qa", "qatar" },- { "re", "reunion" },- { "ro", "romania" },- { "ru", "russian federation" },- { "rw", "rwanda" },- { "sa", "saudi arabia" },- { "sb", "solomon islands" },- { "sc", "seychelles" },- { "sd", "sudan" },- { "se", "sweden" },- { "sg", "singapore" },- { "sh", "st. helena" },- { "si", "slovenia" },- { "sj", "svalbard and jan mayen islands" },- { "sk", "slovak republic" },- { "sl", "sierra leone" },- { "sm", "san marino" },- { "sn", "senegal" },- { "so", "somalia" },- { "sr", "suriname" },- { "st", "sao tome and principe" },- { "su", "ussr (former)" },- { "sv", "el salvador" },- { "sy", "syria" },- { "sz", "swaziland" },- { "tc", "turks and caicos islands" },- { "td", "chad" },- { "tf", "french southern territories" },- { "tg", "togo" },- { "th", "thailand" },- { "tj", "tajikistan" },- { "tk", "tokelau" },- { "tm", "turkmenistan" },- { "tn", "tunisia" },- { "to", "tonga" },- { "tp", "east timor" },- { "tr", "turkey" },- { "tt", "trinidad and tobago" },- { "tv", "tuvalu" },- { "tw", "taiwan" },- { "tz", "tanzania" },- { "ua", "ukraine" },- { "ug", "uganda" },- { "uk", "united kingdom" },- { "um", "us minor outlying islands" },- { "us", "united states" },- { "uy", "uruguay" },- { "uz", "uzbekistan" },- { "va", "vatican city state (holy see)" },- { "vc", "saint vincent and the grenadines" },- { "ve", "venezuela" },- { "vg", "virgin islands (british)" },- { "vi", "virgin islands (u.s.)" },- { "vn", "viet nam" },- { "vu", "vanuatu" },- { "wf", "wallis and futuna islands" },- { "wk", "wake island" },- { "ws", "samoa" },- { "yd", "democratic yemen" },- { "ye", "yemen" },- { "yt", "mayotte" },- { "yu", "yugoslavia" },- { "za", "south africa" },- { "zm", "zambia" },- { "zr", "zaire" },- { "zw", "zimbabwe" },-
- {"gov", "gov"},- {"mil", "mil"},-
- { 0, 0 }-};
-
-int classdebug;
-
-static int
-incountries(char *s, Country *cp)
-{- for(; cp->code != 0; cp++)
- if(cistrcmp(s, cp->code) == 0
- || cistrcmp(s, cp->name) == 0)
- return 1;
- return 0;
-}
-
-static int
-indomains(char *s, char **dp)
-{- for(; *dp != nil; dp++)
- if(cistrcmp(s, *dp) == 0)
- return 1;
-
- return 0;
-}
-
-int
-classify(char *ip, Ndbtuple *t)
-{- int isgov, iscountry, isbadc, isgoodc;
- char dom[256];
- char *df[128];
- Ndbtuple *nt, *x;
- int n;
-
- isgov = iscountry = isbadc = 0;
- isgoodc = 1;
-
- for(nt = t; nt != nil; nt = nt->entry){- if(strcmp(nt->attr, "country") == 0){- iscountry = 1;
- if(incountries(nt->val, badc)){- if(classdebug)fprint(2, "isbadc\n");
- isbadc = 1;
- isgoodc = 0;
- } else if(!incountries(nt->val, goodc)){- if(classdebug)fprint(2, "!isgoodc\n");
- isgoodc = 0;
- }
- }
-
- /* domain names can always hurt, even without forward verification */
- if(strcmp(nt->attr, "dom") == 0){- strncpy(dom, nt->val, sizeof dom);
- dom[sizeof(dom)-1] = 0;
- n = getfields(dom, df, nelem(df), 0, ".");
-
- /* a bad country in a domain name is always believed */
- if(incountries(df[n-1], badc)){- if(classdebug)fprint(2, "isbadc dom\n");
- isbadc = 1;
- isgoodc = 0;
- }
-
- /* a goverment in a domain name is always believed */
- if(n > 1 && indomains(df[n-2], gov))
- isgov = 1;
- }
- }
- if(iscountry == 0){- /* did the forward lookup work? */
- for(nt = t; nt != nil; nt = nt->entry){- if(strcmp(nt->attr, "ip") == 0 && strcmp(nt->val, ip) == 0)
- break;
- }
-
- /* see if the domain name ends in a country code */
- if(nt != nil && (x = ndbfindattr(t, nt, "dom")) != nil){- strncpy(dom, x->val, sizeof dom);
- dom[sizeof(dom)-1] = 0;
- n = getfields(dom, df, nelem(df), 0, ".");
- if(incountries(df[n-1], allc))
- iscountry = 1;
- }
- }
- if(iscountry == 0)
- return Cunknown;
- if(isbadc)
- return Cbadc;
- if(!isgoodc && isgov)
- return Cbadgov;
- return Cok;
-}
--- a/sys/src/cmd/ip/httpd/content.c
+++ /dev/null
@@ -1,172 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-typedef struct Suffix Suffix;
-struct Suffix
-{- Suffix *next;
- char *suffix;
- char *generic;
- char *specific;
- char *encoding;
-};
-
-Suffix *suffixes = nil;
-
-static Suffix* parsesuffix(char*, Suffix*);
-static char* skipwhite(char*);
-static HContents suffixclass(char*);
-static char* towhite(char*);
-
-int
-updateQid(int fd, Qid *q)
-{- Dir *dir;
- Qid dq;
-
- dir = dirfstat(fd);
- if(dir == nil)
- sysfatal("can't dirfstat");- dq = dir->qid;
- free(dir);
- if(q->path == dq.path && q->vers == dq.vers && q->type == dq.type)
- return 0;
- *q = dq;
- return 1;
-}
-
-void
-contentinit(void)
-{- static Biobuf *b = nil;
- static Qid qid;
- char *file, *s;
- Suffix *this;
-
- file = "/sys/lib/mimetype";
- if(b == nil){ /* first time */- b = Bopen(file, OREAD);
- if(b == nil)
- sysfatal("can't read from %s", file);- }
- if(updateQid(Bfildes(b), &qid) == 0)
- return;
- Bseek(b, 0, 0);
- while(suffixes!=nil){- this = suffixes;
- suffixes = suffixes->next;
- free(this->suffix);
- free(this->generic);
- free(this->specific);
- free(this->encoding);
- free(this);
- }
-
- while((s = Brdline(b, '\n')) != nil){- s[Blinelen(b) - 1] = 0;
- suffixes = parsesuffix(s, suffixes);
- }
-}
-
-static Suffix*
-parsesuffix(char *line, Suffix *suffix)
-{- Suffix *s;
- char *p, *fields[5];
- int i, nf;
-
- p = strchr(line, '#');
- if(p != nil)
- *p = '\0';
- nf = tokenize(line, fields, 5);
- for(i = 0; i < 4; i++)
- if(i >= nf || fields[i][0] == '-')
- fields[i] = nil;
-
- if(fields[2] == nil)
- fields[1] = nil;
- if(fields[1] == nil && fields[3] == nil)
- return suffix;
- if(fields[0] == nil)
- return suffix;
-
- s = ezalloc(sizeof *s);
- s->next = suffix;
- s->suffix = estrdup(fields[0]);
- if(fields[1] != nil){- s->generic = estrdup(fields[1]);
- s->specific = estrdup(fields[2]);
- }
- if(fields[3] != nil)
- s->encoding = estrdup(fields[3]);
- return s;
-}
-
-/*
- * classify by file name extensions
- */
-HContents
-uriclass(HConnect *hc, char *name)
-{- HContents conts;
- Suffix *s;
- HContent *type, *enc;
- char *buf, *p;
-
- type = nil;
- enc = nil;
- if((p = strrchr(name, '/')) != nil)
- name = p + 1;
- buf = hstrdup(hc, name);
- while((p = strrchr(buf, '.')) != nil){- for(s = suffixes; s; s = s->next){- if(strcmp(p, s->suffix) == 0){- if(s->generic != nil && type == nil)
- type = hmkcontent(hc, s->generic, s->specific, nil);
- if(s->encoding != nil && enc == nil)
- enc = hmkcontent(hc, s->encoding, nil, nil);
- }
- }
- *p = 0;
- }
- conts.type = type;
- conts.encoding = enc;
- return conts;
-}
-
-/*
- * classify by initial contents of file
- */
-HContents
-dataclass(HConnect *hc, char *buf, int n)
-{- HContents conts;
- Rune r;
- int c, m;
-
- for(; n > 0; n -= m){- c = *buf;
- if(c < Runeself){- if(c < 32 && c != '\n' && c != '\r' && c != '\t' && c != '\v'){- conts.type = nil;
- conts.encoding = nil;
- return conts;
- }
- m = 1;
- }else{- m = chartorune(&r, buf);
- if(r == Runeerror){- conts.type = nil;
- conts.encoding = nil;
- return conts;
- }
- }
- buf += m;
- }
- conts.type = hmkcontent(hc, "text", "plain", nil);
- conts.encoding = nil;
- return conts;
-}
--- a/sys/src/cmd/ip/httpd/emem.c
+++ /dev/null
@@ -1,25 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "httpd.h"
-
-void*
-ezalloc(ulong n)
-{- void *p;
-
- p = malloc(n);
- if(p == nil)
- sysfatal("out of memory");- memset(p, 0, n);
- return p;
-}
-
-char*
-estrdup(char *s)
-{- s = strdup(s);
- if(s == nil)
- sysfatal("out of memory");- return s;
-}
-
--- a/sys/src/cmd/ip/httpd/hints.c
+++ /dev/null
@@ -1,297 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-enum{ URLmax = 65536, HINTmax = 20 };-#define RECIPLOG2 1.44269504089
-
-char **urlname; /* array of url strings 1,...,nurl */
-static int nurl;
-static uint urltab[URLmax]; /* hashstr(url) 1,...,nurl */
-static int urlnext[URLmax]; /* index urltab of next url in chain */
-static int urlhash[URLmax]; /* initially 0, meaning empty buckets */
-
-typedef struct Hint {- ushort url;
- uchar prob;
-} Hint;
-Hint *hints[URLmax];
-uchar nhint[URLmax];
-
-vlong
-Bfilelen(void *vb)
-{- Biobuf *b;
- vlong n;
-
- b = vb;
- n = Bseek(b, 0L, 2);
- Bseek(b, 0L, 0);
- return n;
-}
-
-static uint
-hashstr(char* key)
-{- /* asu works better than pjw for urls */
- uchar *k = (unsigned char*)key;
- uint h = 0;
- while(*k!=0)
- h = 65599*h + *k++;
- return h;
-}
-
-static int
-urllookup(uint url)
-{- /* returns +index into urltab, else -hash */
- int j, hash;
-
- hash = 1 + url%(URLmax-1);
- j = urlhash[hash];
- for(;;){- if(j==0)
- return -hash;
- if(url==urltab[j])
- return j;
- j = urlnext[j];
- }
-}
-
-int
-Bage(Biobuf *b)
-{- Dir *dir;
- long mtime;
-
- dir = dirfstat(Bfildes(b));
- if(dir != nil)
- mtime = dir->mtime;
- else
- mtime = 0;
- free(dir);
- return time(nil) - mtime;
-}
-
-void
-urlinit(void)
-{- static Biobuf *b = nil;
- static vlong filelen = 0;
- vlong newlen;
- char *s, *arena;
- int i, j, n;
- uint url;
- char *file;
-
- if(filelen < 0)
- return;
- file = "/sys/log/httpd/url";
- if(b == nil){- b = Bopen(file, OREAD); /* first time */
- if(b == nil){- syslog(0, HTTPLOG, "no %s, abandon prefetch hints", file);
- filelen = -1;
- return;
- }
- }
- newlen = Bfilelen(b); /* side effect: rewinds b */
- if(newlen == filelen || Bage(b)<300)
- return;
- filelen = newlen;
- if(filelen < 0)
- return;
- if(nurl){ /* free existing tables */- free(urlname[0]); /* arena */
- memset(urlhash,0,sizeof urlhash);
- memset(urlnext,0,sizeof urlnext);
- nurl = 0;
- }
- if(urlname==nil)
- urlname = (char**)ezalloc(URLmax*sizeof(*urlname));
- arena = (char*)ezalloc(filelen); /* enough for all the strcpy below */
- i = 1;
- while((s=Brdline(b,'\n'))!=0){- /* read lines of the form: 999 /url/path */
- n = Blinelen(b) - 1;
- if(n>2 && s[n]=='\n'){- s[n] = '\0';
- }else{- sysfatal("missing fields or newline in url-db");- }
- j = strtoul(s,&s,10);
- while(*s==' ')
- s++;
- if(i++!=j)
- sysfatal("url-db synchronization error");- url = hashstr(s);
- j = urllookup(url);
- if(j>=0)
- sysfatal("duplicate url");- j = -j;
- nurl++;
- if(nurl>=URLmax){- syslog(0, HTTPLOG, "urlinit overflow at %s",s);
- free(urlname[0]); /* arena */
- memset(urlhash,0,sizeof urlhash);
- memset(urlnext,0,sizeof urlnext);
- nurl = 0;
- return;
- }
- urltab[nurl] = url;
- urlnext[nurl] = urlhash[j];
- urlhash[j] = nurl;
- strcpy(arena,s);
- urlname[nurl] = arena;
- arena += strlen(s)+1;
- }
- syslog(0, HTTPLOG, "prefetch-hints url=%d (%.1fMB)", nurl, 1.e-6*(URLmax*sizeof(*urlname)+filelen));
- /* b is held open, because namespace will be chopped */
-}
-
-void
-statsinit(void)
-{- static Biobuf *b = nil;
- static vlong filelen = 0;
- vlong newlen;
- int iq, n, i, nstats = 0;
- uchar *s, buf[3+HINTmax*3]; /* iq, n, (url,prob)... */
- Hint *arena, *h;
- char *file;
- static void *oldarena = nil;
-
- file = "/sys/log/httpd/pathstat";
- if(b == nil){- if(filelen == -1)
- return; /* if failed first time */
- b = Bopen(file, OREAD); /* first time */
- if(b == nil){- syslog(0, HTTPLOG, "no %s, abandon prefetch hints", file);
- filelen = -1;
- return;
- }
- }
- newlen = Bfilelen(b); /* side effect: rewinds b */
- if(newlen == filelen || Bage(b)<300)
- return;
- filelen = newlen;
- if(oldarena){- free(oldarena);
- memset(nhint,0,sizeof nhint);
- }
- arena = (Hint*)ezalloc((filelen/3)*sizeof(Hint));
- oldarena = arena;
- for(;;){- i = Bread(b,buf,3);
- if(i<3)
- break;
- nstats++;
- iq = buf[0];
- iq = (iq<<8) | buf[1];
- n = buf[2];
- h = arena;
- arena += n;
- hints[iq] = h;
- nhint[iq] = n;
- if(Bread(b,buf,3*n)!=3*n)
- sysfatal("stats read error");- for(i=0; i<n; i++){- s = &buf[3*i];
- h[i].url = (s[0]<<8) | s[1];
- h[i].prob = s[2];
- }
- }
- syslog(0, HTTPLOG, "prefetch-hints stats=%d (%.1fMB)", nstats, 1.e-6*((filelen/3)*sizeof(Hint)));
-}
-
-void
-urlcanon(char *url)
-{- /* all the changes here can be implemented by rewriting in-place */
- char *p, *q;
-
- /* remove extraneous '/' in the middle and at the end */
- p = url+1; /* first char needs no change */
- q = p;
- while(q[0]){- if(q[0]=='/' && q[-1]=='/'){- q++;
- continue;
- }
- *p++ = *q++;
- }
- if(q[-1]=='/'){ /* trailing '/' */- p[-1] = '\0';
- }else{- p[0] = '\0';
- }
-
- /* specific to the cm.bell-labs.com web site */
- if(strncmp(url,"/cm/",4)==0){- if(strchr("cims",url[4]) && strncmp(url+5,"s/who/",6)==0)- /* strip off /cm/cs */
- memmove(url,url+6,strlen(url+6)+1);
- else if(strncmp(url+4,"ms/what/wavelet",15)==0)
- /* /cm/ms/what */
- memmove(url,url+11,strlen(url+11)+1);
- }
-}
-
-void
-hintprint(HConnect *hc, Hio *hout, char *uri, int thresh, int havej)
-{- int i, j, pr, prefix, fd, siz, havei, newhint = 0, n;
- char *query, *sf, etag[32], *wurl;
- Dir *dir;
- Hint *h, *haveh;
-
- query = hstrdup(hc, uri);
- urlcanon(query);
- j = urllookup(hashstr(query));
- if(j < 0)
- return;
- query = strrchr(uri,'/');
- if(!query)
- return; /* can't happen */
- prefix = query-uri+1; /* = strlen(dirname)+1 */
- h = hints[j];
- for(i=0; i<nhint[j]; i++){- if(havej > 0 && havej < URLmax){ /* exclude hints client has */- haveh = hints[havej];
- for(havei=0; havei<nhint[havej]; havei++)
- if( haveh[havei].url == h[i].url)
- goto continuei;
- }
- sf = urlname[h[i].url];
- pr = h[i].prob;
- if(pr<thresh)
- break;
- n = strlen(webroot) + strlen(sf) + 1;
- wurl = halloc(hc, n);
- strcpy(wurl, webroot);
- strcat(wurl, sf);
- fd = open(wurl, OREAD);
- if(fd<0)
- continue;
- dir = dirfstat(fd);
- if(dir == nil){- close(fd);
- continue;
- }
- close(fd);
- snprint(etag, sizeof(etag), "\"%lluxv%lux\"", dir->qid.path, dir->qid.vers);
- siz = (int)( log((double)dir->length) * RECIPLOG2 + 0.9999);
- free(dir);
- if(strncmp(uri,sf,prefix)==0 && strchr(sf+prefix,'/')==0 && sf[prefix]!=0)
- sf = sf+prefix;
- hprint(hout, "Fresh: %d,%s,%d,%s\r\n", pr, etag, siz, sf);
- newhint++;
-continuei: ;
- }
- if(newhint)
- hprint(hout, "Fresh: have/%d\r\n", j);
-}
-
--- a/sys/src/cmd/ip/httpd/httpd.c
+++ /dev/null
@@ -1,608 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <mp.h>
-#include <libsec.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-typedef struct Strings Strings;
-
-struct Strings
-{- char *s1;
- char *s2;
-};
-
-char *netdir;
-char *HTTPLOG = "httpd/log";
-
-static char netdirb[256];
-static char *namespace;
-
-static void becomenone(char*);
-static char *csquery(char*, char*, char*);
-static void dolisten(char*);
-static int doreq(HConnect*);
-static int send(HConnect*);
-static Strings stripmagic(HConnect*, char*);
-static char* stripprefix(char*, char*);
-static char* sysdom(void);
-static int notfound(HConnect *c, char *url);
-
-uchar *certificate;
-int certlen;
-PEMChain *certchain;
-
-void
-usage(void)
-{- fprint(2, "usage: httpd [-c certificate] [-C CAchain] [-a srvaddress] "
- "[-d domain] [-n namespace] [-w webroot]\n");
- exits("usage");-}
-
-void
-main(int argc, char **argv)
-{- char *address;
-
- namespace = nil;
- address = nil;
- hmydomain = nil;
- netdir = "/net";
- fmtinstall('D', hdatefmt);- fmtinstall('H', httpfmt);- fmtinstall('U', hurlfmt);- ARGBEGIN{- case 'c':
- certificate = readcert(EARGF(usage()), &certlen);
- if(certificate == nil)
- sysfatal("reading certificate: %r");- break;
- case 'C':
- certchain = readcertchain(EARGF(usage()));
- if (certchain == nil)
- sysfatal("reading certificate chain: %r");- break;
- case 'n':
- namespace = EARGF(usage());
- break;
- case 'a':
- address = EARGF(usage());
- break;
- case 'd':
- hmydomain = EARGF(usage());
- break;
- case 'w':
- webroot = EARGF(usage());
- break;
- default:
- usage();
- break;
- }ARGEND
-
- if(argc)
- usage();
-
- if(namespace == nil)
- namespace = "/lib/namespace.httpd";
- if(address == nil)
- address = "*";
- if(webroot == nil)
- webroot = "/usr/web";
- else{- cleanname(webroot);
- if(webroot[0] != '/')
- webroot = "/usr/web";
- }
-
- switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNAMEG)) {- case -1:
- sysfatal("fork");- case 0:
- break;
- default:
- exits(nil);
- }
-
- /*
- * open all files we might need before castrating namespace
- */
- time(nil);
- if(hmydomain == nil)
- hmydomain = sysdom();
- syslog(0, HTTPLOG, nil);
- logall[0] = open("/sys/log/httpd/0", OWRITE);- logall[1] = open("/sys/log/httpd/1", OWRITE);- logall[2] = open("/sys/log/httpd/clf", OWRITE);- redirectinit();
- contentinit();
- urlinit();
- statsinit();
-
- becomenone(namespace);
- dolisten(netmkaddr(address, "tcp", certificate == nil ? "http" : "https"));
- exits(nil);
-}
-
-static void
-becomenone(char *namespace)
-{- if(procsetuser("none") < 0)- sysfatal("can't become none: %r");- if(newns("none", nil) < 0)- sysfatal("can't build normal namespace: %r");- if(addns("none", namespace) < 0)- sysfatal("can't build httpd namespace: %r");-}
-
-static HConnect*
-mkconnect(char *scheme, char *port)
-{- HConnect *c;
-
- c = ezalloc(sizeof(HConnect));
- c->hpos = c->header;
- c->hstop = c->header;
- c->replog = writelog;
- c->scheme = scheme;
- c->port = port;
- return c;
-}
-
-static HSPriv*
-mkhspriv(void)
-{- HSPriv *p;
-
- p = ezalloc(sizeof(HSPriv));
- return p;
-}
-
-static void
-dolisten(char *address)
-{- HSPriv *hp;
- HConnect *c;
- NetConnInfo *nci;
- char ndir[NETPATHLEN], dir[NETPATHLEN], *p, *scheme;
- int ctl, nctl, data, t, ok, spotchk;
-
- spotchk = 0;
- syslog(0, HTTPLOG, "httpd starting");
- ctl = announce(address, dir);
- if(ctl < 0){- syslog(0, HTTPLOG, "can't announce on %s: %r", address);
- return;
- }
- strcpy(netdirb, dir);
- p = nil;
- if(netdir[0] == '/'){- p = strchr(netdirb+1, '/');
- if(p != nil)
- *p = '\0';
- }
- if(p == nil)
- strcpy(netdirb, "/net");
- netdir = netdirb;
-
- for(;;){-
- /*
- * wait for a call (or an error)
- */
- nctl = listen(dir, ndir);
- if(nctl < 0){- syslog(0, HTTPLOG, "can't listen on %s: %r", address);
- syslog(0, HTTPLOG, "ctls = %d", ctl);
- return;
- }
-
- /*
- * start a process for the service
- */
- switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFNAMEG)){- case -1:
- close(nctl);
- continue;
- case 0:
- /*
- * see if we know the service requested
- */
- data = accept(ctl, ndir);
- if(data >= 0 && certificate != nil){- TLSconn conn;
-
- memset(&conn, 0, sizeof(conn));
- conn.cert = certificate;
- conn.certlen = certlen;
- if (certchain != nil)
- conn.chain = certchain;
- data = tlsServer(data, &conn);
- free(conn.cert);
- free(conn.sessionID);
- scheme = "https";
- }else
- scheme = "http";
- if(data < 0){- syslog(0, HTTPLOG, "can't open %s/data: %r", ndir);
- exits(nil);
- }
- dup(data, 0);
- dup(data, 1);
- dup(data, 2);
- close(data);
- close(ctl);
- close(nctl);
-
- nci = getnetconninfo(ndir, -1);
- c = mkconnect(scheme, nci->lserv);
- hp = mkhspriv();
- hp->remotesys = nci->rsys;
- hp->remoteserv = nci->rserv;
- c->private = hp;
-
- hinit(&c->hin, 0, Hread);
- hinit(&c->hout, 1, Hwrite);
-
- /*
- * serve requests until a magic request.
- * later requests have to come quickly.
- * only works for http/1.1 or later.
- */
- for(t = 15*60*1000; ; t = 15*1000){- if(hparsereq(c, t) <= 0)
- exits(nil);
- ok = doreq(c);
-
- hflush(&c->hout);
-
- if(c->head.closeit || ok < 0)
- exits(nil);
-
- hreqcleanup(c);
- }
- /* not reached */
-
- default:
- close(nctl);
- break;
- }
-
- if(++spotchk > 50){- spotchk = 0;
- redirectinit();
- contentinit();
- urlinit();
- statsinit();
- }
- }
-}
-
-static int
-doreq(HConnect *c)
-{- HSPriv *hp;
- Strings ss;
- char *magic, *uri, *newuri, *origuri, *newpath, *hb;
- char virtualhost[100], logfd0[10], logfd1[10], vers[16];
- int n, nredirect;
- uint flags;
-
- /*
- * munge uri for magic
- */
- uri = c->req.uri;
- nredirect = 0;
- werrstr("");-top:
- if(++nredirect > 10){- if(hparseheaders(c, 15*60*1000) < 0)
- exits("failed");- werrstr("redirection loop");- return hfail(c, HNotFound, uri);
- }
- ss = stripmagic(c, uri);
- uri = ss.s1;
- origuri = uri;
- magic = ss.s2;
- if(magic)
- goto magic;
-
- /*
- * Apply redirects. Do this before reading headers
- * (if possible) so that we can redirect to magic invisibly.
- */
- flags = 0;
- if(origuri[0]=='/' && origuri[1]=='~'){- n = strlen(origuri) + 4 + UTFmax;
- newpath = halloc(c, n);
- snprint(newpath, n, "/who/%s", origuri+2);
- c->req.uri = newpath;
- newuri = newpath;
- }else if(origuri[0]=='/' && origuri[1]==0){- /* can't redirect / until we read the headers below */
- newuri = nil;
- }else
- newuri = redirect(c, origuri, &flags);
-
- if(newuri != nil){- if(flags & Redirsilent) {- c->req.uri = uri = newuri;
- logit(c, "%s: silent replacement %s", origuri, uri);
- goto top;
- }
- if(hparseheaders(c, 15*60*1000) < 0)
- exits("failed");- if(flags & Redirperm) {- logit(c, "%s: permanently moved to %s", origuri, newuri);
- return hmoved(c, newuri);
- } else if (flags & (Redironly | Redirsubord))
- logit(c, "%s: top-level or many-to-one replacement %s",
- origuri, uri);
-
- /*
- * try temporary redirect instead of permanent
- */
- if (http11(c))
- return hredirected(c, "307 Temporary Redirect", newuri);
- else
- return hredirected(c, "302 Temporary Redirect", newuri);
- }
-
- /*
- * for magic we exec a new program and serve no more requests
- */
-magic:
- if(magic != nil && strcmp(magic, "httpd") != 0){- snprint(c->xferbuf, HBufSize, "/bin/ip/httpd/%s", magic);
- snprint(logfd0, sizeof(logfd0), "%d", logall[0]);
- snprint(logfd1, sizeof(logfd1), "%d", logall[1]);
- snprint(vers, sizeof(vers), "HTTP/%d.%d", c->req.vermaj, c->req.vermin);
- hb = hunload(&c->hin);
- if(hb == nil){- hfail(c, HInternal);
- return -1;
- }
- hp = c->private;
- execl(c->xferbuf, magic, "-d", hmydomain, "-w", webroot,
- "-s", c->scheme, "-p", c->port,
- "-r", hp->remotesys, "-N", netdir, "-b", hb,
- "-L", logfd0, logfd1, "-R", c->header,
- c->req.meth, vers, uri, c->req.search, nil);
- logit(c, "no magic %s uri %s", magic, uri);
- hfail(c, HNotFound, uri);
- return -1;
- }
-
- /*
- * normal case is just file transfer
- */
- if(hparseheaders(c, 15*60*1000) < 0)
- exits("failed");- if(origuri[0] == '/' && origuri[1] == 0){ - snprint(virtualhost, sizeof virtualhost, "http://%s/", c->head.host);
- newuri = redirect(c, virtualhost, nil);
- if(newuri == nil)
- newuri = redirect(c, origuri, nil);
- if(newuri)
- return hmoved(c, newuri);
- }
- if(!http11(c) && !c->head.persist)
- c->head.closeit = 1;
- return send(c);
-}
-
-static int
-send(HConnect *c)
-{- Dir *dir;
- char *w, *w2, *p, *masque;
- int fd, fd1, n, force301, ok;
-
-/*
- if(c->req.search)
- return hfail(c, HNoSearch, c->req.uri);
- */
- if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
- return hunallowed(c, "GET, HEAD");
- if(c->head.expectother || c->head.expectcont)
- return hfail(c, HExpectFail);
-
- masque = masquerade(c->head.host);
-
- /*
- * check for directory/file mismatch with trailing /,
- * and send any redirections.
- */
- n = strlen(webroot) + strlen(masque) + strlen(c->req.uri) +
- STRLEN("/index.html") + STRLEN("/.httplogin") + 1;- w = halloc(c, n);
- strcpy(w, webroot);
- strcat(w, masque);
- strcat(w, c->req.uri);
-
- /*
- * favicon can be overridden by hostname.ico
- */
- if(strcmp(c->req.uri, "/favicon.ico") == 0){- w2 = halloc(c, n+strlen(c->head.host)+2);
- strcpy(w2, webroot);
- strcat(w2, masque);
- strcat(w2, "/");
- strcat(w2, c->head.host);
- strcat(w2, ".ico");
- if(access(w2, AREAD)==0)
- w = w2;
- }
-
- /*
- * don't show the contents of .httplogin
- */
- n = strlen(w);
- if(strcmp(w+n-STRLEN(".httplogin"), ".httplogin") == 0)- return notfound(c, c->req.uri);
-
- fd = open(w, OREAD);
- if(fd < 0 && strlen(masque)>0 && strncmp(c->req.uri, masque, strlen(masque)) == 0){- // may be a URI from before virtual hosts; try again without masque
- strcpy(w, webroot);
- strcat(w, c->req.uri);
- fd = open(w, OREAD);
- }
- if(fd < 0)
- return notfound(c, c->req.uri);
- dir = dirfstat(fd);
- if(dir == nil){- close(fd);
- return hfail(c, HInternal);
- }
- p = strchr(w, '\0');
- if(dir->mode & DMDIR){- free(dir);
- if(p > w && p[-1] == '/'){- strcat(w, "index.html");
- force301 = 0;
- }else{- strcat(w, "/index.html");
- force301 = 1;
- }
- fd1 = open(w, OREAD);
- if(fd1 < 0){- close(fd);
- return notfound(c, c->req.uri);
- }
- c->req.uri = w + strlen(webroot) + strlen(masque);
- if(force301 && c->req.vermaj){- close(fd);
- close(fd1);
- return hmoved(c, c->req.uri);
- }
- close(fd);
- fd = fd1;
- dir = dirfstat(fd);
- if(dir == nil){- close(fd);
- return hfail(c, HInternal);
- }
- }else if(p > w && p[-1] == '/'){- free(dir);
- close(fd);
- *strrchr(c->req.uri, '/') = '\0';
- return hmoved(c, c->req.uri);
- }
-
- ok = authorize(c, w);
- if(ok <= 0){- free(dir);
- close(fd);
- return ok;
- }
-
- return sendfd(c, fd, dir, nil, nil);
-}
-
-static Strings
-stripmagic(HConnect *hc, char *uri)
-{- Strings ss;
- char *newuri, *prog, *s;
-
- prog = stripprefix("/magic/", uri);- if(prog == nil){- ss.s1 = uri;
- ss.s2 = nil;
- return ss;
- }
-
- s = strchr(prog, '/');
- if(s == nil)
- newuri = "";
- else{- newuri = hstrdup(hc, s);
- *s = 0;
- s = strrchr(s, '/');
- if(s != nil && s[1] == 0)
- *s = 0;
- }
- ss.s1 = newuri;
- ss.s2 = prog;
- return ss;
-}
-
-static char*
-stripprefix(char *pre, char *str)
-{- while(*pre)
- if(*str++ != *pre++)
- return nil;
- return str;
-}
-
-/*
- * couldn't open a file
- * figure out why and return and error message
- */
-static int
-notfound(HConnect *c, char *url)
-{- c->xferbuf[0] = 0;
- rerrstr(c->xferbuf, sizeof c->xferbuf);
- if(strstr(c->xferbuf, "file does not exist") != nil)
- return hfail(c, HNotFound, url);
- if(strstr(c->xferbuf, "permission denied") != nil)
- return hfail(c, HUnauth, url);
- return hfail(c, HNotFound, url);
-}
-
-static char*
-sysdom(void)
-{- char *dn;
-
- dn = csquery("sys" , sysname(), "dom");- if(dn == nil)
- dn = "who cares";
- return dn;
-}
-
-/*
- * query the connection server
- */
-static char*
-csquery(char *attr, char *val, char *rattr)
-{- char token[64+4];
- char buf[256], *p, *sp;
- int fd, n;
-
- if(val == nil || val[0] == 0)
- return nil;
- snprint(buf, sizeof(buf), "%s/cs", netdir);
- fd = open(buf, ORDWR);
- if(fd < 0)
- return nil;
- fprint(fd, "!%s=%s", attr, val);
- seek(fd, 0, 0);
- snprint(token, sizeof(token), "%s=", rattr);
- for(;;){- n = read(fd, buf, sizeof(buf)-1);
- if(n <= 0)
- break;
- buf[n] = 0;
- p = strstr(buf, token);
- if(p != nil && (p == buf || *(p-1) == 0)){- close(fd);
- sp = strchr(p, ' ');
- if(sp)
- *sp = 0;
- p = strchr(p, '=');
- if(p == nil)
- return nil;
- return estrdup(p+1);
- }
- }
- close(fd);
- return nil;
-}
--- a/sys/src/cmd/ip/httpd/httpsrv.h
+++ /dev/null
@@ -1,79 +1,0 @@
-typedef struct HSPriv HSPriv;
-
-enum
-{- HSTIMEOUT = 15 * 60 * 1000,
-
- /* rewrite replacement field modifiers */
- Modsilent = '@', /* don't tell the browser about the redirect. */
- Modperm = '=', /* generate permanent redirection */
- Modsubord = '*', /* map page & all subordinates to same URL */
- Modonly = '>', /* match only this page, not subordinates */
-
- Redirsilent = 1<<0,
- Redirperm = 1<<1,
- Redirsubord = 1<<2,
- Redironly = 1<<3,
-};
-
-struct HSPriv
-{- char *remotesys;
- char *remoteserv;
-};
-
-extern int logall[3];
-extern char* HTTPLOG;
-extern char* webroot;
-extern char* netdir;
-
-#define STRLEN(s) (sizeof(s)-1)
-
-/* emem.c */
-char *estrdup(char*);
-void* ezalloc(ulong);
-
-/* sendfd.c */
-int authcheck(HConnect *c);
-int checkreq(HConnect *c, HContent *type, HContent *enc, long mtime, char *etag);
-int etagmatch(int, HETag*, char*);
-HRange *fixrange(HRange *h, long length);
-int sendfd(HConnect *c, int fd, Dir *dir, HContent *type, HContent *enc);
-
-/* content.c */
-void contentinit(void);
-HContents dataclass(HConnect *, char*, int);
-int updateQid(int, Qid*);
-HContents uriclass(HConnect *, char*);
-
-/* anonymous.c */
-void anonymous(HConnect*);
-
-/* hint.c */
-void hintprint(HConnect *hc, Hio*, char *, int, int);
-void statsinit(void);
-void urlcanon(char *url);
-void urlinit(void);
-
-/* init.c */
-HConnect* init(int, char**);
-
-vlong Bfilelen(void*);
-
-/* redirect.c */
-void redirectinit(void);
-char* redirect(HConnect *hc, char*, uint *);
-char* masquerade(char*);
-char* authrealm(HConnect *hc, char *path);
-char *undecorated(char *repl);
-
-/* log.c */
-void logit(HConnect*, char*, ...);
-#pragma varargck argpos logit 2
-void writelog(HConnect*, char*, ...);
-#pragma varargck argpos writelog 2
-
-/* authorize.c */
-int authorize(HConnect*, char*);
-
-char *webroot;
--- a/sys/src/cmd/ip/httpd/imagemap.c
+++ /dev/null
@@ -1,320 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-typedef struct Point Point;
-typedef struct OkPoint OkPoint;
-typedef struct Strings Strings;
-
-struct Point
-{- int x;
- int y;
-};
-
-struct OkPoint
-{- Point p;
- int ok;
-};
-
-struct Strings
-{- char *s1;
- char *s2;
-};
-
-static char *me;
-
-int polytest(int, Point, Point, Point);
-Strings getfield(char*);
-OkPoint pt(char*);
-char* translate(HConnect*, char*, char*);
-Point sub(Point, Point);
-float dist(Point, Point);
-
-void
-main(int argc, char **argv)
-{- HConnect *c;
- Hio *hout;
- char *dest;
-
- me = "imagemap";
- c = init(argc, argv);
- hout = &c->hout;
- if(hparseheaders(c, HSTIMEOUT) < 0)
- exits("failed");- anonymous(c);
-
- if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0){- hunallowed(c, "GET, HEAD");
- exits("unallowed");- }
- if(c->head.expectother || c->head.expectcont){- hfail(c, HExpectFail, nil);
- exits("failed");- }
- dest = translate(c, c->req.uri, c->req.search);
-
- if(dest == nil){- if(c->req.vermaj){- hokheaders(c);
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "\r\n");
- }
- hprint(hout, "<head><title>Nothing Found</title></head><body>\n");
- hprint(hout, "Nothing satisfying your search request could be found.\n</body>\n");
- hflush(hout);
- writelog(c, "Reply: 200 imagemap %ld %ld\n", hout->seek, hout->seek);
- exits(nil);
- }
-
- if(http11(c) && strcmp(c->req.meth, "POST") == 0)
- hredirected(c, "303 See Other", dest);
- else
- hredirected(c, "302 Found", dest);
- exits(nil);
-}
-
-char*
-translate(HConnect *c, char *uri, char *search)
-{- Biobuf *b;
- Strings ss;
- OkPoint okp;
- Point p, cen, q, start;
- float close, d;
- char *line, *to, *def, *s, *dst;
- int n, inside, r, ncsa;
-
- if(search == nil){- hfail(c, HNoData, me);
- exits("failed");- }
- okp = pt(search);
- if(!okp.ok){- hfail(c, HBadSearch, me);
- exits("failed");- }
- p = okp.p;
-
- b = Bopen(uri, OREAD);
- if(b == nil){- hfail(c, HNotFound, uri);
- exits("failed");- }
-
- to = nil;
- def = nil;
- dst = nil;
- close = 0.;
- ncsa = 1;
- while(line = Brdline(b, '\n')){- line[Blinelen(b)-1] = 0;
-
- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- if(ncsa){- ss = getfield(line);
- dst = ss.s1;
- line = ss.s2;
- }
- if(strcmp(s, "#cern") == 0){- ncsa = 0;
- continue;
- }
- if(strcmp(s, "rect") == 0){- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- q = okp.p;
- if(!okp.ok || q.x > p.x || q.y > p.y)
- continue;
- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- q = okp.p;
- if(!okp.ok || q.x < p.x || q.y < p.y)
- continue;
- if(!ncsa){- ss = getfield(line);
- dst = ss.s1;
- }
- return dst;
- }else if(strcmp(s, "circle") == 0){- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- cen = okp.p;
- if(!okp.ok)
- continue;
- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- if(ncsa){- okp = pt(s);
- if(!okp.ok)
- continue;
- if(dist(okp.p, cen) >= dist(p, cen))
- return dst;
- }else{- r = strtol(s, nil, 10);
- ss = getfield(line);
- dst = ss.s1;
- d = (float)r * r;
- if(d >= dist(p, cen))
- return dst;
- }
- }else if(strcmp(s, "poly") == 0){- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- start = okp.p;
- if(!okp.ok)
- continue;
- inside = 0;
- cen = start;
- for(n = 1; ; n++){- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- q = okp.p;
- if(!okp.ok)
- break;
- inside = polytest(inside, p, cen, q);
- cen = q;
- }
- inside = polytest(inside, p, cen, start);
- if(!ncsa)
- dst = s;
- if(n >= 3 && inside)
- return dst;
- }else if(strcmp(s, "point") == 0){- ss = getfield(line);
- s = ss.s1;
- line = ss.s2;
- okp = pt(s);
- q = okp.p;
- if(!okp.ok)
- continue;
- d = dist(p, q);
- if(!ncsa){- ss = getfield(line);
- dst = ss.s1;
- }
- if(d == 0.)
- return dst;
- if(close == 0. || d < close){- close = d;
- to = dst;
- }
- }else if(strcmp(s, "default") == 0){- if(!ncsa){- ss = getfield(line);
- dst = ss.s1;
- }
- def = dst;
- }
- }
- if(to == nil)
- to = def;
- return to;
-}
-
-int
-polytest(int inside, Point p, Point b, Point a)
-{- Point pa, ba;
-
- if(b.y>a.y){- pa=sub(p, a);
- ba=sub(b, a);
- }else{- pa=sub(p, b);
- ba=sub(a, b);
- }
- if(0<=pa.y && pa.y<ba.y && pa.y*ba.x<=pa.x*ba.y)
- inside = !inside;
- return inside;
-}
-
-Point
-sub(Point p, Point q)
-{- p.x -= q.x;
- p.y -= q.y;
- return p;
-}
-
-float
-dist(Point p, Point q)
-{- p.x -= q.x;
- p.y -= q.y;
- return (float)p.x * p.x + (float)p.y * p.y;
-}
-
-OkPoint
-pt(char *s)
-{- OkPoint okp;
- Point p;
- char *t, *e;
-
- if(*s == '(')- s++;
- t = strchr(s, ')');
- if(t != nil)
- *t = 0;
- p.x = 0;
- p.y = 0;
- t = strchr(s, ',');
- if(t == nil){- okp.p = p;
- okp.ok = 0;
- return okp;
- }
- e = nil;
- p.x = strtol(s, &e, 10);
- if(e != t){- okp.p = p;
- okp.ok = 0;
- return okp;
- }
- p.y = strtol(t+1, &e, 10);
- if(e == nil || *e != 0){- okp.p = p;
- okp.ok = 0;
- return okp;
- }
- okp.p = p;
- okp.ok = 1;
- return okp;
-}
-
-Strings
-getfield(char *s)
-{- Strings ss;
- char *f;
-
- while(*s == '\t' || *s == ' ')
- s++;
- f = s;
- while(*s && *s != '\t' && *s != ' ')
- s++;
- if(*s)
- *s++ = 0;
- ss.s1 = f;
- ss.s2 = s;
- return ss;
-}
--- a/sys/src/cmd/ip/httpd/init.c
+++ /dev/null
@@ -1,113 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-void
-usage(void)
-{- fprint(2, "usage: %s [-b inbuf] [-d domain] [-p localport]"
- " [-r remoteip] [-s uri-scheme] [-w webroot]"
- " [-L logfd0 logfd1] [-N netdir] [-R reqline]"
- " method version uri [search]\n", argv0);
- exits("usage");-}
-
-char *netdir;
-char *webroot;
-char *HTTPLOG = "httpd/log";
-
-static HConnect connect;
-static HSPriv priv;
-
-HConnect*
-init(int argc, char **argv)
-{- char *vs;
-
- hinit(&connect.hin, 0, Hread);
- hinit(&connect.hout, 1, Hwrite);
- hmydomain = nil;
- connect.replog = writelog;
- connect.scheme = "http";
- connect.port = "80";
- connect.private = &priv;
- priv.remotesys = nil;
- priv.remoteserv = nil;
- fmtinstall('D', hdatefmt);- fmtinstall('H', httpfmt);- fmtinstall('U', hurlfmt);- netdir = "/net";
- ARGBEGIN{- case 'b':
- hload(&connect.hin, EARGF(usage()));
- break;
- case 'd':
- hmydomain = EARGF(usage());
- break;
- case 'p':
- connect.port = EARGF(usage());
- break;
- case 'r':
- priv.remotesys = EARGF(usage());
- break;
- case 's':
- connect.scheme = EARGF(usage());
- break;
- case 'w':
- webroot = EARGF(usage());
- break;
- case 'L':
- logall[0] = strtol(EARGF(usage()), nil, 10);
- logall[1] = strtol(EARGF(usage()), nil, 10);
- break;
- case 'N':
- netdir = EARGF(usage());
- break;
- case 'R':
- snprint((char*)connect.header, sizeof(connect.header), "%s",
- EARGF(usage()));
- break;
- default:
- usage();
- }ARGEND
-
- if(priv.remotesys == nil)
- priv.remotesys = "unknown";
- if(priv.remoteserv == nil)
- priv.remoteserv = "unknown";
- if(hmydomain == nil)
- hmydomain = "unknown";
- if(webroot == nil)
- webroot = "/usr/web";
-
- /*
- * open all files we might need before castrating namespace
- */
- time(nil);
- syslog(0, HTTPLOG, nil);
-
- if(argc != 4 && argc != 3)
- usage();
-
- connect.req.meth = argv[0];
-
- vs = argv[1];
- connect.req.vermaj = 0;
- connect.req.vermin = 9;
- if(strncmp(vs, "HTTP/", 5) == 0){- vs += 5;
- connect.req.vermaj = strtoul(vs, &vs, 10);
- if(*vs == '.')
- vs++;
- connect.req.vermin = strtoul(vs, &vs, 10);
- }
-
- connect.req.uri = argv[2];
- connect.req.search = argv[3];
- connect.head.closeit = 1;
- connect.hpos = (uchar*)strchr((char*)connect.header, '\0');
- connect.hstop = connect.hpos;
- connect.reqtime = time(nil); /* not quite right, but close enough */
- return &connect;
-}
--- a/sys/src/cmd/ip/httpd/log.c
+++ /dev/null
@@ -1,104 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-int logall[3]; /* logall[2] is in "Common Log Format" */
-
-static char *
-monname[12] =
-{- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-void
-logit(HConnect *c, char *fmt, ...)
-{- char buf[4096];
- va_list arg;
- HSPriv *p;
-
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- p = nil;
- if(c != nil)
- p = c->private;
- if(p != nil && p->remotesys != nil)
- syslog(0, HTTPLOG, "%s %s", p->remotesys, buf);
- else
- syslog(0, HTTPLOG, "%s", buf);
-}
-
-void
-writelog(HConnect *c, char *fmt, ...)
-{- HSPriv *p;
- char buf[HBufSize+500], *bufp, *bufe;
- char statuscode[4];
- vlong objectsize;
- ulong now, today;
- int logfd;
- va_list arg;
- Tm *tm;
-
- if(c == nil)
- return;
- p = c->private;
- bufe = buf + sizeof(buf);
- now = time(nil);
- tm = gmtime(now);
- today = now / (24*60*60);
-
- /* verbose logfile, for research on web traffic */
- logfd = logall[today & 1];
- if(logfd >= 0){- if(c->hstop == c->header || c->hstop[-1] != '\n')
- *c->hstop = '\n';
- *c->hstop = '\0';
- bufp = seprint(buf, bufe, "==========\n");
- bufp = seprint(bufp, bufe, "LogTime: %D\n", now);
- bufp = seprint(bufp, bufe, "ConnTime: %D\n", c->reqtime);
- bufp = seprint(bufp, bufe, "RemoteIP: %s\n", p->remotesys);
- bufp = seprint(bufp, bufe, "Port: %s\n", p->remoteserv);
- va_start(arg, fmt);
- bufp = vseprint(bufp, bufe, fmt, arg);
- va_end(arg);
- if(c->req.uri != nil && c->req.uri[0] != 0)
- bufp = seprint(bufp, bufe, "FinalURI: %s\n", c->req.uri);
- bufp = seprint(bufp, bufe, "----------\n%s\n", (char*)c->header);
- write(logfd, buf, bufp-buf); /* append-only file */
- }
-
- /* another log, with less information but formatted for common analysis tools */
- if(logall[2] > 0 && strncmp(fmt, "Reply: ", 7) == 0){- objectsize = 0;
- strecpy(statuscode, statuscode+4, fmt+7);
- if( fmt[7] == '%'){- va_start(arg, fmt);
- vseprint(statuscode, statuscode+4, fmt+7, arg);
- va_end(arg);
- }else if(
- strcmp(fmt+7, "200 file %lld %lld\n") == 0 ||
- strcmp(fmt+7, "206 partial content %lld %lld\n") == 0 ||
- strcmp(fmt+7, "206 partial content, early termination %lld %lld\n") == 0){- va_start(arg, fmt);
- objectsize = va_arg(arg, vlong); /* length in sendfd.c */
- USED(objectsize);
- objectsize = va_arg(arg, vlong); /* wrote in sendfd.c */
- va_end(arg);
- }
- bufp = seprint(buf, bufe, "%s - -", p->remotesys);
- bufp = seprint(bufp, bufe, " [%.2d/%s/%d:%.2d:%.2d:%.2d +0000]", tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec);
- if(c->req.uri == nil || c->req.uri[0] == 0){- bufp = seprint(bufp, bufe, " \"%.*s\"",
- (int)utfnlen((char*)c->header, strcspn((char*)c->header, "\r\n")),
- (char*)c->header);
- }else{- /* use more canonical form of URI, if available */
- bufp = seprint(bufp, bufe, " \"%s %s HTTP/%d.%d\"", c->req.meth, c->req.uri, c->req.vermaj, c->req.vermin);
- }
- bufp = seprint(bufp, bufe, " %s %lld\n", statuscode, objectsize);
- write(logall[2], buf, bufp-buf); /* append-only file */
- }
-}
--- a/sys/src/cmd/ip/httpd/man2html.c
+++ /dev/null
@@ -1,449 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-static Hio *hout;
-static Hio houtb;
-static HConnect *connect;
-
-void doconvert(char*, int);
-
-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\n", hversion, title);
- hprint(hout, "Date: %D\n", time(nil));
- hprint(hout, "Server: Plan9\n");
- hprint(hout, "Content-type: text/html\n");
- hprint(hout, "\n");
- hprint(hout, "<head><title>%s</title></head>\n", title);
- hprint(hout, "<body><h1>%s</h1></body>\n", title);
- hprint(hout, "%s\n", buf);
- hflush(hout);
- writelog(connect, "Reply: 404\nReason: %s\n", title);
- exits(nil);
-}
-
-typedef struct Hit Hit;
-struct Hit
-{- Hit *next;
- char *file;
-};
-
-void
-lookup(char *object, int section, Hit **list)
-{- int fd;
- char *p, *f;
- Biobuf b;
- char file[256];
- Hit *h;
-
- while(*list != nil)
- list = &(*list)->next;
-
- snprint(file, sizeof(file), "/sys/man/%d/INDEX", section);
- fd = open(file, OREAD);
- if(fd >= 0){- Binit(&b, fd, OREAD);
- for(;;){- p = Brdline(&b, '\n');
- if(p == nil)
- break;
- p[Blinelen(&b)-1] = 0;
- f = strchr(p, ' ');
- if(f == nil)
- continue;
- *f++ = 0;
- if(strcmp(p, object) == 0){- h = ezalloc(sizeof *h);
- *list = h;
- h->next = nil;
- snprint(file, sizeof(file), "/%d/%s", section, f);
- h->file = estrdup(file);
- close(fd);
- return;
- }
- }
- close(fd);
- }
- snprint(file, sizeof(file), "/sys/man/%d/%s", section, object);
- if(access(file, 0) == 0){- h = ezalloc(sizeof *h);
- *list = h;
- h->next = nil;
- h->file = estrdup(file+8);
- }
-}
-
-void
-manindex(int sect, int vermaj)
-{- int i;
-
- if(vermaj){- hokheaders(connect);
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "\r\n");
- }
-
- hprint(hout, "<head><title>plan 9 section index");
- if(sect)
- hprint(hout, "(%d)\n", sect);
- hprint(hout, "</title></head><body>\n");
- hprint(hout, "<H6>Section Index");
- if(sect)
- hprint(hout, "(%d)\n", sect);
- hprint(hout, "</H6>\n");
-
- if(sect)
- hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
- sect, sect);
- else for(i = 1; i < 10; i++)
- hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
- i, i);
- hprint(hout, "</body>\n");
-}
-
-void
-man(char *o, int sect, int vermaj)
-{- int i;
- Hit *list;
-
- list = nil;
-
- if(*o == 0){- manindex(sect, vermaj);
- return;
- }
-
- if(sect > 0 && sect < 10)
- lookup(o, sect, &list);
- else
- for(i = 1; i < 9; i++)
- lookup(o, i, &list);
-
- if(list != nil && list->next == nil){- doconvert(list->file, vermaj);
- return;
- }
-
- if(vermaj){- hokheaders(connect);
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "\r\n");
- }
-
- hprint(hout, "<head><title>plan 9 man %H", o);
- if(sect)
- hprint(hout, "(%d)\n", sect);
- hprint(hout, "</title></head><body>\n");
- hprint(hout, "<H6>Search for %H", o);
- if(sect)
- hprint(hout, "(%d)\n", sect);
- hprint(hout, "</H6>\n");
-
- for(; list; list = list->next)
- hprint(hout, "<p><a href=\"/magic/man2html%U\">/magic/man2html%H</a>\n",
- list->file, list->file);
- hprint(hout, "</body>\n");
-}
-
-void
-strlwr(char *p)
-{- for(; *p; p++)
- if('A' <= *p && *p <= 'Z')- *p += 'a'-'A';
-}
-
-void
-redirectto(char *uri)
-{- if(connect){- hmoved(connect, uri);
- exits(0);
- }else
- hprint(hout, "Your selection moved to <a href=\"%U\"> here</a>.<p></body>\r\n", uri);
-}
-
-void
-searchfor(char *search)
-{- int i, j, n, fd;
- char *p, *sp;
- Biobufhdr *b;
- char *arg[32];
-
- hprint(hout, "<head><title>plan 9 search for %H</title></head>\n", search);
- hprint(hout, "<body>\n");
-
- hprint(hout, "<p>This is a keyword search through Plan 9 man pages.\n");
- hprint(hout, "The search is case insensitive; blanks denote \"boolean and\".\n");
- hprint(hout, "<FORM METHOD=\"GET\" ACTION=\"/magic/man2html\">\n");
- hprint(hout, "<INPUT NAME=\"pat\" TYPE=\"text\" SIZE=\"60\">\n");
- hprint(hout, "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n");
- hprint(hout, "</FORM>\n");
-
- hprint(hout, "<hr><H6>Search for %H</H6>\n", search);
- n = getfields(search, arg, 32, 1, "+");
- for(i = 0; i < n; i++){- for(j = i+1; j < n; j++){- if(strcmp(arg[i], arg[j]) > 0){- sp = arg[j];
- arg[j] = arg[i];
- arg[i] = sp;
- }
- }
- sp = malloc(strlen(arg[i]) + 2);
- if(sp != nil){- strcpy(sp+1, arg[i]);
- sp[0] = ' ';
- arg[i] = sp;
- }
- }
-
- /*
- * search index till line starts alphabetically < first token
- */
- fd = open("/sys/man/searchindex", OREAD);- if(fd < 0){- hprint(hout, "<body>error: No Plan 9 search index\n");
- hprint(hout, "</body>");
- return;
- }
- p = malloc(32*1024);
- if(p == nil){- close(fd);
- return;
- }
- b = ezalloc(sizeof *b);
- Binits(b, fd, OREAD, (uchar*)p, 32*1024);
- for(;;){- p = Brdline(b, '\n');
- if(p == nil)
- break;
- p[Blinelen(b)-1] = 0;
- for(i = 0; i < n; i++){- sp = strstr(p, arg[i]);
- if(sp == nil)
- break;
- p = sp;
- }
- if(i < n)
- continue;
- sp = strrchr(p, '\t');
- if(sp == nil)
- continue;
- sp++;
- hprint(hout, "<p><a href=\"/magic/man2html/%U\">/magic/man2html/%H</a>\n",
- sp, sp);
- }
- hprint(hout, "</body>");
-
- Bterm(b);
- free(b);
- free(p);
- close(fd);
-}
-
-/*
- * find man pages mentioning the search string
- */
-void
-dosearch(int vermaj, char *search)
-{- int sect;
- char *p;
-
- if(strncmp(search, "man=", 4) == 0){- sect = 0;
- search = hurlunesc(connect, search+4);
- p = strchr(search, '&');
- if(p != nil){- *p++ = 0;
- if(strncmp(p, "sect=", 5) == 0)
- sect = atoi(p+5);
- }
- man(search, sect, vermaj);
- return;
- }
-
- if(vermaj){- hokheaders(connect);
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "\r\n");
- }
-
- if(strncmp(search, "pat=", 4) == 0){- search = hurlunesc(connect, search+4);
- search = hlower(search);
- searchfor(search);
- return;
- }
-
- hprint(hout, "<head><title>illegal search</title></head>\n");
- hprint(hout, "<body><p>Illegally formatted Plan 9 man page search</p>\n");
- search = hurlunesc(connect, search);
- hprint(hout, "<body><p>%H</p>\n", search);
- hprint(hout, "</body>");
-}
-
-/*
- * 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);
- }
-}
-
-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);
-}
--- a/sys/src/cmd/ip/httpd/mkfile
+++ /dev/null
@@ -1,76 +1,0 @@
-</$objtype/mkfile
-
-HFILES=\
- /sys/include/httpd.h\
- httpsrv.h\
-
-TARG=\
- httpd\
- imagemap\
- man2html\
- save\
- netlib_find\
- netlib_history\
- webls\
- wikipost\
-
-XTARG=\
- httpd\
- imagemap\
- netlib_find\
- netlib_history\
- man2html\
- save\
- wikipost\
-
-LIB=libhttps.a$O
-
-LIBS=libhttps.a$O
-LIBSOFILES=\
- anonymous.$O\
- content.$O\
- emem.$O\
- hints.$O\
- init.$O\
- log.$O\
- redirect.$O\
- sendfd.$O\
- authorize.$O\
-
-BIN=/$objtype/bin/ip/httpd
-
-CLEANFILES=$LIB
-
-</sys/src/cmd/mkmany
-
-trial: $O.netlib_history
- # should first mount -b /srv/histnetlib /usr/web/historic
- echo '
- ' | $O.netlib_history GET HTTP/1.0 xxx 'file=fp%2Fdtoa.c.gz'
-
-trial2: $O.netlib_find
- echo "\n" | $O.netlib_find GET HTTP/1.0 xxx 'db=1&pat=Hearing' > /tmp/search
- sed 17q /tmp/search
-
-$LIBS: $LIBSOFILES
- ar vu $LIBS $newprereq
- rm $newprereq
- # rm $newmember - cannot do this because of mk race
-
-
-re:N: v.re
- v.re redirect.urls
-
-none:VQ:
- echo usage: mk all, install, installall, '$O'.cmd, cmd.install, or cmd.installall
- echo usage: mk safeinstall, safeinstallall, cmd.safeinstallall, or cmd.safeinstallall
-
-$O.9down: 9down.$O whois.$O classify.$O $LIB
- $LD -o $target $prereq
-
-$O.test9down: 9down4e.$O whois.$O classify.$O $LIB
- $LD -o $target $prereq
-
-$O.testclassify: testclassify.$O whois.$O classify.$O $LIB
- $LD -o $target $prereq
-
--- a/sys/src/cmd/ip/httpd/netlib_find.c
+++ /dev/null
@@ -1,278 +1,0 @@
-/* invoked from /netlib/pub/search.html */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-void bib_fmt(char*,char*);
-void index_fmt(char*,char*);
-void no_fmt(char*,char*);
-int send(HConnect*);
-
-Hio *hout;
-
-/********** table of databases ************/
-
-typedef struct DB DB;
-struct DB
-{- int SELECT; /* value from search.html */
- char *log; /* abbreviation for logfile */
- int maxhit; /* maximum number of hits to return */
- char *file; /* searchfs database */
- void (*fmt)(char*,char*); /* convert one record to HTML */
- char *postlude; /* trailer text */
-};
-
-DB db[] =
-{- {0, "netlib", 250, "/srv/netlib_DEFAULT", index_fmt,- "<HR><A HREF=\"/netlib/master\">browse netlib</A></BODY>\r\n"},
- {1, "BibNet", 250, "/srv/netlib_bibnet", bib_fmt,- "<HR><A HREF=\"/netlib/bibnet\">browse BibNet</A></BODY>\r\n"},
- {2, "compgeom", 250, "/srv/netlib_compgeom", no_fmt, "</BODY>\r\n"},- {3, "approx", 250, "/srv/netlib_approximation", no_fmt,- "<HR><A HREF=\"/netlib/a/catalog.html.gz\">hierarchical catalog</A></BODY>\r\n"},
- {4, "siam", 50, "/srv/netlib_siam-Secret", no_fmt, "</BODY>\r\n"},- {-1,"",0,"",no_fmt,""}-};
-
-
-
-/********** reformat database record as HTML ************/
-
-void /* tr '\015' '\012' ("uncombline") */-no_fmt(char*s,char*e)
-{- /* s = start, e = (one past) end of database record */
- char *p;
- for(p = s; p<e; p++)
- if(*p=='\r'){- hwrite(hout, s,p-s);
- hprint(hout, "\n");
- s = p+1;
- }
-}
-
-int /* should the filename have .gz appended? */
-suffix(char*filename)
-{- int n;
- char *z;
-
- if(!filename || *filename==0)
- return(0);
- n = strlen(filename);
- if(strncmp(".html",filename+n-5,5)==0)- return(0);
- z = malloc(n+50);
- if(z == nil)
- return(0);
- strcpy(z,"/netlib/pub/");
- strcat(z,filename);
- strcat(z,".gz");
- if(access(z,4)==0){- free(z);
- return(1);
- }
- free(z);
- return(0);
-}
-
-void /* add HREF to "file:" lines */
-index_fmt(char*s,char*e)
-{- char *p, *filename;
- if(strncmp(s,"file",4)==0 && (s[4]==' '||s[4]=='\t')){- for(filename = s+4; strchr(" \t",*filename); filename++){}- for(s = filename; *s && strchr("\r\n",*s)==nil; s++){}- *s++ = '\0';
- if(*s=='\n') s++;
- hprint(hout, "file: <A HREF=\"/netlib/%s",filename);
- if(suffix(filename))
- hprint(hout, ".gz");
- hprint(hout, "\">%s</A>\r\n",filename);
- for(p = s; p<e; p++)
- if(*p=='\r'){- hwrite(hout, s,p-s);
- hprint(hout, "\n");
- s = p+1;
- }
- }else if(strncmp(s,"lib",3)==0 && (s[3]==' '||s[3]=='\t')){- for(filename = s+3; strchr(" \t",*filename); filename++){}- for(s = filename; *s && strchr("\r\n",*s)==nil; s++){}- *s++ = '\0';
- if(*s=='\n') s++;
- hprint(hout, "lib: <A HREF=\"/netlib/%s",filename);
- hprint(hout, "\">%s</A>\r\n",filename);
- for(p = s; p<e; p++)
- if(*p=='\r'){- hwrite(hout, s,p-s);
- hprint(hout, "\n");
- s = p+1;
- }
- }else{- no_fmt(s,e);
- }
-}
-
-void /* add HREF to "URL" lines */
-bib_fmt(char*s,char*e)
-{- char *p, *filename;
- for(p = s; p<e; p++)
- if(*p=='\r'){- hwrite(hout, s,p-s);
- hprint(hout, "\n");
- s = p+1;
- if(strncmp(s," URL =",6)==0 &&
- (filename = strchr(s+6,'"'))!=nil){- filename++;
- for(s = filename; *s && strchr("\"\r\n",*s)==nil; s++){}- *s++ = '\0';
- p = s;
- hprint(hout, " URL =<A HREF=\"%s\">%s</A>",
- filename,filename);
- }
- }
-}
-
-
-/********** main() calls httpheadget() calls send() ************/
-
-void
-main(int argc, char **argv)
-{- HConnect *c;
-
- c = init(argc, argv);
- hout = &c->hout;
- if(hparseheaders(c, HSTIMEOUT) >= 0)
- send(c);
- exits(nil);
-}
-
-Biobuf Blist;
-
-Biobuf*
-init800fs(char*name,char*pat)
-{- int fd800fs, n;
- char*search;
-
- fd800fs = open(name, ORDWR);
- if(fd800fs < 0)
- exits("can't connect to 800fs server");- if(mount(fd800fs, -1, "/mnt", MREPL, "") == -1)
- exits("can't mount /mnt");- fd800fs = open("/mnt/search", ORDWR);- n = strlen("search=")+strlen(pat)+1;- search = ezalloc(n);
- strcpy(search,"search=");
- strcat(search,pat);
- write(fd800fs,search,n);
- free(search);
- Binit(&Blist, fd800fs,OREAD);
- return(&Blist);
-}
-
-
-static char *
-hq(char *text)
-{- int textlen = strlen(text), escapedlen = textlen;
- char *escaped, *s, *w;
-
- for(s = text; *s; s++)
- if(*s=='<' || *s=='>' || *s=='&')
- escapedlen += 4;
- escaped = ezalloc(escapedlen+1);
- for(s = text, w = escaped; *s; s++){- if(*s == '<'){- strcpy(w, "<");
- w += 4;
- }else if(*s == '>'){- strcpy(w, ">");
- w += 4;
- }else if(*s == '&'){- strcpy(w, "&");
- w += 5;
- }else{- *w++ = *s;
- }
- }
- return escaped;
-}
-
-int
-send(HConnect *c)
-{- Biobuf*blist;
- int m, n, dbi, nmatch;
- char *pat, *s, *e;
- HSPairs *q;
-
- if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
- return hunallowed(c, "GET, HEAD");
- if(c->head.expectother || c->head.expectcont)
- return hfail(c, HExpectFail, nil);
- if(c->req.search == nil || !*c->req.search)
- return hfail(c, HNoData, "netlib_find");
- s = c->req.search;
- while((s = strchr(s, '+')) != nil)
- *s++ = ' ';
- dbi = -1;
- pat = nil;
- for(q = hparsequery(c, hstrdup(c, c->req.search)); q; q = q->next){- if(strcmp(q->s, "db") == 0){- m = atoi(q->t);
- for(dbi = 0; m!=db[dbi].SELECT; dbi++)
- if(db[dbi].SELECT<0)
- exits("unrecognized db");- }else if(strcmp(q->s, "pat") == 0){- pat = q->t;
- }
- }
- if(dbi < 0)
- exits("missing db field in query");- if(pat == nil)
- exits("missing pat field in query");- logit(c, "netlib_find %s %s", db[dbi].log,pat);
-
- blist = init800fs(db[dbi].file,pat);
-
- if(c->req.vermaj){- hokheaders(c);
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "\r\n");
- }
- if(strcmp(c->req.meth, "HEAD") == 0){- writelog(c, "Reply: 200 netlib_find 0\n");
- hflush(hout);
- exits(nil);
- }
-
- hprint(hout, "<HEAD><TITLE>%s/%s</TITLE></HEAD>\r\n<BODY>\r\n",
- db[dbi].log,hq(pat));
- nmatch = 0;
-
- while(s = Brdline(blist, '\n')){ /* get next database record */- n = Blinelen(blist);
- e = s+n;
- hprint(hout, "<PRE>");
- (*db[dbi].fmt)(s,e);
- hprint(hout, "</PRE>\r\n");
- if(nmatch++>=db[dbi].maxhit){- hprint(hout, "<H4>reached limit at %d hits</H4>\n\r",nmatch);
- break;
- }
- }
- if(nmatch==0)
- hprint(hout, "<H4>Nothing Found.</H4>\r\n");
- hprint(hout, db[dbi].postlude);
- hflush(hout);
- writelog(c, "Reply: 200 netlib_find %ld %ld\n", hout->seek, hout->seek);
- return 1;
-}
--- a/sys/src/cmd/ip/httpd/netlib_history.c
+++ /dev/null
@@ -1,218 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-Hio *HO;
-int diffb;
-
-enum{ DAY = 24*60*60 };-
-void
-lastbefore(ulong t, char *f, char *b)
-{- Tm *tm;
- Dir *dir;
- int try;
- ulong t0, mtime;
-
- t0 = t;
- for(try=0; try<10; try++) {- tm = localtime(t);
- t -= DAY;
- sprint(b,"%.4d/%.2d%.2d/netlib/pub/%s",tm->year+1900,tm->mon+1,tm->mday,f);
- dir = dirstat(b);
- if(dir == nil)
- continue;
- mtime = dir->mtime;
- free(dir);
- if(mtime > t0)
- continue;
- return;
- }
- strcpy(b, "filenotfound");
-}
-
-// create explicit file for diff, which otherwise would create a
-// mode 0600 file that it couldn't read (because running as none)
-void
-gunzip(char *f, char *tmp)
-{- int fd = open(tmp, OWRITE);
-
- if(fd < 0) // can't happen
- return;
- switch(fork()){- case 0:
- dup(fd, 1);
- close(fd);
- close(0);
- execl("/bin/gunzip", "gunzip", "-c", f, nil);- hprint(HO, "can't exec gunzip: %r\n");
- break;
- case -1:
- hprint(HO, "fork failed: %r\n");
- default:
- while(waitpid() != -1)
- ;
- break;
- }
- close(fd);
-}
-
-void
-netlibhistory(char *file)
-{- char buf[500], pair[2][500], tmpf[2][30], *f;
- int toggle = 0, started = 0, limit;
- Dir *dir;
- ulong otime, dt;
- int i, fd, tmpcnt;
-
- if(strncmp(file, "../", 3) == 0 || strstr(file, "/../") ||
- strlen(file) >= sizeof(buf) - strlen("1997/0204/netlib/pub/0"))- return;
- limit = 50;
- if(diffb){- limit = 10;
- // create two tmp files for gunzip
- for(i = 0, tmpcnt = 0; i < 2 && tmpcnt < 20; tmpcnt++){- snprint(tmpf[i], sizeof(tmpf[0]), "/tmp/d%x", tmpcnt);
- if(access(buf, AEXIST) == 0)
- continue;
- fd = create(tmpf[i], OWRITE, 0666);
- if(fd < 0)
- goto done;
- close(fd);
- i++;
- }
- }
- otime = time(0);
- hprint(HO,"<UL>\n");
- while(limit--){- lastbefore(otime, file, buf);
- dir = dirstat(buf);
- if(dir == nil)
- goto done;
- dt = DAY/2;
- while(otime <= dir->mtime){- lastbefore(otime-dt, file, buf);
- free(dir);
- dir = dirstat(buf);
- if(dir == nil)
- goto done;
- dt += DAY/2;
- }
- f = pair[toggle];
- strcpy(f, buf);
- if(diffb && strcmp(f+strlen(f)-3, ".gz") == 0){- gunzip(f, tmpf[toggle]);
- strcpy(f, tmpf[toggle]);
- }
- if(diffb && started){- hprint(HO, "<PRE>\n");
- hflush(HO);
- switch(fork()){- case 0:
- execl("/bin/diff", "diff", "-nb",- pair[1-toggle], pair[toggle], nil);
- hprint(HO, "can't exec diff: %r\n");
- break;
- case -1:
- hprint(HO, "fork failed: %r\n");
- break;
- default:
- while(waitpid() != -1)
- ;
- break;
- }
- hprint(HO, "</PRE>\n");
- }
- hprint(HO,"<LI><A HREF=\"/historic/%s\">%s</A> %lld bytes\n",
- buf, 4+asctime(gmtime(dir->mtime)), dir->length);
- if(diffb)
- hprint(HO," <FONT SIZE=-1>(%s)</FONT>\n", pair[toggle]);
- toggle = 1-toggle;
- started = 1;
- otime = dir->mtime;
- free(dir);
- }
- hprint(HO,"<LI>...\n");
-done:
- hprint(HO,"</UL>\n");
- if(diffb){- remove(tmpf[0]);
- remove(tmpf[1]);
- }
-}
-
-int
-send(HConnect *c)
-{- char *file, *s;
- HSPairs *q;
-
- if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
- return hunallowed(c, "GET, HEAD");
- if(c->head.expectother || c->head.expectcont)
- return hfail(c, HExpectFail, nil);
- if(c->req.search == nil || !*c->req.search)
- return hfail(c, HNoData, "netlib_history");
- s = c->req.search;
- while((s = strchr(s, '+')) != nil)
- *s++ = ' ';
- file = nil;
- for(q = hparsequery(c, hstrdup(c, c->req.search)); q; q = q->next){- if(strcmp(q->s, "file") == 0)
- file = q->t;
- else if(strcmp(q->s, "diff") == 0)
- diffb = 1;
- }
- if(file == nil)
- return hfail(c, HNoData, "netlib_history missing file field");
- logit(c, "netlib_hist %s%s", file, diffb?" DIFF":"");
-
- if(c->req.vermaj){- hokheaders(c);
- hprint(HO, "Content-type: text/html\r\n");
- hprint(HO, "\r\n");
- }
- if(strcmp(c->req.meth, "HEAD") == 0){- writelog(c, "Reply: 200 netlib_history 0\n");
- hflush(HO);
- exits(nil);
- }
-
- hprint(HO, "<HEAD><TITLE>%s history</TITLE></HEAD>\n<BODY>\n",file);
- hprint(HO, "<H2>%s history</H2>\n",file);
- hprint(HO, "<I>Netlib's copy of %s was changed\n", file);
- hprint(HO, "on the dates shown. <BR>Click on the date link\n");
- hprint(HO, "to retrieve the corresponding version.</I>\n");
- if(diffb){- hprint(HO, "<BR><I>Lines beginning with < are for the\n");
- hprint(HO, "newer of the two versions.</I>\n");
- }
-
- if(chdir("/usr/web/historic") < 0)- hprint(HO, "chdir failed: %r\n");
- netlibhistory(file);
-
- hprint(HO, "<BR><A HREF=\"http://cm.bell-labs.com/who/ehg\">Eric Grosse</A>\n");
- hprint(HO, "</BODY></HTML>\n");
- hflush(HO);
- writelog(c, "Reply: 200 netlib_history %ld %ld\n", HO->seek, HO->seek);
- return 1;
-}
-
-void
-main(int argc, char **argv)
-{- HConnect *c;
-
- c = init(argc, argv);
- HO = &c->hout;
- if(hparseheaders(c, HSTIMEOUT) >= 0)
- send(c);
- exits(nil);
-}
--- a/sys/src/cmd/ip/httpd/redirect.c
+++ /dev/null
@@ -1,227 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-enum
-{- HASHSIZE = 1019,
-};
-
-typedef struct Redir Redir;
-struct Redir
-{- Redir *next;
- char *pat;
- char *repl;
- uint flags; /* generated from repl's decorations */
-};
-
-static Redir *redirtab[HASHSIZE];
-static Redir *vhosttab[HASHSIZE];
-static char emptystring[1];
-/* these two arrays must be kept in sync */
-static char decorations[] = { Modsilent, Modperm, Modsubord, Modonly, '\0' };-static uint redirflags[] = { Redirsilent, Redirperm, Redirsubord, Redironly, };-
-/* replacement field decorated with redirection modifiers? */
-static int
-isdecorated(char *repl)
-{- return strchr(decorations, repl[0]) != nil;
-}
-
-static uint
-decor2flags(char *repl)
-{- uint flags;
- char *p;
-
- flags = 0;
- while ((p = strchr(decorations, *repl++)) != nil)
- flags |= redirflags[p - decorations];
- return flags;
-}
-
-/* return replacement without redirection modifiers */
-char *
-undecorated(char *repl)
-{- while (isdecorated(repl))
- repl++;
- return repl;
-}
-
-static int
-hashasu(char *key, int n)
-{- ulong h;
-
- h = 0;
- while(*key != 0)
- h = 65599*h + *(uchar*)key++;
- return h % n;
-}
-
-static void
-insert(Redir **tab, char *pat, char *repl)
-{- Redir **l;
- Redir *srch;
- ulong hash;
-
- hash = hashasu(pat, HASHSIZE);
- for(l = &tab[hash]; *l; l = &(*l)->next)
- ;
- *l = srch = ezalloc(sizeof(Redir));
- srch->pat = pat;
- srch->flags = decor2flags(repl);
- srch->repl = undecorated(repl);
- srch->next = 0;
-}
-
-static void
-cleartab(Redir **tab)
-{- Redir *t;
- int i;
-
- for(i = 0; i < HASHSIZE; i++){- while((t = tab[i]) != nil){- tab[i] = t->next;
- free(t->pat);
- free(t->repl);
- free(t);
- }
- }
-}
-
-void
-redirectinit(void)
-{- static Biobuf *b = nil;
- static Qid qid;
- char *file, *line, *s, *host, *field[3];
- static char pfx[] = "http://";
-
- file = "/sys/lib/httpd.rewrite";
- if(b != nil){- if(updateQid(Bfildes(b), &qid) == 0)
- return;
- Bterm(b);
- }
- b = Bopen(file, OREAD);
- if(b == nil)
- sysfatal("can't read from %s", file);- updateQid(Bfildes(b), &qid);
-
- cleartab(redirtab);
- cleartab(vhosttab);
-
- while((line = Brdline(b, '\n')) != nil){- line[Blinelen(b)-1] = 0;
- s = strchr(line, '#');
- if(s != nil && (s == line || s[-1] == ' ' || s[-1] == '\t'))
- *s = '\0'; /* chop comment iff after whitespace */
- if(tokenize(line, field, nelem(field)) == 2){- if(strncmp(field[0], pfx, STRLEN(pfx)) == 0 &&
- strncmp(undecorated(field[1]), pfx, STRLEN(pfx)) != 0){- /* url -> filename */
- host = field[0] + STRLEN(pfx);
- s = strrchr(host, '/');
- if(s)
- *s = 0; /* chop trailing slash */
-
- insert(vhosttab, estrdup(host), estrdup(field[1]));
- }else{- insert(redirtab, estrdup(field[0]), estrdup(field[1]));
- }
- }
- }
- syslog(0, HTTPLOG, "redirectinit pid=%d", getpid());
-}
-
-static Redir*
-lookup(Redir **tab, char *pat, int count)
-{- Redir *srch;
- ulong hash;
-
- hash = hashasu(pat,HASHSIZE);
- for(srch = tab[hash]; srch != nil; srch = srch->next)
- if(strcmp(pat, srch->pat) == 0) {- /* only exact match wanted? */
- if (!(srch->flags & Redironly) || count == 0)
- return srch;
- }
- return nil;
-}
-
-static char*
-prevslash(char *p, char *s)
-{- while(--s > p)
- if(*s == '/')
- break;
- return s;
-}
-
-/*
- * find the longest match of path against the redirection table,
- * chopping off the rightmost path component until success or
- * there's nothing left. return a copy of the replacement string
- * concatenated with a slash and the portion of the path *not* matched.
- * So a match of /who/gre/some/stuff.html matched against
- * /who/gre http://gremlinsrus.org
- * returns
- * http://gremlinsrus.org/some/stuff.html
- *
- * further flags: if Redironly, match only the named page and no
- * subordinate ones. if Redirsubord, map the named patch and any
- * subordinate ones to the same replacement URL.
- */
-char*
-redirect(HConnect *hc, char *path, uint *flagp)
-{- Redir *redir;
- char *s, *newpath, *repl;
- int c, n, count;
-
- count = 0;
- for(s = strchr(path, '\0'); s > path; s = prevslash(path, s)){- c = *s;
- *s = '\0';
- redir = lookup(redirtab, path, count++);
- *s = c;
- if(redir != nil){- if (flagp)
- *flagp = redir->flags;
- repl = redir->repl;
- if(redir->flags & Redirsubord)
- /* don't append s, all matches map to repl */
- s = "";
- n = strlen(repl) + strlen(s) + 2 + UTFmax;
- newpath = halloc(hc, n);
- snprint(newpath, n, "%s%s", repl, s);
- return newpath;
- }
- }
- return nil;
-}
-
-/*
- * if host is virtual, return implicit prefix for URI within webroot.
- * if not, return empty string.
- * return value should not be freed by caller.
- */
-char*
-masquerade(char *host)
-{- Redir *redir;
-
- redir = lookup(vhosttab, host, 0);
- if(redir == nil)
- return emptystring;
- return redir->repl;
-}
--- a/sys/src/cmd/ip/httpd/save.c
+++ /dev/null
@@ -1,153 +1,0 @@
-/*
- * for GET or POST to /magic/save/foo.
- * add incoming data to foo.data.
- * send foo.html as reply.
- *
- * supports foo.data with "exclusive use" mode to prevent interleaved saves.
- * thus http://cm.bell-labs.com/magic/save/t?args should access:
- * -lrw-rw--w- M 21470 ehg web 1533 May 21 18:19 /usr/web/save/t.data
- * --rw-rw-r-- M 21470 ehg web 73 May 21 18:17 /usr/web/save/t.html
-*/
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-enum
-{- MaxLog = 24*1024, /* limit on length of any one log request */
- LockSecs = MaxLog/500, /* seconds to wait before giving up on opening the data file */
-};
-
-static int
-dangerous(char *s)
-{- if(s == nil)
- return 1;
-
- /*
- * This check shouldn't be needed;
- * filename folding is already supposed to have happened.
- * But I'm paranoid.
- */
- while(s = strchr(s,'/')){- if(s[1]=='.' && s[2]=='.')
- return 1;
- s++;
- }
- return 0;
-}
-
-/*
- * open a file which might be locked.
- * if it is, spin until available
- */
-int
-openLocked(char *file, int mode)
-{- char buf[ERRMAX];
- int tries, fd;
-
- for(tries = 0; tries < LockSecs*2; tries++){- fd = open(file, mode);
- if(fd >= 0)
- return fd;
- errstr(buf, sizeof buf);
- if(strstr(buf, "locked") == nil)
- break;
- sleep(500);
- }
- return -1;
-}
-
-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");- }
-
- 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);
-}
--- a/sys/src/cmd/ip/httpd/sendfd.c
+++ /dev/null
@@ -1,466 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-static void printtype(Hio *hout, HContent *type, HContent *enc);
-
-/*
- * these should be done better; see the reponse codes in /lib/rfc/rfc2616 for
- * more info on what should be included.
- */
-#define UNAUTHED "You are not authorized to see this area.\n"
-#define NOCONTENT "No acceptable type of data is available.\n"
-#define NOENCODE "No acceptable encoding of the contents is available.\n"
-#define UNMATCHED "The entity requested does not match the existing entity.\n"
-#define BADRANGE "No bytes are avaible for the range you requested.\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", 1 + 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", 1 + r->stop - r->start);
- hprint(hout, "\r\n");
- }
- hflush(hout);
-
- if(seek(fd, r->start, 0) != r->start){- ok = -1;
- break;
- }
- for(tr = 1 + r->stop - r->start; 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
-printtype(Hio *hout, HContent *type, HContent *enc)
-{- hprint(hout, "Content-Type: %s/%s", type->generic, type->specific);
-/*
- if(cistrcmp(type->generic, "text") == 0)
- hprint(hout, ";charset=utf-8");
-*/
- hprint(hout, "\r\n");
- if(enc != nil)
- hprint(hout, "Content-Encoding: %s\r\n", enc->generic);
-}
-
-int
-etagmatch(int strong, HETag *tags, char *e)
-{- char *s, *t;
-
- for(; tags != nil; tags = tags->next){- if(strong && tags->weak)
- continue;
- s = tags->etag;
- if(s[0] == '*' && s[1] == '\0')
- return 1;
-
- t = e + 1;
- while(*t != '"'){- if(*s != *t)
- break;
- s++;
- t++;
- }
-
- if(*s == '\0' && *t == '"')
- return 1;
- }
- return 0;
-}
-
-static char *
-acceptcont(char *s, char *e, HContent *ok, char *which)
-{- char *sep;
-
- if(ok == nil)
- return seprint(s, e, "Your browser accepts any %s.<br>\n", which);
- s = seprint(s, e, "Your browser accepts %s: ", which);
- sep = "";
- for(; ok != nil; ok = ok->next){- if(ok->specific)
- s = seprint(s, e, "%s%s/%s", sep, ok->generic, ok->specific);
- else
- s = seprint(s, e, "%s%s", sep, ok->generic);
- sep = ", ";
- }
- return seprint(s, e, ".<br>\n");
-}
-
-/*
- * 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: %zud\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);
-}
-
-/*
- * 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;
-}
-
-/*
- * length is the actual length of the entity requested.
- * discard any range requests which are invalid,
- * ie start after the end, or have stop before start.
- * rewrite suffix requests
- */
-HRange*
-fixrange(HRange *h, long length)
-{- HRange *r, *rr;
-
- if(length == 0)
- return nil;
-
- /*
- * rewrite each range to reflect the actual length of the file
- * toss out any invalid ranges
- */
- rr = nil;
- for(r = h; r != nil; r = r->next){- if(r->suffix){- /*
- * for suffix, r->stop is a byte *length*
- * not the byte *offset* of last byte!
- */
- r->start = length - r->stop;
- if(r->start >= length)
- r->start = 0;
- r->stop = length - 1;
- r->suffix = 0;
- }
- if(r->stop >= length)
- r->stop = length - 1;
- if(r->start > r->stop){- if(rr == nil)
- h = r->next;
- else
- rr->next = r->next;
- }else
- rr = r;
- }
-
- /*
- * merge consecutive overlapping or abutting ranges
- *
- * not clear from rfc2616 how much merging needs to be done.
- * this code merges only if a range is adjacent to a later starting,
- * over overlapping or abutting range. this allows a client
- * to request wanted data first, followed by other data.
- * this may be useful then fetching part of a page, then the adjacent regions.
- */
- if(h == nil)
- return h;
- r = h;
- for(;;){- rr = r->next;
- if(rr == nil)
- break;
- if(r->start <= rr->start && r->stop + 1 >= rr->start){- if(r->stop < rr->stop)
- r->stop = rr->stop;
- r->next = rr->next;
- }else
- r = rr;
- }
- return h;
-}
--- a/sys/src/cmd/ip/httpd/webls.c
+++ /dev/null
@@ -1,335 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <bio.h>
-#include <regexp.h>
-#include <fcall.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-static Hio *hout;
-static Hio houtb;
-static HConnect *connect;
-static int vermaj, gidwidth, uidwidth, lenwidth, devwidth;
-static Biobuf *aio, *dio;
-
-static void
-doctype(void)
-{- hprint(hout, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n");
- hprint(hout, " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
-}
-
-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);
-}
-
-/*
- * Are we actually allowed to look in here?
- *
- * Rules:
- * 1) If neither allowed nor denied files exist, access is granted.
- * 2) If allowed exists and denied does not, dir *must* be in allowed
- * for access to be granted, otherwise, access is denied.
- * 3) If denied exists and allowed does not, dir *must not* be in
- * denied for access to be granted, otherwise, access is enied.
- * 4) If both exist, okay if either (a) file is not in denied, or
- * (b) in denied and in allowed. Otherwise, access is denied.
- */
-static Reprog *
-getre(Biobuf *buf)
-{- Reprog *re;
- char *p, *t;
- char *bbuf;
- int n;
-
- if (buf == nil)
- return(nil);
- for ( ; ; free(p)) {- p = Brdstr(buf, '\n', 0);
- if (p == nil)
- return(nil);
- t = strchr(p, '#');
- if (t != nil)
- *t = '\0';
- t = p + strlen(p);
- while (--t > p && isspace(*t))
- *t = '\0';
- n = strlen(p);
- if (n == 0)
- continue;
-
- /* root the regular expresssion */
- bbuf = malloc(n+2);
- if(bbuf == nil)
- sysfatal("out of memory");- bbuf[0] = '^';
- strcpy(bbuf+1, p);
- re = regcomp(bbuf);
- free(bbuf);
-
- if (re == nil)
- continue;
- free(p);
- return(re);
- }
-}
-
-static int
-allowed(char *dir)
-{- Reprog *re;
- int okay;
- Resub match;
-
- if (strcmp(dir, "..") == 0 || strncmp(dir, "../", 3) == 0)
- return(0);
- if (aio == nil)
- return(0);
-
- if (aio != nil)
- Bseek(aio, 0, 0);
- if (dio != nil)
- Bseek(dio, 0, 0);
-
- /* if no deny list, assume everything is denied */
- okay = (dio != nil);
-
- /* go through denials till we find a match */
- while (okay && (re = getre(dio)) != nil) {- memset(&match, 0, sizeof(match));
- okay = (regexec(re, dir, &match, 1) != 1);
- free(re);
- }
-
- /* go through accepts till we have a match */
- if (aio == nil)
- return(okay);
- while (!okay && (re = getre(aio)) != nil) {- memset(&match, 0, sizeof(match));
- okay = (regexec(re, dir, &match, 1) == 1);
- free(re);
- }
- return(okay);
-}
-
-/*
- * Comparison routine for sorting the directory.
- */
-static int
-compar(Dir *a, Dir *b)
-{- return(strcmp(a->name, b->name));
-}
-
-/*
- * These is for formating; how wide are variable-length
- * fields?
- */
-static void
-maxwidths(Dir *dp, long n)
-{- long i;
- char scratch[64];
-
- for (i = 0; i < n; i++) {- if (snprint(scratch, sizeof scratch, "%ud", dp[i].dev) > devwidth)
- devwidth = strlen(scratch);
- if (strlen(dp[i].uid) > uidwidth)
- uidwidth = strlen(dp[i].uid);
- if (strlen(dp[i].gid) > gidwidth)
- gidwidth = strlen(dp[i].gid);
- if (snprint(scratch, sizeof scratch, "%lld", dp[i].length) > lenwidth)
- lenwidth = strlen(scratch);
- }
-}
-
-/*
- * Do an actual directory listing.
- * asciitime is lifted directly out of ls.
- */
-char *
-asciitime(long l)
-{- ulong clk;
- static char buf[32];
- char *t;
-
- clk = time(nil);
- t = ctime(l);
- /* 6 months in the past or a day in the future */
- if(l<clk-180L*24*60*60 || clk+24L*60*60<l){- memmove(buf, t+4, 7); /* month and day */
- memmove(buf+7, t+23, 5); /* year */
- }else
- memmove(buf, t+4, 12); /* skip day of week */
- buf[12] = 0;
- return buf;
-}
-
-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);
-}
-
-/*
- * Handle unpacking the request in the URI and
- * invoking the actual handler.
- */
-static void
-dosearch(char *search)
-{- if (strncmp(search, "dir=", 4) == 0){- search = hurlunesc(connect, search+4);
- dols(search);
- return;
- }
-
- /*
- * Otherwise, we've gotten an illegal request.
- * spit out a non-apologetic error.
- */
- search = hurlunesc(connect, search);
- error("Bad directory listing request",- "<p>Illegal formatted directory listing request:</p>\n"
- "<p>%H</p>", search);
-}
-
-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(webroot, "/", 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);
-}
--- a/sys/src/cmd/ip/httpd/webls.denied
+++ /dev/null
@@ -1,1 +1,0 @@
-.*
--- a/sys/src/cmd/ip/httpd/wikipost.c
+++ /dev/null
@@ -1,305 +1,0 @@
-/*
- * Accept new wiki pages or modifications to existing ones via POST method.
- *
- * Talks to the server at /srv/wiki.service.
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "httpd.h"
-#include "httpsrv.h"
-
-#define LOG "wiki"
-
-HConnect *hc;
-HSPriv *hp;
-
-
-/* go from possibly-latin1 url with escapes to utf */
-char *
-_urlunesc(char *s)
-{- char *t, *v, *u;
- Rune r;
- int c, n;
-
- /* unescape */
- u = halloc(hc, strlen(s)+1);
- for(t = u; c = *s; s++){- if(c == '%'){- n = s[1];
- if(n >= '0' && n <= '9')
- n = n - '0';
- else if(n >= 'A' && n <= 'F')
- n = n - 'A' + 10;
- else if(n >= 'a' && n <= 'f')
- n = n - 'a' + 10;
- else
- break;
- r = n;
- n = s[2];
- if(n >= '0' && n <= '9')
- n = n - '0';
- else if(n >= 'A' && n <= 'F')
- n = n - 'A' + 10;
- else if(n >= 'a' && n <= 'f')
- n = n - 'a' + 10;
- else
- break;
- s += 2;
- c = r*16+n;
- }
- *t++ = c;
- }
- *t = 0;
-
- /* latin1 heuristic */
- v = halloc(hc, UTFmax*strlen(u) + 1);
- s = u;
- t = v;
- while(*s){- /* in decoding error, assume latin1 */
- if((n=chartorune(&r, s)) == 1 && r == Runeerror)
- r = *s;
- s += n;
- t += runetochar(t, &r);
- }
- *t = 0;
-
- return v;
-}
-
-enum
-{- MaxLog = 100*1024, /* limit on length of any one log request */
-};
-
-static int
-dangerous(char *s)
-{- if(s == nil)
- return 1;
-
- /*
- * This check shouldn't be needed;
- * filename folding is already supposed to have happened.
- * But I'm paranoid.
- */
- while(s = strchr(s,'/')){- if(s[1]=='.' && s[2]=='.')
- return 1;
- s++;
- }
- return 0;
-}
-
-char*
-unhttp(char *s)
-{- char *p, *r, *w;
-
- if(s == nil)
- return nil;
-
- for(p=s; *p; p++)
- if(*p=='+')
- *p = ' ';
- s = _urlunesc(s);
-
- for(r=w=s; *r; r++){- if(*r != '\r')
- *w++ = *r;
- }
- *w = '\0';
- return s;
-}
-
-void
-mountwiki(HConnect *c, char *service)
-{- char buf[128];
- int fd;
-
- /* already in (possibly private) namespace? */
- snprint(buf, sizeof buf, "/mnt/wiki.%s/new", service);
- if (access(buf, AREAD) == 0){- if (bind(buf, "/mnt/wiki", MREPL) < 0){- syslog(0, LOG, "%s bind /mnt/wiki failed: %r",
- hp->remotesys);
- hfail(c, HNotFound);
- exits("bind /mnt/wiki failed");- }
- return;
- }
-
- /* old way: public wikifs from /srv */
- snprint(buf, sizeof buf, "/srv/wiki.%s", service);
- if((fd = open(buf, ORDWR)) < 0){- syslog(0, LOG, "%s open %s failed: %r", buf, hp->remotesys);
- hfail(c, HNotFound);
- exits("failed");- }
- if(mount(fd, -1, "/mnt/wiki", MREPL, "") == -1){- syslog(0, LOG, "%s mount /mnt/wiki failed: %r", hp->remotesys);
- hfail(c, HNotFound);
- exits("failed");- }
- close(fd);
-}
-
-char*
-dowiki(HConnect *c, char *title, char *author, char *comment, char *base, ulong version, char *text)
-{- int fd, l, n, err;
- char *p, tmp[256];
-int i;
-
- if((fd = open("/mnt/wiki/new", ORDWR)) < 0){- syslog(0, LOG, "%s open /mnt/wiki/new failed: %r", hp->remotesys);
- hfail(c, HNotFound);
- exits("failed");- }
-
-i=0;
- if((i++,fprint(fd, "%s\nD%lud\nA%s (%s)\n", title, version, author, hp->remotesys) < 0)
- || (i++,(comment && comment[0] && fprint(fd, "C%s\n", comment) < 0))
- || (i++,fprint(fd, "\n") < 0)
- || (i++,(text[0] && write(fd, text, strlen(text)) != strlen(text)))){- syslog(0, LOG, "%s write failed %d %ld fd %d: %r", hp->remotesys, i, strlen(text), fd);
- hfail(c, HInternal);
- exits("failed");- }
-
- err = write(fd, "", 0);
- if(err)
- syslog(0, LOG, "%s commit failed %d: %r", hp->remotesys, err);
-
- seek(fd, 0, 0);
- if((n = read(fd, tmp, sizeof(tmp)-1)) <= 0){- if(n == 0)
- werrstr("short read");- syslog(0, LOG, "%s read failed: %r", hp->remotesys);
- hfail(c, HInternal);
- exits("failed");- }
-
- tmp[n] = '\0';
-
- p = halloc(c, l=strlen(base)+strlen(tmp)+40);
- snprint(p, l, "%s/%s/%s.html", base, tmp, err ? "werror" : "index");
- return p;
-}
-
-
-void
-main(int argc, char **argv)
-{- Hio *hin, *hout;
- char *s, *t, *p, *f[10];
- char *text, *title, *service, *base, *author, *comment, *url;
- int i, nf;
- ulong version;
-
- hc = init(argc, argv);
- hp = hc->private;
-
- if(dangerous(hc->req.uri)){- hfail(hc, HSyntax);
- exits("failed");- }
-
- if(hparseheaders(hc, HSTIMEOUT) < 0)
- exits("failed");- hout = &hc->hout;
- if(hc->head.expectother){- hfail(hc, HExpectFail, nil);
- exits("failed");- }
- if(hc->head.expectcont){- hprint(hout, "100 Continue\r\n");
- hprint(hout, "\r\n");
- hflush(hout);
- }
-
- s = nil;
- if(strcmp(hc->req.meth, "POST") == 0){- hin = hbodypush(&hc->hin, hc->head.contlen, hc->head.transenc);
- if(hin != nil){- alarm(15*60*1000);
- s = hreadbuf(hin, hin->pos);
- alarm(0);
- }
- if(s == nil){- hfail(hc, HBadReq, nil);
- exits("failed");- }
- t = strchr(s, '\n');
- if(t != nil)
- *t = '\0';
- }else{- hunallowed(hc, "GET, HEAD, PUT");
- exits("unallowed");- }
-
- if(s == nil){- hfail(hc, HNoData, "wiki");
- exits("failed");- }
-
- text = nil;
- title = nil;
- service = nil;
- author = "???";
- comment = "";
- base = nil;
- version = ~0;
- nf = getfields(s, f, nelem(f), 1, "&");
- for(i=0; i<nf; i++){- if((p = strchr(f[i], '=')) == nil)
- continue;
- *p++ = '\0';
- if(strcmp(f[i], "title")==0)
- title = p;
- else if(strcmp(f[i], "version")==0)
- version = strtoul(unhttp(p), 0, 10);
- else if(strcmp(f[i], "text")==0)
- text = p;
- else if(strcmp(f[i], "service")==0)
- service = p;
- else if(strcmp(f[i], "comment")==0)
- comment = p;
- else if(strcmp(f[i], "author")==0)
- author = p;
- else if(strcmp(f[i], "base")==0)
- base = p;
- }
-
- syslog(0, LOG, "%s post s %s t '%s' v %ld a %s c %s b %s t 0x%p",
- hp->remotesys, service, title, (long)version, author, comment, base, text);
-
- title = unhttp(title);
- comment = unhttp(comment);
- service = unhttp(service);
- text = unhttp(text);
- author = unhttp(author);
- base = unhttp(base);
-
- if(title==nil || version==~0 || text==nil || text[0]=='\0' || base == nil
- || service == nil || strchr(title, '\n') || strchr(comment, '\n')
- || dangerous(service) || strchr(service, '/') || strlen(service)>20){- syslog(0, LOG, "%s failed dangerous", hp->remotesys);
- hfail(hc, HSyntax);
- exits("failed");- }
-
- syslog(0, LOG, "%s post s %s t '%s' v %ld a %s c %s",
- hp->remotesys, service, title, (long)version, author, comment);
-
- if(strlen(text) > MaxLog)
- text[MaxLog] = '\0';
-
- mountwiki(hc, service);
- url = dowiki(hc, title, author, comment, base, version, text);
- hredirected(hc, "303 See Other", url);
- exits(nil);
-}
--- a/sys/src/libhttpd/alloc.c
+++ /dev/null
@@ -1,35 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-/*
- * memory allocators:
- * h routines call canalloc; they should be used by everything else
- * note this memory is wiped out at the start of each new request
- * note: these routines probably shouldn't fatal.
- */
-char*
-hstrdup(HConnect *c, char *s)
-{- char *t;
- int n;
-
- n = strlen(s) + 1;
- t = binalloc(&c->bin, n, 0);
- if(t == nil)
- sysfatal("out of memory");- memmove(t, s, n);
- return t;
-}
-
-void*
-halloc(HConnect *c, ulong n)
-{- void *p;
-
- p = binalloc(&c->bin, n, 1);
- if(p == nil)
- sysfatal("out of memory");- return p;
-}
--- a/sys/src/libhttpd/checkcontent.c
+++ /dev/null
@@ -1,33 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-int
-hcheckcontent(HContent *me, HContent *oks, char *list, int size)
-{- HContent *ok;
-
- if(oks == nil || me == nil)
- return 1;
- for(ok = oks; ok != nil; ok = ok->next){- if((cistrcmp(ok->generic, me->generic) == 0 || strcmp(ok->generic, "*") == 0)
- && (me->specific == nil || cistrcmp(ok->specific, me->specific) == 0 || strcmp(ok->specific, "*") == 0)){- if(ok->mxb > 0 && size > ok->mxb)
- return 0;
- return 1;
- }
- }
-
- USED(list);
- if(0){- fprint(2, "list: %s/%s not found\n", me->generic, me->specific);
- for(; oks != nil; oks = oks->next){- if(oks->specific)
- fprint(2, "\t%s/%s\n", oks->generic, oks->specific);
- else
- fprint(2, "\t%s\n", oks->generic);
- }
- }
- return 0;
-}
--- a/sys/src/libhttpd/date.c
+++ /dev/null
@@ -1,215 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <httpd.h>
-
-/*
- * print dates in the format
- * Wkd, DD Mon YYYY HH:MM:SS GMT
- * parse dates of formats
- * Wkd, DD Mon YYYY HH:MM:SS GMT
- * Weekday, DD-Mon-YY HH:MM:SS GMT
- * Wkd Mon ( D|DD) HH:MM:SS YYYY
- * plus anything similar
- */
-static char *
-weekdayname[7] =
-{- "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
-};
-static char *
-wdayname[7] =
-{- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-static char *
-monname[12] =
-{- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-static int dateindex(char*, char**, int);
-
-static int
-dtolower(int c)
-{- if(c >= 'A' && c <= 'Z')
- return c - 'A' + 'a';
- return c;
-}
-
-static int
-disalpha(int c)
-{- return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
-}
-
-static int
-disdig(int c)
-{- return c >= '0' && c <= '9';
-}
-
-int
-hdatefmt(Fmt *f)
-{- Tm *tm;
- ulong t;
-
- t = va_arg(f->args, ulong);
- tm = gmtime(t);
- return fmtprint(f, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
- wdayname[tm->wday], tm->mday, monname[tm->mon], tm->year+1900,
- tm->hour, tm->min, tm->sec);
-}
-
-static char*
-dateword(char *date, char *buf)
-{- char *p;
- int c;
-
- p = buf;
- while(!disalpha(c = *date) && !disdig(c) && c)
- date++;
- while(disalpha(c = *date)){- if(p - buf < 30)
- *p++ = dtolower(c);
- date++;
- }
- *p = 0;
- return date;
-}
-
-static int
-datenum(char **d)
-{- char *date;
- int c, n;
-
- date = *d;
- while(!disdig(c = *date) && c)
- date++;
- if(c == 0){- *d = date;
- return -1;
- }
- n = 0;
- while(disdig(c = *date)){- n = n * 10 + c - '0';
- date++;
- }
- *d = date;
- return n;
-}
-
-/*
- * parse a date and return the seconds since the epoch
- * return 0 for a failure
- */
-ulong
-hdate2sec(char *date)
-{- Tm tm;
- char buf[32];
-
- memset(&tm, 0, sizeof(tm));
-
- /*
- * Weekday|Wday
- */
- date = dateword(date, buf);
- tm.wday = dateindex(buf, wdayname, 7);
- if(tm.wday < 0)
- tm.wday = dateindex(buf, weekdayname, 7);
- if(tm.wday < 0)
- return 0;
-
- /*
- * check for the two major formats
- */
- date = dateword(date, buf);
- tm.mon = dateindex(buf, monname, 12);
- if(tm.mon >= 0){- /*
- * MM
- */
- tm.mday = datenum(&date);
- if(tm.mday < 1 || tm.mday > 31)
- return 0;
-
- /*
- * HH:MM:SS
- */
- tm.hour = datenum(&date);
- if(tm.hour < 0 || tm.hour >= 24)
- return 0;
- tm.min = datenum(&date);
- if(tm.min < 0 || tm.min >= 60)
- return 0;
- tm.sec = datenum(&date);
- if(tm.sec < 0 || tm.sec >= 60)
- return 0;
-
- /*
- * YYYY
- */
- tm.year = datenum(&date);
- if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
- return 0;
- if(tm.year >= 1970)
- tm.year -= 1900;
- }else{- /*
- * MM-Mon-(YY|YYYY)
- */
- tm.mday = datenum(&date);
- if(tm.mday < 1 || tm.mday > 31)
- return 0;
- date = dateword(date, buf);
- tm.mon = dateindex(buf, monname, 12);
- if(tm.mon < 0 || tm.mon >= 12)
- return 0;
- tm.year = datenum(&date);
- if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
- return 0;
- if(tm.year >= 1970)
- tm.year -= 1900;
-
- /*
- * HH:MM:SS
- */
- tm.hour = datenum(&date);
- if(tm.hour < 0 || tm.hour >= 24)
- return 0;
- tm.min = datenum(&date);
- if(tm.min < 0 || tm.min >= 60)
- return 0;
- tm.sec = datenum(&date);
- if(tm.sec < 0 || tm.sec >= 60)
- return 0;
-
- /*
- * timezone
- */
- dateword(date, buf);
- if(strncmp(buf, "gmt", 3) != 0)
- return 0;
- }
-
- strcpy(tm.zone, "GMT");
- tm.tzoff = 0;
- tm.yday = 0;
- return tm2sec(&tm);
-}
-
-static int
-dateindex(char *d, char **tab, int n)
-{- int i;
-
- for(i = 0; i < n; i++)
- if(cistrcmp(d, tab[i]) == 0)
- return i;
- return -1;
-}
--- a/sys/src/libhttpd/escape.h
+++ /dev/null
@@ -1,124 +1,0 @@
-
-Htmlesc htmlesc[] =
-{- { "¡", L'¡', },- { "¢", L'¢', },- { "£", L'£', },- { "¤", L'¤', },- { "¥", L'¥', },- { "¦", L'¦', },- { "§", L'§', },- { "¨", L'¨', },- { "©", L'©', },- { "ª", L'ª', },- { "«", L'«', },- { "¬", L'¬', },- { "­", L'', },- { "®", L'®', },- { "¯", L'¯', },- { "°", L'°', },- { "±", L'±', },- { "²", L'²', },- { "³", L'³', },- { "´", L'´', },- { "µ", L'µ', },- { "¶", L'¶', },- { "·", L'·', },- { "¸", L'¸', },- { "¹", L'¹', },- { "º", L'º', },- { "»", L'»', },- { "¼", L'¼', },- { "½", L'½', },- { "¾", L'¾', },- { "¿", L'¿', },- { "À", L'À', },- { "Á", L'Á', },- { "Â", L'Â', },- { "Ã", L'Ã', },- { "Ä", L'Ä', },- { "Å", L'Å', },- { "Æ", L'Æ', },- { "Ç", L'Ç', },- { "È", L'È', },- { "É", L'É', },- { "Ê", L'Ê', },- { "Ë", L'Ë', },- { "Ì", L'Ì', },- { "Í", L'Í', },- { "Î", L'Î', },- { "Ï", L'Ï', },- { "Ð", L'Ð', },- { "Ñ", L'Ñ', },- { "Ò", L'Ò', },- { "Ó", L'Ó', },- { "Ô", L'Ô', },- { "Õ", L'Õ', },- { "Ö", L'Ö', },- { "&215;", L'×', },- { "Ø", L'Ø', },- { "Ù", L'Ù', },- { "Ú", L'Ú', },- { "Û", L'Û', },- { "Ü", L'Ü', },- { "Ý", L'Ý', },- { "Þ", L'Þ', },- { "ß", L'ß', },- { "à", L'à', },- { "á", L'á', },- { "â", L'â', },- { "ã", L'ã', },- { "ä", L'ä', },- { "å", L'å', },- { "æ", L'æ', },- { "ç", L'ç', },- { "è", L'è', },- { "é", L'é', },- { "ê", L'ê', },- { "ë", L'ë', },- { "ì", L'ì', },- { "í", L'í', },- { "î", L'î', },- { "ï", L'ï', },- { "ð", L'ð', },- { "ñ", L'ñ', },- { "ò", L'ò', },- { "ó", L'ó', },- { "ô", L'ô', },- { "õ", L'õ', },- { "ö", L'ö', },- { "&247;", L'÷', },- { "ø", L'ø', },- { "ù", L'ù', },- { "ú", L'ú', },- { "û", L'û', },- { "ü", L'ü', },- { "ý", L'ý', },- { "þ", L'þ', },- { "ÿ", L'ÿ', },-
- { """, L'"', },- { "'", L'\'', }, /* Note ' is valid XML but not valid HTML */- { "&", L'&', },- { "<", L'<', },- { ">", L'>', },-
- { "CAP-DELTA", L'Δ', },- { "ALPHA", L'α', },- { "BETA", L'β', },- { "DELTA", L'δ', },- { "EPSILON", L'ε', },- { "THETA", L'θ', },- { "MU", L'μ', },- { "PI", L'π', },- { "TAU", L'τ', },- { "CHI", L'χ', },-
- { "<-", L'←', },- { "^", L'↑', },- { "->", L'→', },- { "v", L'↓', },- { "!=", L'≠', },- { "<=", L'≤', },- { nil, 0 },-};
--- a/sys/src/libhttpd/fail.c
+++ /dev/null
@@ -1,93 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-typedef struct Error Error;
-
-struct Error
-{- char *num;
- char *concise;
- char *verbose;
-};
-
-Error errormsg[] =
-{- [HInternal] {"500 Internal Error", "Internal Error",- "This server could not process your request due to an internal error."},
- [HTempFail] {"500 Internal Error", "Temporary Failure",- "The object %s is currently inaccessible.<p>Please try again later."},
- [HUnimp] {"501 Not implemented", "Command not implemented",- "This server does not implement the %s command."},
- [HUnkVers] {"501 Not Implemented", "Unknown http version",- "This server does not know how to respond to http version %s."},
- [HBadCont] {"501 Not Implemented", "Impossible format",- "This server cannot produce %s in any of the formats your client accepts."},
- [HBadReq] {"400 Bad Request", "Strange Request",- "Your client sent a query that this server could not understand."},
- [HSyntax] {"400 Bad Request", "Garbled Syntax",- "Your client sent a query with incoherent syntax."},
- [HBadSearch] {"400 Bad Request", "Inapplicable Search",- "Your client sent a search that cannot be applied to %s."},
- [HNotFound] {"404 Not Found", "Object not found",- "The object %s does not exist on this server."},
- [HNoSearch] {"403 Forbidden", "Search not supported",- "The object %s does not support the search command."},
- [HNoData] {"403 Forbidden", "No data supplied",- "Search or forms data must be supplied to %s."},
- [HExpectFail] {"403 Expectation Failed", "Expectation Failed",- "This server does not support some of your request's expectations."},
- [HUnauth] {"403 Forbidden", "Forbidden",- "You are not allowed to see the object %s."},
- [HOK] {"200 OK", "everything is fine"},-};
-
-/*
- * write a failure message to the net and exit
- */
-int
-hfail(HConnect *c, int reason, ...)
-{- Hio *hout;
- char makeup[HBufSize], err[ERRMAX];
- va_list arg;
- int n;
-
- rerrstr(err, sizeof err);
- hout = &c->hout;
- va_start(arg, reason);
- vseprint(makeup, makeup+HBufSize, errormsg[reason].verbose, arg);
- va_end(arg);
- /*
- * this additional information has proved useful when debugging
- * complex http configuration problems.
- */
- n = snprint(c->xferbuf, HBufSize, "<head><title>%s</title></head>\n"
- "<body><h1>%s</h1>\n%s<p>\n"
- "errstr: %s<br>\n"
- "uri host: %s<br>\n"
- "header host: %s<br>\nactual host: %s\n</body>\n",
- errormsg[reason].concise, errormsg[reason].concise, makeup,
- err,
- (c->req.urihost? c->req.urihost: ""),
- c->head.host, hmydomain);
-
- hprint(hout, "%s %s\r\n", hversion, errormsg[reason].num);
- hprint(hout, "Date: %D\r\n", time(nil));
- hprint(hout, "Server: Plan9\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);
-
- if(c->replog)
- c->replog(c, "Reply: %s\nReason: %s\n", errormsg[reason].num, errormsg[reason].concise);
- return hflush(hout);
-}
--- a/sys/src/libhttpd/gethead.c
+++ /dev/null
@@ -1,40 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-/*
- * read in some header lines, either one or all of them.
- * copy results into header log buffer.
- */
-int
-hgethead(HConnect *c, int many)
-{- Hio *hin;
- char *s, *p, *pp;
- int n;
-
- hin = &c->hin;
- for(;;){- s = (char*)hin->pos;
- pp = s;
- while(p = memchr(pp, '\n', (char*)hin->stop - pp)){- if(!many || p == pp || (p == pp + 1 && *pp == '\r')){- pp = p + 1;
- break;
- }
- pp = p + 1;
- }
- hin->pos = (uchar*)pp;
- n = pp - s;
- if(c->hstop + n > &c->header[HBufSize])
- return -1;
- memmove(c->hstop, s, n);
- c->hstop += n;
- *c->hstop = '\0';
- if(p != nil)
- return 0;
- if(hreadbuf(hin, hin->pos) == nil || hin->state == Hend)
- return -1;
- }
-}
--- a/sys/src/libhttpd/hio.c
+++ /dev/null
@@ -1,488 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <httpd.h>
-
-static char hstates[] = "nrewE";
-static char hxfers[] = " x";
-static int _hflush(Hio*, int, int);
-
-int
-hinit(Hio *h, int fd, int mode)
-{- if(fd == -1 || mode != Hread && mode != Hwrite)
- return -1;
- h->hh = nil;
- h->fd = fd;
- h->seek = 0;
- h->state = mode;
- h->start = h->buf + 16; /* leave space for chunk length */
- h->stop = h->pos = h->start;
- if(mode == Hread){- h->bodylen = ~0UL;
- *h->pos = '\0';
- }else
- h->stop = h->start + Hsize;
- return 0;
-}
-
-int
-hiserror(Hio *h)
-{- return h->state == Herr;
-}
-
-int
-hgetc(Hio *h)
-{- uchar *p;
-
- p = h->pos;
- if(p < h->stop){- h->pos = p + 1;
- return *p;
- }
- p -= UTFmax;
- if(p < h->start)
- p = h->start;
- if(!hreadbuf(h, p) || h->pos == h->stop)
- return -1;
- return *h->pos++;
-}
-
-int
-hungetc(Hio *h)
-{- if(h->state == Hend)
- h->state = Hread;
- else if(h->state == Hread)
- h->pos--;
- if(h->pos < h->start || h->state != Hread){- h->state = Herr;
- h->pos = h->stop;
- return -1;
- }
- return 0;
-}
-
-/*
- * fill the buffer, saving contents from vsave onwards.
- * nothing is saved if vsave is nil.
- * returns the beginning of the buffer.
- *
- * understands message body sizes and chunked transfer encoding
- */
-void *
-hreadbuf(Hio *h, void *vsave)
-{- Hio *hh;
- uchar *save;
- int c, in, cpy, dpos;
-
- save = vsave;
- if(save && (save < h->start || save > h->stop)
- || h->state != Hread && h->state != Hend){- h->state = Herr;
- h->pos = h->stop;
- return nil;
- }
-
- dpos = 0;
- if(save && h->pos > save)
- dpos = h->pos - save;
- cpy = 0;
- if(save){- cpy = h->stop - save;
- memmove(h->start, save, cpy);
- }
- h->seek += h->stop - h->start - cpy;
- h->pos = h->start + dpos;
-
- in = Hsize - cpy;
- if(h->state == Hend)
- in = 0;
- else if(in > h->bodylen)
- in = h->bodylen;
-
- /*
- * for chunked encoding, fill buffer,
- * then read in new chunk length and wipe out that line
- */
- hh = h->hh;
- if(hh != nil){- if(!in && h->xferenc && h->state != Hend){- if(h->xferenc == 2){- c = hgetc(hh);
- if(c == '\r')
- c = hgetc(hh);
- if(c != '\n'){- h->pos = h->stop;
- h->state = Herr;
- return nil;
- }
- }
- h->xferenc = 2;
- in = 0;
- while((c = hgetc(hh)) != '\n'){- if(c >= '0' && c <= '9')
- c -= '0';
- else if(c >= 'a' && c <= 'f')
- c -= 'a' - 10;
- else if(c >= 'A' && c <= 'F')
- c -= 'A' - 10;
- else
- break;
- in = in * 16 + c;
- }
- while(c != '\n'){- if(c < 0){- h->pos = h->stop;
- h->state = Herr;
- return nil;
- }
- c = hgetc(hh);
- }
- h->bodylen = in;
-
- in = Hsize - cpy;
- if(in > h->bodylen)
- in = h->bodylen;
- }
- if(in){- while(hh->pos + in > hh->stop){- if(hreadbuf(hh, hh->pos) == nil){- h->pos = h->stop;
- h->state = Herr;
- return nil;
- }
- }
- memmove(h->start + cpy, hh->pos, in);
- hh->pos += in;
- }
- }else if(in){- if((in = read(h->fd, h->start + cpy, in)) < 0){- h->state = Herr;
- h->pos = h->stop;
- return nil;
- }
- }
- if(in == 0)
- h->state = Hend;
-
- h->bodylen -= in;
-
- h->stop = h->start + cpy + in;
- *h->stop = '\0';
- if(h->pos == h->stop)
- return nil;
- return h->start;
-}
-
-int
-hbuflen(Hio *h, void *p)
-{- return h->stop - (uchar*)p;
-}
-
-/*
- * prepare to receive a message body
- * len is the content length (~0 => unspecified)
- * te is the transfer encoding
- * returns < 0 if setup failed
- */
-Hio*
-hbodypush(Hio *hh, ulong len, HFields *te)
-{- Hio *h;
- int xe;
-
- if(hh->state != Hread)
- return nil;
- xe = 0;
- if(te != nil){- if(te->params != nil || te->next != nil)
- return nil;
- if(cistrcmp(te->s, "chunked") == 0){- xe = 1;
- len = 0;
- }else if(cistrcmp(te->s, "identity") == 0){- ;
- }else
- return nil;
- }
-
- h = malloc(sizeof *h);
- if(h == nil)
- return nil;
-
- h->hh = hh;
- h->fd = -1;
- h->seek = 0;
- h->state = Hread;
- h->xferenc = xe;
- h->start = h->buf + 16; /* leave space for chunk length */
- h->stop = h->pos = h->start;
- *h->pos = '\0';
- h->bodylen = len;
- return h;
-}
-
-/*
- * dump the state of the io buffer into a string
- */
-char *
-hunload(Hio *h)
-{- uchar *p, *t, *stop, *buf;
- int ne, n, c;
-
- stop = h->stop;
- ne = 0;
- for(p = h->pos; p < stop; p++){- c = *p;
- if(c == 0x80)
- ne++;
- }
- p = h->pos;
-
- n = (stop - p) + ne + 3;
- buf = mallocz(n, 1);
- if(buf == nil)
- return nil;
- buf[0] = hstates[h->state];
- buf[1] = hxfers[h->xferenc];
-
- t = &buf[2];
- for(; p < stop; p++){- c = *p;
- if(c == 0 || c == 0x80){- *t++ = 0x80;
- if(c == 0x80)
- *t++ = 0x80;
- }else
- *t++ = c;
- }
- *t++ = '\0';
- if(t != buf + n)
- return nil;
- return (char*)buf;
-}
-
-/*
- * read the io buffer state from a string
- */
-int
-hload(Hio *h, char *buf)
-{- uchar *p, *t, *stop;
- char *s;
- int c;
-
- s = strchr(hstates, buf[0]);
- if(s == nil)
- return -1;
- h->state = s - hstates;
-
- s = strchr(hxfers, buf[1]);
- if(s == nil)
- return -1;
- h->xferenc = s - hxfers;
-
- t = h->start;
- stop = t + Hsize;
- for(p = (uchar*)&buf[2]; c = *p; p++){- if(c == 0x80){- if(p[1] != 0x80)
- c = 0;
- else
- p++;
- }
- *t++ = c;
- if(t >= stop)
- return -1;
- }
- *t = '\0';
- h->pos = h->start;
- h->stop = t;
- h->seek = 0;
- return 0;
-}
-
-void
-hclose(Hio *h)
-{- if(h->fd >= 0){- if(h->state == Hwrite)
- hxferenc(h, 0);
- close(h->fd);
- }
- h->stop = h->pos = nil;
- h->fd = -1;
-}
-
-/*
- * flush the buffer and possibly change encoding modes
- */
-int
-hxferenc(Hio *h, int on)
-{- if(h->xferenc && !on && h->pos != h->start)
- hflush(h);
- if(_hflush(h, 1, 0) < 0)
- return -1;
- h->xferenc = !!on;
- return 0;
-}
-
-int
-hputc(Hio *h, int c)
-{- uchar *p;
-
- p = h->pos;
- if(p < h->stop){- h->pos = p + 1;
- return *p = c;
- }
- if(hflush(h) < 0)
- return -1;
- return *h->pos++ = c;
-}
-
-static int
-fmthflush(Fmt *f)
-{- Hio *h;
-
- h = f->farg;
- h->pos = f->to;
- if(hflush(h) < 0)
- return 0;
- f->stop = h->stop;
- f->to = h->pos;
- f->start = h->pos;
- return 1;
-}
-
-int
-hvprint(Hio *h, char *fmt, va_list args)
-{- int n;
- Fmt f;
-
- f.runes = 0;
- f.stop = h->stop;
- f.to = h->pos;
- f.start = h->pos;
- f.flush = fmthflush;
- f.farg = h;
- f.nfmt = 0;
-// fmtlocaleinit(&f, nil, nil, nil);
- n = fmtvprint(&f, fmt, args);
- h->pos = f.to;
- return n;
-}
-
-int
-hprint(Hio *h, char *fmt, ...)
-{- int n;
- va_list arg;
-
- va_start(arg, fmt);
- n = hvprint(h, fmt, arg);
- va_end(arg);
- return n;
-}
-
-static int
-_hflush(Hio *h, int force, int dolength)
-{- uchar *s;
- int w;
-
- if(h == nil)
- return -1;
- if(h->state != Hwrite){- h->state = Herr;
- h->stop = h->pos;
- return -1;
- }
- s = h->start;
- w = h->pos - s;
- if(w == 0 && !force)
- return 0;
- if(h->xferenc){- *--s = '\n';
- *--s = '\r';
- do{- *--s = "0123456789abcdef"[w & 0xf];
- w >>= 4;
- }while(w);
- h->pos[0] = '\r';
- h->pos[1] = '\n';
- w = &h->pos[2] - s;
- }
- if(dolength)
- fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
- if(write(h->fd, s, w) != w){- h->state = Herr;
- h->stop = h->pos;
- return -1;
- }
- h->seek += w;
- h->pos = h->start;
- return 0;
-}
-
-int
-hflush(Hio *h)
-{- return _hflush(h, 0, 0);
-}
-
-int
-hlflush(Hio* h)
-{- return _hflush(h, 0, 1);
-}
-
-int
-hwrite(Hio *h, void *vbuf, int len)
-{- uchar *buf;
- int n, m;
-
- buf = vbuf;
- n = len;
- if(n < 0 || h->state != Hwrite){- h->state = Herr;
- h->stop = h->pos;
- return -1;
- }
- if(h->pos + n >= h->stop){- if(h->start != h->pos)
- if(hflush(h) < 0)
- return -1;
- while(h->pos + n >= h->stop){- m = h->stop - h->pos;
- if(h->xferenc){- memmove(h->pos, buf, m);
- h->pos += m;
- if(hflush(h) < 0)
- return -1;
- }else{- if(write(h->fd, buf, m) != m){- h->state = Herr;
- h->stop = h->pos;
- return -1;
- }
- h->seek += m;
- }
- n -= m;
- buf += m;
- }
- }
- memmove(h->pos, buf, n);
- h->pos += n;
- return len;
-}
--- a/sys/src/libhttpd/httpfmt.c
+++ /dev/null
@@ -1,30 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-int
-httpfmt(Fmt *f)
-{- char buf[HMaxWord*2];
- Rune r;
- char *t, *s;
- Htmlesc *l;
-
- s = va_arg(f->args, char*);
- for(t = buf; t < buf + sizeof(buf) - 8; ){- s += chartorune(&r, s);
- if(r == 0)
- break;
- for(l = htmlesc; l->name != nil; l++)
- if(l->value == r)
- break;
- if(l->name != nil){- strcpy(t, l->name);
- t += strlen(t);
- }else
- *t++ = r;
- }
- *t = 0;
- return fmtstrcpy(f, buf);
-}
--- a/sys/src/libhttpd/httpunesc.c
+++ /dev/null
@@ -1,49 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-/*
- * go from http with latin1 escapes to utf,
- * we assume that anything >= Runeself is already in utf
- */
-char *
-httpunesc(HConnect *cc, char *s)
-{- char *t, *v;
- int c;
- Htmlesc *e;
-
- v = halloc(cc, UTFmax*strlen(s) + 1);
- for(t = v; c = *s;){- if(c == '&'){- if(s[1] == '#' && s[2] && s[3] && s[4] && s[5] == ';'){- c = strtol(s+2, 0, 10);
- if(c < Runeself){- *t++ = c;
- s += 6;
- continue;
- }
- if(c < 256 && c >= 161){- e = &htmlesc[c-161];
- t += runetochar(t, &e->value);
- s += 6;
- continue;
- }
- } else {- for(e = htmlesc; e->name != nil; e++)
- if(strncmp(e->name, s, strlen(e->name)) == 0)
- break;
- if(e->name != nil){- t += runetochar(t, &e->value);
- s += strlen(e->name);
- continue;
- }
- }
- }
- *t++ = c;
- s++;
- }
- *t = 0;
- return v;
-}
--- a/sys/src/libhttpd/lower.c
+++ /dev/null
@@ -1,19 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-char*
-hlower(char *p)
-{- char c;
- char *x;
-
- if(p == nil)
- return p;
-
- for(x = p; c = *x; x++)
- if(c >= 'A' && c <= 'Z')
- *x -= 'A' - 'a';
- return p;
-}
--- a/sys/src/libhttpd/mkfile
+++ /dev/null
@@ -1,27 +1,0 @@
-</$objtype/mkfile
-
-LIB=/$objtype/lib/libhttpd.a
-OFILES=\
- alloc.$O\
- checkcontent.$O\
- date.$O\
- fail.$O\
- gethead.$O\
- hio.$O\
- httpfmt.$O\
- httpunesc.$O\
- lower.$O\
- okheaders.$O\
- parse.$O\
- parsereq.$O\
- query.$O\
- redirected.$O\
- unallowed.$O\
- urlfmt.$O\
- urlunesc.$O\
-
-HFILES=\
- /sys/include/httpd.h\
- escape.h\
-
-</sys/src/cmd/mksyslib
--- a/sys/src/libhttpd/okheaders.c
+++ /dev/null
@@ -1,22 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-/*
- * write initial part of successful header
- */
-void
-hokheaders(HConnect *c)
-{- Hio *hout;
-
- hout = &c->hout;
- hprint(hout, "%s 200 OK\r\n", hversion);
- hprint(hout, "Server: Plan9\r\n");
- hprint(hout, "Date: %D\r\n", time(nil));
- if(c->head.closeit)
- hprint(hout, "Connection: close\r\n");
- else if(!http11(c))
- hprint(hout, "Connection: Keep-Alive\r\n");
-}
--- a/sys/src/libhttpd/parse.c
+++ /dev/null
@@ -1,1126 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <libsec.h>
-#include <bin.h>
-#include <httpd.h>
-#include "escape.h"
-
-typedef struct Hlex Hlex;
-typedef struct MimeHead MimeHead;
-
-enum
-{- /*
- * tokens
- */
- Word = 1,
- QString,
-};
-
-#define UlongMax 4294967295UL
-
-struct Hlex
-{- int tok;
- int eoh;
- int eol; /* end of header line encountered? */
- uchar *hstart; /* start of header */
- jmp_buf jmp; /* jmp here to parse header */
- char wordval[HMaxWord];
- HConnect *c;
-};
-
-struct MimeHead
-{- char *name;
- void (*parse)(Hlex*, char*);
- uchar seen;
- uchar ignore;
-};
-
-static void mimeaccept(Hlex*, char*);
-static void mimeacceptchar(Hlex*, char*);
-static void mimeacceptenc(Hlex*, char*);
-static void mimeacceptlang(Hlex*, char*);
-static void mimeagent(Hlex*, char*);
-static void mimeauthorization(Hlex*, char*);
-static void mimeconnection(Hlex*, char*);
-static void mimecontlen(Hlex*, char*);
-static void mimecookie(Hlex*, char*);
-static void mimeexpect(Hlex*, char*);
-static void mimefresh(Hlex*, char*);
-static void mimefrom(Hlex*, char*);
-static void mimehost(Hlex*, char*);
-static void mimeifrange(Hlex*, char*);
-static void mimeignore(Hlex*, char*);
-static void mimematch(Hlex*, char*);
-static void mimemodified(Hlex*, char*);
-static void mimenomatch(Hlex*, char*);
-static void mimerange(Hlex*, char*);
-static void mimetransenc(Hlex*, char*);
-static void mimeunmodified(Hlex*, char*);
-
-/*
- * headers seen also include
- * allow cache-control chargeto
- * content-encoding content-language content-location content-md5 content-range content-type
- * date etag expires forwarded last-modified max-forwards pragma
- * proxy-agent proxy-authorization proxy-connection
- * ua-color ua-cpu ua-os ua-pixels
- * upgrade via x-afs-tokens x-serial-number
- */
-static MimeHead mimehead[] =
-{- {"accept", mimeaccept},- {"accept-charset", mimeacceptchar},- {"accept-encoding", mimeacceptenc},- {"accept-language", mimeacceptlang},- {"authorization", mimeauthorization},- {"connection", mimeconnection},- {"content-length", mimecontlen},- {"cookie", mimecookie},- {"expect", mimeexpect},- {"fresh", mimefresh},- {"from", mimefrom},- {"host", mimehost},- {"if-match", mimematch},- {"if-modified-since", mimemodified},- {"if-none-match", mimenomatch},- {"if-range", mimeifrange},- {"if-unmodified-since", mimeunmodified},- {"range", mimerange},- {"transfer-encoding", mimetransenc},- {"user-agent", mimeagent},-};
-
-char* hmydomain;
-char* hversion = "HTTP/1.1";
-
-static void lexhead(Hlex*);
-static void parsejump(Hlex*, char*);
-static int getc(Hlex*);
-static void ungetc(Hlex*);
-static int wordcr(Hlex*);
-static int wordnl(Hlex*);
-static void word(Hlex*, char*);
-static int lex1(Hlex*, int);
-static int lex(Hlex*);
-static int lexbase64(Hlex*);
-static ulong digtoul(char *s, char **e);
-
-/*
- * flush and clean up junk from a request
- */
-void
-hreqcleanup(HConnect *c)
-{- int i;
-
- hxferenc(&c->hout, 0);
- memset(&c->req, 0, sizeof(c->req));
- memset(&c->head, 0, sizeof(c->head));
- c->hpos = c->header;
- c->hstop = c->header;
- binfree(&c->bin);
- for(i = 0; i < nelem(mimehead); i++){- mimehead[i].seen = 0;
- mimehead[i].ignore = 0;
- }
-}
-
-/*
- * list of tokens
- * if the client is HTTP/1.0,
- * ignore headers which match one of the tokens.
- * restarts parsing if necessary.
- */
-static void
-mimeconnection(Hlex *h, char *)
-{- char *u, *p;
- int reparse, i;
-
- reparse = 0;
- for(;;){- while(lex(h) != Word)
- if(h->tok != ',')
- goto breakout;
-
- if(cistrcmp(h->wordval, "keep-alive") == 0)
- h->c->head.persist = 1;
- else if(cistrcmp(h->wordval, "close") == 0)
- h->c->head.closeit = 1;
- else if(!http11(h->c)){- for(i = 0; i < nelem(mimehead); i++){- if(cistrcmp(mimehead[i].name, h->wordval) == 0){- reparse = mimehead[i].seen && !mimehead[i].ignore;
- mimehead[i].ignore = 1;
- if(cistrcmp(mimehead[i].name, "authorization") == 0){- h->c->head.authuser = nil;
- h->c->head.authpass = nil;
- }
- }
- }
- }
-
- if(lex(h) != ',')
- break;
- }
-
-breakout:;
- /*
- * if need to ignore headers we've already parsed,
- * reset & start over. need to save authorization
- * info because it's written over when parsed.
- */
- if(reparse){- u = h->c->head.authuser;
- p = h->c->head.authpass;
- memset(&h->c->head, 0, sizeof(h->c->head));
- h->c->head.authuser = u;
- h->c->head.authpass = p;
-
- h->c->hpos = h->hstart;
- longjmp(h->jmp, 1);
- }
-}
-
-int
-hparseheaders(HConnect *c, int timeout)
-{- Hlex h;
-
- c->head.fresh_thresh = 0;
- c->head.fresh_have = 0;
- c->head.persist = 0;
- if(c->req.vermaj == 0){- c->head.host = hmydomain;
- return 1;
- }
-
- memset(&h, 0, sizeof(h));
- h.c = c;
- if(timeout)
- alarm(timeout);
- if(hgethead(c, 1) < 0)
- return -1;
- if(timeout)
- alarm(0);
- h.hstart = c->hpos;
-
- if(setjmp(h.jmp) == -1)
- return -1;
-
- h.eol = 0;
- h.eoh = 0;
- h.tok = '\n';
- while(lex(&h) != '\n'){- if(h.tok == Word && lex(&h) == ':')
- parsejump(&h, hstrdup(c, h.wordval));
- while(h.tok != '\n')
- lex(&h);
- h.eol = h.eoh;
- }
-
- if(http11(c)){- /*
- * according to the http/1.1 spec,
- * these rules must be followed
- */
- if(c->head.host == nil){- hfail(c, HBadReq, nil);
- return -1;
- }
- if(c->req.urihost != nil)
- c->head.host = c->req.urihost;
- /*
- * also need to check host is actually this one
- */
- }else if(c->head.host == nil)
- c->head.host = hmydomain;
- return 1;
-}
-
-/*
- * mimeparams : | mimeparams ";" mimepara
- * mimeparam : token "=" token | token "=" qstring
- */
-static HSPairs*
-mimeparams(Hlex *h)
-{- HSPairs *p;
- char *s;
-
- p = nil;
- for(;;){- if(lex(h) != Word)
- break;
- s = hstrdup(h->c, h->wordval);
- if(lex(h) != Word && h->tok != QString)
- break;
- p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
- }
- return hrevspairs(p);
-}
-
-/*
- * mimehfields : mimehfield | mimehfields commas mimehfield
- * mimehfield : token mimeparams
- * commas : "," | commas ","
- */
-static HFields*
-mimehfields(Hlex *h)
-{- HFields *f;
-
- f = nil;
- for(;;){- while(lex(h) != Word)
- if(h->tok != ',')
- goto breakout;
-
- f = hmkhfields(h->c, hstrdup(h->c, h->wordval), nil, f);
-
- if(lex(h) == ';')
- f->params = mimeparams(h);
- if(h->tok != ',')
- break;
- }
-breakout:;
- return hrevhfields(f);
-}
-
-/*
- * parse a list of acceptable types, encodings, languages, etc.
- */
-static HContent*
-mimeok(Hlex *h, char *name, int multipart, HContent *head)
-{- char *generic, *specific, *s;
- float v;
-
- /*
- * each type is separated by one or more commas
- */
- while(lex(h) != Word)
- if(h->tok != ',')
- return head;
-
- generic = hstrdup(h->c, h->wordval);
- lex(h);
- if(h->tok == '/' || multipart){- /*
- * at one time, IE5 improperly said '*' for single types
- */
- if(h->tok != '/')
- return nil;
- if(lex(h) != Word)
- return head;
- specific = hstrdup(h->c, h->wordval);
- if(!multipart && strcmp(specific, "*") != 0)
- return head;
- lex(h);
- }else
- specific = nil;
- head = hmkcontent(h->c, generic, specific, head);
-
- for(;;){- switch(h->tok){- case ';':
- /*
- * should make a list of these params
- * for accept, they fall into two classes:
- * up to a q=..., they modify the media type.
- * afterwards, they acceptance criteria
- */
- if(lex(h) == Word){- s = hstrdup(h->c, h->wordval);
- if(lex(h) != '=' || lex(h) != Word && h->tok != QString)
- return head;
- v = strtod(h->wordval, nil);
- if(strcmp(s, "q") == 0)
- head->q = v;
- else if(strcmp(s, "mxb") == 0)
- head->mxb = v;
- else{- /* cope with accept: application/xhtml+xml; profile=http://www.wapforum.org/xhtml, */
- while(lex(h) == Word || (h->tok != ',' && h->eol == 0) )
- ;
- return mimeok(h, name, multipart, head);
- }
- }
- break;
- case ',':
- return mimeok(h, name, multipart, head);
- default:
- return head;
- }
- lex(h);
- }
-}
-
-/*
- * parse a list of entity tags
- * 1#entity-tag
- * entity-tag = [weak] opaque-tag
- * weak = "W/"
- * opaque-tag = quoted-string
- */
-static HETag*
-mimeetag(Hlex *h, HETag *head)
-{- HETag *e;
- int weak;
-
- for(;;){- while(lex(h) != Word && h->tok != QString)
- if(h->tok != ',')
- return head;
-
- weak = 0;
- if(h->tok == Word && strcmp(h->wordval, "*") != 0){- if(strcmp(h->wordval, "W") != 0)
- return head;
- if(lex(h) != '/' || lex(h) != QString)
- return head;
- weak = 1;
- }
-
- e = halloc(h->c, sizeof(HETag));
- e->etag = hstrdup(h->c, h->wordval);
- e->weak = weak;
- e->next = head;
- head = e;
-
- if(lex(h) != ',')
- return head;
- }
-}
-
-/*
- * ranges-specifier = byte-ranges-specifier
- * byte-ranges-specifier = "bytes" "=" byte-range-set
- * byte-range-set = 1#(byte-range-spec|suffix-byte-range-spec)
- * byte-range-spec = byte-pos "-" [byte-pos]
- * byte-pos = 1*DIGIT
- * suffix-byte-range-spec = "-" suffix-length
- * suffix-length = 1*DIGIT
- *
- * syntactically invalid range specifiers cause the
- * entire header field to be ignored.
- * it is syntactically incorrect for the second byte pos
- * to be smaller than the first byte pos
- */
-static HRange*
-mimeranges(Hlex *h, HRange *head)
-{- HRange *r, *rh, *tail;
- char *w;
- ulong start, stop;
- int suf;
-
- if(lex(h) != Word || strcmp(h->wordval, "bytes") != 0 || lex(h) != '=')
- return head;
-
- rh = nil;
- tail = nil;
- for(;;){- while(lex(h) != Word){- if(h->tok != ','){- if(h->tok == '\n')
- goto breakout;
- return head;
- }
- }
-
- w = h->wordval;
- start = 0;
- suf = 1;
- if(w[0] != '-'){- suf = 0;
- start = digtoul(w, &w);
- if(w[0] != '-')
- return head;
- }
- w++;
- stop = ~0UL;
- if(w[0] != '\0'){- stop = digtoul(w, &w);
- if(w[0] != '\0')
- return head;
- if(!suf && stop < start)
- return head;
- }
-
- r = halloc(h->c, sizeof(HRange));
- r->suffix = suf;
- r->start = start;
- r->stop = stop;
- r->next = nil;
- if(rh == nil)
- rh = r;
- else
- tail->next = r;
- tail = r;
-
- if(lex(h) != ','){- if(h->tok == '\n')
- break;
- return head;
- }
- }
-breakout:;
-
- if(head == nil)
- return rh;
-
- for(tail = head; tail->next != nil; tail = tail->next)
- ;
- tail->next = rh;
- return head;
-}
-
-static void
-mimeaccept(Hlex *h, char *name)
-{- h->c->head.oktype = mimeok(h, name, 1, h->c->head.oktype);
-}
-
-static void
-mimeacceptchar(Hlex *h, char *name)
-{- h->c->head.okchar = mimeok(h, name, 0, h->c->head.okchar);
-}
-
-static void
-mimeacceptenc(Hlex *h, char *name)
-{- h->c->head.okencode = mimeok(h, name, 0, h->c->head.okencode);
-}
-
-static void
-mimeacceptlang(Hlex *h, char *name)
-{- h->c->head.oklang = mimeok(h, name, 0, h->c->head.oklang);
-}
-
-static void
-mimemodified(Hlex *h, char *)
-{- lexhead(h);
- h->c->head.ifmodsince = hdate2sec(h->wordval);
-}
-
-static void
-mimeunmodified(Hlex *h, char *)
-{- lexhead(h);
- h->c->head.ifunmodsince = hdate2sec(h->wordval);
-}
-
-static void
-mimematch(Hlex *h, char *)
-{- h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch);
-}
-
-static void
-mimenomatch(Hlex *h, char *)
-{- h->c->head.ifnomatch = mimeetag(h, h->c->head.ifnomatch);
-}
-
-/*
- * argument is either etag or date
- */
-static void
-mimeifrange(Hlex *h, char *)
-{- int c, d, et;
-
- et = 0;
- c = getc(h);
- while(c == ' ' || c == '\t')
- c = getc(h);
- if(c == '"')
- et = 1;
- else if(c == 'W'){- d = getc(h);
- if(d == '/')
- et = 1;
- ungetc(h);
- }
- ungetc(h);
- if(et){- h->c->head.ifrangeetag = mimeetag(h, h->c->head.ifrangeetag);
- }else{- lexhead(h);
- h->c->head.ifrangedate = hdate2sec(h->wordval);
- }
-}
-
-static void
-mimerange(Hlex *h, char *)
-{- h->c->head.range = mimeranges(h, h->c->head.range);
-}
-
-/*
- * parse it like cookies
- */
-static void
-authdigest(Hlex *h, char *)
-{- char *s;
- HSPairs *p;
-
- p = nil;
- for(;;){- while(lex(h) != Word)
- if(h->tok != ';' && h->tok != ',')
- goto breakout;
- s = hstrdup(h->c, h->wordval);
- while (lex(h) != Word && h->tok != QString)
- if (h->tok != '=')
- goto breakout;
- p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
- }
-breakout:
- h->c->head.authinfo = hrevspairs(p);
-}
-
-/*
- * note: netscape and ie through versions 4.7 and 4
- * support only basic authorization, so that is all that is supported here
- *
- * "Authorization" ":" "Basic" base64-user-pass
- * where base64-user-pass is the base64 encoding of
- * username ":" password
- */
-static void
-authbasic(Hlex *h, char *)
-{- char *up, *p;
- int n;
-
- n = lexbase64(h);
- if(!n)
- return;
-
- /*
- * wipe out source for password, so it won't be logged.
- * it is replaced by a single =,
- * which is valid base64, but not ok for an auth reponse.
- * therefore future parses of the header field will not overwrite
- * authuser and authpass.
- */
- memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos);
- h->c->hstop -= n - 1;
- *h->c->hstop = '\0';
- h->c->hpos -= n - 1;
- h->c->hpos[-1] = '=';
-
- up = halloc(h->c, n + 1);
- n = dec64((uchar*)up, n, h->wordval, n);
- up[n] = '\0';
- p = strchr(up, ':');
- if(p != nil){- *p++ = '\0';
- h->c->head.authuser = hstrdup(h->c, up);
- h->c->head.authpass = hstrdup(h->c, p);
- }
-}
-
-/*
- * "Authorization" ":" "Basic" | "Digest" ...
- */
-static void
-mimeauthorization(Hlex *h, char *)
-{- int i;
- static MimeHead authparser[] = {- { "basic", authbasic },- { "digest", authdigest },- };
-
- if(lex(h) != Word)
- return;
-
- for (i = 0; i < nelem(authparser); i++)
- if (cistrcmp(h->wordval, authparser[i].name) == 0) {- (*authparser[i].parse)(h, nil);
- break;
- }
-}
-
-static void
-mimeagent(Hlex *h, char *)
-{- lexhead(h);
- h->c->head.client = hstrdup(h->c, h->wordval);
-}
-
-static void
-mimefrom(Hlex *h, char *)
-{- lexhead(h);
-}
-
-static void
-mimehost(Hlex *h, char *)
-{- char *hd;
-
- lexhead(h);
- for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++)
- ;
- h->c->head.host = hlower(hstrdup(h->c, hd));
-}
-
-/*
- * if present, implies that a message body follows the headers
- * "content-length" ":" digits
- */
-static void
-mimecontlen(Hlex *h, char *)
-{- char *e;
- ulong v;
-
- if(lex(h) != Word)
- return;
- e = h->wordval;
- v = digtoul(e, &e);
- if(v == ~0UL || *e != '\0')
- return;
- h->c->head.contlen = v;
-}
-
-/*
- * mimexpect : "expect" ":" expects
- * expects : | expects "," expect
- * expect : "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams
- * expectparams : ";" token | ";" token "=" token | token "=" qstring
- * for now, we merely parse "100-continue" or anything else.
- */
-static void
-mimeexpect(Hlex *h, char *)
-{- if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n')
- h->c->head.expectother = 1;
- h->c->head.expectcont = 1;
-}
-
-static void
-mimetransenc(Hlex *h, char *)
-{- h->c->head.transenc = mimehfields(h);
-}
-
-static void
-mimecookie(Hlex *h, char *)
-{- char *s;
- HSPairs *p;
-
- p = nil;
- for(;;){- while(lex(h) != Word)
- if(h->tok != ';' && h->tok != ',')
- goto breakout;
- s = hstrdup(h->c, h->wordval);
- while (lex(h) != Word && h->tok != QString)
- if (h->tok != '=')
- goto breakout;
- p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
- }
-breakout:
- h->c->head.cookie = hrevspairs(p);
-}
-
-static void
-mimefresh(Hlex *h, char *)
-{- char *s;
-
- lexhead(h);
- for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++)
- ;
- if(strncmp(s, "pathstat/", 9) == 0)
- h->c->head.fresh_thresh = atoi(s+9);
- else if(strncmp(s, "have/", 5) == 0)
- h->c->head.fresh_have = atoi(s+5);
-}
-
-static void
-mimeignore(Hlex *h, char *)
-{- lexhead(h);
-}
-
-static void
-parsejump(Hlex *h, char *k)
-{- int l, r, m;
-
- l = 1;
- r = nelem(mimehead) - 1;
- while(l <= r){- m = (r + l) >> 1;
- if(cistrcmp(mimehead[m].name, k) <= 0)
- l = m + 1;
- else
- r = m - 1;
- }
- m = l - 1;
- if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){- mimehead[m].seen = 1;
- (*mimehead[m].parse)(h, k);
- }else
- mimeignore(h, k);
-}
-
-static int
-lex(Hlex *h)
-{- return h->tok = lex1(h, 0);
-}
-
-static int
-lexbase64(Hlex *h)
-{- int c, n;
-
- n = 0;
- lex1(h, 1);
-
- while((c = getc(h)) >= 0){- if(!isalnum(c) && c != '+' && c != '/'){- ungetc(h);
- break;
- }
- if(n < HMaxWord-1)
- h->wordval[n++] = c;
- }
- h->wordval[n] = '\0';
- return n;
-}
-
-/*
- * rfc 822/rfc 1521 lexical analyzer
- */
-static int
-lex1(Hlex *h, int skipwhite)
-{- int level, c;
-
- if(h->eol)
- return '\n';
-
-top:
- c = getc(h);
- switch(c){- case '(':- level = 1;
- while((c = getc(h)) >= 0){- if(c == '\\'){- c = getc(h);
- if(c < 0)
- return '\n';
- continue;
- }
- if(c == '(')- level++;
- else if(c == ')' && --level == 0)
- break;
- else if(c == '\n'){- c = getc(h);
- if(c < 0)
- return '\n';
- if(c == ')' && --level == 0)
- break;
- if(c != ' ' && c != '\t'){- ungetc(h);
- return '\n';
- }
- }
- }
- goto top;
-
- case ' ': case '\t':
- goto top;
-
- case '\r':
- c = getc(h);
- if(c != '\n'){- ungetc(h);
- goto top;
- }
-
- case '\n':
- if(h->tok == '\n'){- h->eol = 1;
- h->eoh = 1;
- return '\n';
- }
- c = getc(h);
- if(c < 0){- h->eol = 1;
- return '\n';
- }
- if(c != ' ' && c != '\t'){- ungetc(h);
- h->eol = 1;
- return '\n';
- }
- goto top;
-
- case ')':
- case '<': case '>':
- case '[': case ']':
- case '@': case '/':
- case ',': case ';': case ':': case '?': case '=':
- if(skipwhite){- ungetc(h);
- return c;
- }
- return c;
-
- case '"':
- if(skipwhite){- ungetc(h);
- return c;
- }
- word(h, "\"");
- getc(h); /* skip the closing quote */
- return QString;
-
- default:
- ungetc(h);
- if(skipwhite)
- return c;
- word(h, "\"(){}<>@,;:/[]?=\r\n \t");- if(h->wordval[0] == '\0'){- h->c->head.closeit = 1;
- hfail(h->c, HSyntax);
- longjmp(h->jmp, -1);
- }
- return Word;
- }
- /* not reached */
-}
-
-/*
- * return the rest of an rfc 822, including \n
- * do not map to lower case
- */
-static void
-lexhead(Hlex *h)
-{- int c, n;
-
- n = 0;
- while((c = getc(h)) >= 0){- if(c == '\r')
- c = wordcr(h);
- else if(c == '\n')
- c = wordnl(h);
- if(c == '\n')
- break;
- if(c == '\\'){- c = getc(h);
- if(c < 0)
- break;
- }
-
- if(n < HMaxWord-1)
- h->wordval[n++] = c;
- }
- h->tok = '\n';
- h->eol = 1;
- h->wordval[n] = '\0';
-}
-
-static void
-word(Hlex *h, char *stop)
-{- int c, n;
-
- n = 0;
- while((c = getc(h)) >= 0){- if(c == '\r')
- c = wordcr(h);
- else if(c == '\n')
- c = wordnl(h);
- if(c == '\\'){- c = getc(h);
- if(c < 0)
- break;
- }else if(c < 32 || strchr(stop, c) != nil){- ungetc(h);
- break;
- }
-
- if(n < HMaxWord-1)
- h->wordval[n++] = c;
- }
- h->wordval[n] = '\0';
-}
-
-static int
-wordcr(Hlex *h)
-{- int c;
-
- c = getc(h);
- if(c == '\n')
- return wordnl(h);
- ungetc(h);
- return ' ';
-}
-
-static int
-wordnl(Hlex *h)
-{- int c;
-
- c = getc(h);
- if(c == ' ' || c == '\t')
- return c;
- ungetc(h);
-
- return '\n';
-}
-
-static int
-getc(Hlex *h)
-{- if(h->eoh)
- return -1;
- if(h->c->hpos < h->c->hstop)
- return *h->c->hpos++;
- h->eoh = 1;
- h->eol = 1;
- return -1;
-}
-
-static void
-ungetc(Hlex *h)
-{- if(h->eoh)
- return;
- h->c->hpos--;
-}
-
-static ulong
-digtoul(char *s, char **e)
-{- ulong v;
- int c, ovfl;
-
- v = 0;
- ovfl = 0;
- for(;;){- c = *s;
- if(c < '0' || c > '9')
- break;
- s++;
- c -= '0';
- if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10)
- ovfl = 1;
- v = v * 10 + c;
- }
-
- if(e)
- *e = s;
- if(ovfl)
- return UlongMax;
- return v;
-}
-
-int
-http11(HConnect *c)
-{- return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
-}
-
-char*
-hmkmimeboundary(HConnect *c)
-{- char buf[32];
- int i;
-
- srand((time(0)<<16)|getpid());
- strcpy(buf, "upas-");
- for(i = 5; i < sizeof(buf)-1; i++)
- buf[i] = 'a' + nrand(26);
- buf[i] = 0;
- return hstrdup(c, buf);
-}
-
-HSPairs*
-hmkspairs(HConnect *c, char *s, char *t, HSPairs *next)
-{- HSPairs *sp;
-
- sp = halloc(c, sizeof *sp);
- sp->s = s;
- sp->t = t;
- sp->next = next;
- return sp;
-}
-
-HSPairs*
-hrevspairs(HSPairs *sp)
-{- HSPairs *last, *next;
-
- last = nil;
- for(; sp != nil; sp = next){- next = sp->next;
- sp->next = last;
- last = sp;
- }
- return last;
-}
-
-HFields*
-hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next)
-{- HFields *hf;
-
- hf = halloc(c, sizeof *hf);
- hf->s = s;
- hf->params = p;
- hf->next = next;
- return hf;
-}
-
-HFields*
-hrevhfields(HFields *hf)
-{- HFields *last, *next;
-
- last = nil;
- for(; hf != nil; hf = next){- next = hf->next;
- hf->next = last;
- last = hf;
- }
- return last;
-}
-
-HContent*
-hmkcontent(HConnect *c, char *generic, char *specific, HContent *next)
-{- HContent *ct;
-
- ct = halloc(c, sizeof(HContent));
- ct->generic = generic;
- ct->specific = specific;
- ct->next = next;
- ct->q = 1;
- ct->mxb = 0;
- return ct;
-}
--- a/sys/src/libhttpd/parsereq.c
+++ /dev/null
@@ -1,295 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-typedef struct Strings Strings;
-
-struct Strings
-{- char *s1;
- char *s2;
-};
-
-static char* abspath(HConnect *cc, char *origpath, char *curdir);
-static int getc(HConnect*);
-static char* getword(HConnect*);
-static Strings parseuri(HConnect *c, char*);
-static Strings stripsearch(char*);
-
-/*
- * parse the next request line
- * returns:
- * 1 ok
- * 0 eof
- * -1 error
- */
-int
-hparsereq(HConnect *c, int timeout)
-{- Strings ss;
- char *vs, *v, *search, *uri, *origuri, *extra;
-
- if(c->bin != nil){- hfail(c, HInternal);
- return -1;
- }
-
- /*
- * serve requests until a magic request.
- * later requests have to come quickly.
- * only works for http/1.1 or later.
- */
- if(timeout)
- alarm(timeout);
- if(hgethead(c, 0) < 0)
- return -1;
- if(timeout)
- alarm(0);
- c->reqtime = time(nil);
- c->req.meth = getword(c);
- if(c->req.meth == nil){- hfail(c, HSyntax);
- return -1;
- }
- uri = getword(c);
- if(uri == nil || strlen(uri) == 0){- hfail(c, HSyntax);
- return -1;
- }
- v = getword(c);
- if(v == nil){- if(strcmp(c->req.meth, "GET") != 0){- hfail(c, HUnimp, c->req.meth);
- return -1;
- }
- c->req.vermaj = 0;
- c->req.vermin = 9;
- }else{- vs = v;
- if(strncmp(vs, "HTTP/", 5) != 0){- hfail(c, HUnkVers, vs);
- return -1;
- }
- vs += 5;
- c->req.vermaj = strtoul(vs, &vs, 10);
- if(*vs != '.' || c->req.vermaj != 1){- hfail(c, HUnkVers, vs);
- return -1;
- }
- vs++;
- c->req.vermin = strtoul(vs, &vs, 10);
- if(*vs != '\0'){- hfail(c, HUnkVers, vs);
- return -1;
- }
-
- extra = getword(c);
- if(extra != nil){- hfail(c, HSyntax);
- return -1;
- }
- }
-
- /*
- * the fragment is not supposed to be sent
- * strip it 'cause some clients send it
- */
- origuri = uri;
- uri = strchr(origuri, '#');
- if(uri != nil)
- *uri = 0;
-
- /*
- * http/1.1 requires the server to accept absolute
- * or relative uri's. convert to relative with an absolute path
- */
- if(http11(c)){- ss = parseuri(c, origuri);
- uri = ss.s1;
- c->req.urihost = ss.s2;
- if(uri == nil){- hfail(c, HBadReq, uri);
- return -1;
- }
- origuri = uri;
- }
-
- /*
- * munge uri for search, protection, and magic
- */
- ss = stripsearch(origuri);
- origuri = ss.s1;
- search = ss.s2;
- uri = hurlunesc(c, origuri);
- uri = abspath(c, uri, "/");
- if(uri == nil || uri[0] == '\0'){- hfail(c, HNotFound, "no object specified");
- return -1;
- }
-
- c->req.uri = uri;
- c->req.search = search;
- if(search)
- c->req.searchpairs = hparsequery(c, hstrdup(c, search));
-
- return 1;
-}
-
-static Strings
-parseuri(HConnect *c, char *uri)
-{- Strings ss;
- char *urihost, *p;
-
- urihost = nil;
- ss.s1 = ss.s2 = nil;
- if(uri[0] != '/')
- if(cistrncmp(uri, "http://", 7) == 0)
- uri += 5; /* skip http: */
- else if (cistrncmp(uri, "https://", 8) == 0)
- uri += 6; /* skip https: */
- else
- return ss;
-
- /*
- * anything starting with // is a host name or number
- * hostnames consists of letters, digits, - and .
- * for now, just ignore any port given
- */
- if(uri[0] == '/' && uri[1] == '/'){- urihost = uri + 2;
- p = strchr(urihost, '/');
- if(p == nil)
- uri = hstrdup(c, "/");
- else{- uri = hstrdup(c, p);
- *p = '\0';
- }
- p = strchr(urihost, ':');
- if(p != nil)
- *p = '\0';
- }
-
- if(uri[0] != '/' || uri[1] == '/')
- return ss;
-
- ss.s1 = uri;
- ss.s2 = hlower(urihost);
- return ss;
-}
-static Strings
-stripsearch(char *uri)
-{- Strings ss;
- char *search;
-
- search = strchr(uri, '?');
- if(search != nil)
- *search++ = 0;
- ss.s1 = uri;
- ss.s2 = search;
- return ss;
-}
-
-/*
- * to circumscribe the accessible files we have to eliminate ..'s
- * and resolve all names from the root.
- */
-static char*
-abspath(HConnect *cc, char *origpath, char *curdir)
-{- char *p, *sp, *path, *work, *rpath;
- int len, n, c;
-
- if(curdir == nil)
- curdir = "/";
- if(origpath == nil)
- origpath = "";
- work = hstrdup(cc, origpath);
- path = work;
-
- /*
- * remove any really special characters
- */
- for(sp = "`;|"; *sp; sp++){- p = strchr(path, *sp);
- if(p)
- *p = 0;
- }
-
- len = strlen(curdir) + strlen(path) + 2 + UTFmax;
- if(len < 10)
- len = 10;
- rpath = halloc(cc, len);
- if(*path == '/')
- rpath[0] = 0;
- else
- strcpy(rpath, curdir);
- n = strlen(rpath);
-
- while(path){- p = strchr(path, '/');
- if(p)
- *p++ = 0;
- if(strcmp(path, "..") == 0){- while(n > 1){- n--;
- c = rpath[n];
- rpath[n] = 0;
- if(c == '/')
- break;
- }
- }else if(strcmp(path, ".") == 0){- ;
- }else if(n == 1)
- n += snprint(rpath+n, len-n, "%s", path);
- else
- n += snprint(rpath+n, len-n, "/%s", path);
- path = p;
- }
-
- if(strncmp(rpath, "/bin/", 5) == 0)
- strcpy(rpath, "/");
- return rpath;
-}
-
-static char*
-getword(HConnect *c)
-{- char *buf;
- int ch, n;
-
- while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r')
- ;
- if(ch == '\n')
- return nil;
- n = 0;
- buf = halloc(c, 1);
- for(;;){- switch(ch){- case ' ':
- case '\t':
- case '\r':
- case '\n':
- buf[n] = '\0';
- return hstrdup(c, buf);
- }
-
- if(n < HMaxWord-1){- buf = bingrow(&c->bin, buf, n, n + 1, 0);
- if(buf == nil)
- return nil;
- buf[n++] = ch;
- }
- ch = getc(c);
- }
-}
-
-static int
-getc(HConnect *c)
-{- if(c->hpos < c->hstop)
- return *c->hpos++;
- return '\n';
-}
--- a/sys/src/libhttpd/query.c
+++ /dev/null
@@ -1,39 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <httpd.h>
-
-/*
- * parse a search string of the form
- * tag=val&tag1=val1...
- */
-HSPairs*
-hparsequery(HConnect *c, char *search)
-{- HSPairs *q;
- char *tag, *val, *s;
-
- while((s = strchr(search, '?')) != nil)
- search = s + 1;
- s = search;
- while((s = strchr(s, '+')) != nil)
- *s++ = ' ';
- q = nil;
- while(*search){- tag = search;
- while(*search != '='){- if(*search == '\0')
- return q;
- search++;
- }
- *search++ = 0;
- val = search;
- while(*search != '&'){- if(*search == '\0')
- return hmkspairs(c, hurlunesc(c, tag), hurlunesc(c, val), q);
- search++;
- }
- *search++ = '\0';
- q = hmkspairs(c, hurlunesc(c, tag), hurlunesc(c, val), q);
- }
- return q;
-}
--- a/sys/src/libhttpd/redirected.c
+++ /dev/null
@@ -1,74 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-int
-hredirected(HConnect *c, char *how, char *uri)
-{- Hio *hout;
- char *s, *ss, *scheme, *host;
- char sayport[NETPATHLEN];
- int n;
-
- scheme = c->scheme? c->scheme: "http";
- host = c->head.host;
- if(strchr(uri, ':') != nil)
- host = "";
- else if(uri[0] != '/'){- s = strrchr(c->req.uri, '/');
- if(s != nil)
- *s = '\0';
- ss = halloc(c, strlen(c->req.uri) + strlen(uri) + 2 + UTFmax);
- sprint(ss, "%s/%s", c->req.uri, uri);
- uri = ss;
- if(s != nil)
- *s = '/';
- }
-
- if((strcmp(scheme, "http") == 0 && atoi(c->port) == 80) ||
- (strcmp(scheme, "https") == 0 && atoi(c->port) == 443) ||
- strchr(host, ':') != nil)
- sayport[0] = '\0';
- else
- snprint(sayport, sizeof sayport, ":%s", c->port);
-
- n = snprint(c->xferbuf, HBufSize,
- "<head><title>Redirection</title></head>\r\n"
- "<body><h1>Redirection</h1>\r\n"
- "Your selection can be found <a href=\"%U\"> here</a>.<p></body>\r\n", uri);
-
- hout = &c->hout;
- hprint(hout, "%s %s\r\n", hversion, how);
- hprint(hout, "Date: %D\r\n", time(nil));
- hprint(hout, "Server: Plan9\r\n");
- hprint(hout, "Content-type: text/html\r\n");
- hprint(hout, "Content-Length: %d\r\n", n);
- if(host == nil || host[0] == 0)
- hprint(hout, "Location: %U\r\n", uri);
- else
- hprint(hout, "Location: %s://%U%s%U\r\n",
- scheme, host, sayport, uri);
- 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, n);
-
- if(c->replog)
- if(host == nil || host[0] == 0)
- c->replog(c, "Reply: %s\nRedirect: %U\n", how, uri);
- else
- c->replog(c, "Reply: %s\nRedirect: %s://%U%s%U\n",
- how, scheme, host, sayport, uri);
- return hflush(hout);
-}
-
-int
-hmoved(HConnect *c, char *uri)
-{- return hredirected(c, "301 Moved Permanently", uri);
-}
--- a/sys/src/libhttpd/unallowed.c
+++ /dev/null
@@ -1,35 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-int
-hunallowed(HConnect *c, char *allowed)
-{- Hio *hout;
- int n;
-
- n = snprint(c->xferbuf, HBufSize, "<head><title>Method Not Allowed</title></head>\r\n"
- "<body><h1>Method Not Allowed</h1>\r\n"
- "You can't %s on <a href=\"%U\"> here</a>.<p></body>\r\n", c->req.meth, c->req.uri);
-
- hout = &c->hout;
- hprint(hout, "%s 405 Method Not Allowed\r\n", hversion);
- hprint(hout, "Date: %D\r\n", time(nil));
- hprint(hout, "Server: Plan9\r\n");
- hprint(hout, "Content-Type: text/html\r\n");
- hprint(hout, "Allow: %s\r\n", allowed);
- 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(strcmp(c->req.meth, "HEAD") != 0)
- hwrite(hout, c->xferbuf, n);
-
- if(c->replog)
- c->replog(c, "Reply: 405 Method Not Allowed\nReason: Method Not Allowed\n");
- return hflush(hout);
-}
--- a/sys/src/libhttpd/urlfmt.c
+++ /dev/null
@@ -1,26 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-int
-hurlfmt(Fmt *f)
-{- char buf[HMaxWord*2];
- Rune r;
- char *s;
- int t;
-
- s = va_arg(f->args, char*);
- for(t = 0; t < sizeof(buf) - 8; ){- s += chartorune(&r, s);
- if(r == 0)
- break;
- if(r <= ' ' || r == '%' || r >= Runeself)
- t += snprint(&buf[t], sizeof(buf)-t, "%%%2.2x", r);
- else
- buf[t++] = r;
- }
- buf[t] = 0;
- return fmtstrcpy(f, buf);
-}
--- a/sys/src/libhttpd/urlunesc.c
+++ /dev/null
@@ -1,58 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bin.h>
-#include <httpd.h>
-
-/* go from url with escaped utf to utf */
-char *
-hurlunesc(HConnect *cc, char *s)
-{- char *t, *v, *u;
- Rune r;
- int c, n;
-
- /* unescape */
- u = halloc(cc, strlen(s)+1);
- for(t = u; c = *s; s++){- if(c == '%'){- n = s[1];
- if(n >= '0' && n <= '9')
- n = n - '0';
- else if(n >= 'A' && n <= 'F')
- n = n - 'A' + 10;
- else if(n >= 'a' && n <= 'f')
- n = n - 'a' + 10;
- else
- break;
- r = n;
- n = s[2];
- if(n >= '0' && n <= '9')
- n = n - '0';
- else if(n >= 'A' && n <= 'F')
- n = n - 'A' + 10;
- else if(n >= 'a' && n <= 'f')
- n = n - 'a' + 10;
- else
- break;
- s += 2;
- c = (r<<4)+n;
- }
- *t++ = c;
- }
- *t = '\0';
-
- /* convert to valid utf */
- v = halloc(cc, UTFmax*strlen(u) + 1);
- s = u;
- t = v;
- while(*s){- /* in decoding error, assume latin1 */
- if((n=chartorune(&r, s)) == 1 && r == Runeerror)
- r = (uchar)*s;
- s += n;
- t += runetochar(t, &r);
- }
- *t = '\0';
-
- return v;
-}
--
⑨