180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
32bef681aSDavid du Colombier #include <ctype.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier #include <bin.h>
680ee5cbfSDavid du Colombier #include <httpd.h>
780ee5cbfSDavid du Colombier #include "escape.h"
880ee5cbfSDavid du Colombier
980ee5cbfSDavid du Colombier typedef struct Hlex Hlex;
1080ee5cbfSDavid du Colombier typedef struct MimeHead MimeHead;
1180ee5cbfSDavid du Colombier
1280ee5cbfSDavid du Colombier enum
1380ee5cbfSDavid du Colombier {
1480ee5cbfSDavid du Colombier /*
1580ee5cbfSDavid du Colombier * tokens
1680ee5cbfSDavid du Colombier */
1780ee5cbfSDavid du Colombier Word = 1,
1880ee5cbfSDavid du Colombier QString,
1980ee5cbfSDavid du Colombier };
2080ee5cbfSDavid du Colombier
2180ee5cbfSDavid du Colombier #define UlongMax 4294967295UL
2280ee5cbfSDavid du Colombier
2380ee5cbfSDavid du Colombier struct Hlex
2480ee5cbfSDavid du Colombier {
2580ee5cbfSDavid du Colombier int tok;
2680ee5cbfSDavid du Colombier int eoh;
2780ee5cbfSDavid du Colombier int eol; /* end of header line encountered? */
2880ee5cbfSDavid du Colombier uchar *hstart; /* start of header */
2980ee5cbfSDavid du Colombier jmp_buf jmp; /* jmp here to parse header */
3080ee5cbfSDavid du Colombier char wordval[HMaxWord];
3180ee5cbfSDavid du Colombier HConnect *c;
3280ee5cbfSDavid du Colombier };
3380ee5cbfSDavid du Colombier
3480ee5cbfSDavid du Colombier struct MimeHead
3580ee5cbfSDavid du Colombier {
3680ee5cbfSDavid du Colombier char *name;
3780ee5cbfSDavid du Colombier void (*parse)(Hlex*, char*);
3880ee5cbfSDavid du Colombier uchar seen;
3980ee5cbfSDavid du Colombier uchar ignore;
4080ee5cbfSDavid du Colombier };
4180ee5cbfSDavid du Colombier
4280ee5cbfSDavid du Colombier static void mimeaccept(Hlex*, char*);
4380ee5cbfSDavid du Colombier static void mimeacceptchar(Hlex*, char*);
4480ee5cbfSDavid du Colombier static void mimeacceptenc(Hlex*, char*);
4580ee5cbfSDavid du Colombier static void mimeacceptlang(Hlex*, char*);
4680ee5cbfSDavid du Colombier static void mimeagent(Hlex*, char*);
4780ee5cbfSDavid du Colombier static void mimeauthorization(Hlex*, char*);
4880ee5cbfSDavid du Colombier static void mimeconnection(Hlex*, char*);
4980ee5cbfSDavid du Colombier static void mimecontlen(Hlex*, char*);
502bef681aSDavid du Colombier static void mimecookie(Hlex*, char*);
5180ee5cbfSDavid du Colombier static void mimeexpect(Hlex*, char*);
5280ee5cbfSDavid du Colombier static void mimefresh(Hlex*, char*);
5380ee5cbfSDavid du Colombier static void mimefrom(Hlex*, char*);
5480ee5cbfSDavid du Colombier static void mimehost(Hlex*, char*);
5580ee5cbfSDavid du Colombier static void mimeifrange(Hlex*, char*);
5680ee5cbfSDavid du Colombier static void mimeignore(Hlex*, char*);
5780ee5cbfSDavid du Colombier static void mimematch(Hlex*, char*);
5880ee5cbfSDavid du Colombier static void mimemodified(Hlex*, char*);
5980ee5cbfSDavid du Colombier static void mimenomatch(Hlex*, char*);
6080ee5cbfSDavid du Colombier static void mimerange(Hlex*, char*);
6180ee5cbfSDavid du Colombier static void mimetransenc(Hlex*, char*);
6280ee5cbfSDavid du Colombier static void mimeunmodified(Hlex*, char*);
6380ee5cbfSDavid du Colombier
6480ee5cbfSDavid du Colombier /*
6580ee5cbfSDavid du Colombier * headers seen also include
6680ee5cbfSDavid du Colombier * allow cache-control chargeto
6780ee5cbfSDavid du Colombier * content-encoding content-language content-location content-md5 content-range content-type
6880ee5cbfSDavid du Colombier * date etag expires forwarded last-modified max-forwards pragma
6980ee5cbfSDavid du Colombier * proxy-agent proxy-authorization proxy-connection
7080ee5cbfSDavid du Colombier * ua-color ua-cpu ua-os ua-pixels
7180ee5cbfSDavid du Colombier * upgrade via x-afs-tokens x-serial-number
7280ee5cbfSDavid du Colombier */
7380ee5cbfSDavid du Colombier static MimeHead mimehead[] =
7480ee5cbfSDavid du Colombier {
7580ee5cbfSDavid du Colombier {"accept", mimeaccept},
7680ee5cbfSDavid du Colombier {"accept-charset", mimeacceptchar},
7780ee5cbfSDavid du Colombier {"accept-encoding", mimeacceptenc},
7880ee5cbfSDavid du Colombier {"accept-language", mimeacceptlang},
7980ee5cbfSDavid du Colombier {"authorization", mimeauthorization},
8080ee5cbfSDavid du Colombier {"connection", mimeconnection},
8180ee5cbfSDavid du Colombier {"content-length", mimecontlen},
822bef681aSDavid du Colombier {"cookie", mimecookie},
8380ee5cbfSDavid du Colombier {"expect", mimeexpect},
8480ee5cbfSDavid du Colombier {"fresh", mimefresh},
8580ee5cbfSDavid du Colombier {"from", mimefrom},
8680ee5cbfSDavid du Colombier {"host", mimehost},
8780ee5cbfSDavid du Colombier {"if-match", mimematch},
8880ee5cbfSDavid du Colombier {"if-modified-since", mimemodified},
8980ee5cbfSDavid du Colombier {"if-none-match", mimenomatch},
9080ee5cbfSDavid du Colombier {"if-range", mimeifrange},
9180ee5cbfSDavid du Colombier {"if-unmodified-since", mimeunmodified},
9280ee5cbfSDavid du Colombier {"range", mimerange},
9380ee5cbfSDavid du Colombier {"transfer-encoding", mimetransenc},
9480ee5cbfSDavid du Colombier {"user-agent", mimeagent},
9580ee5cbfSDavid du Colombier };
9680ee5cbfSDavid du Colombier
9780ee5cbfSDavid du Colombier char* hmydomain;
9880ee5cbfSDavid du Colombier char* hversion = "HTTP/1.1";
9980ee5cbfSDavid du Colombier
10080ee5cbfSDavid du Colombier static void lexhead(Hlex*);
10180ee5cbfSDavid du Colombier static void parsejump(Hlex*, char*);
10280ee5cbfSDavid du Colombier static int getc(Hlex*);
10380ee5cbfSDavid du Colombier static void ungetc(Hlex*);
10480ee5cbfSDavid du Colombier static int wordcr(Hlex*);
10580ee5cbfSDavid du Colombier static int wordnl(Hlex*);
10680ee5cbfSDavid du Colombier static void word(Hlex*, char*);
10780ee5cbfSDavid du Colombier static int lex1(Hlex*, int);
10880ee5cbfSDavid du Colombier static int lex(Hlex*);
10980ee5cbfSDavid du Colombier static int lexbase64(Hlex*);
11080ee5cbfSDavid du Colombier static ulong digtoul(char *s, char **e);
11180ee5cbfSDavid du Colombier
11280ee5cbfSDavid du Colombier /*
113f9e1cf08SDavid du Colombier * flush and clean up junk from a request
11480ee5cbfSDavid du Colombier */
11580ee5cbfSDavid du Colombier void
hreqcleanup(HConnect * c)11680ee5cbfSDavid du Colombier hreqcleanup(HConnect *c)
11780ee5cbfSDavid du Colombier {
11880ee5cbfSDavid du Colombier int i;
11980ee5cbfSDavid du Colombier
12080ee5cbfSDavid du Colombier hxferenc(&c->hout, 0);
12180ee5cbfSDavid du Colombier memset(&c->req, 0, sizeof(c->req));
12280ee5cbfSDavid du Colombier memset(&c->head, 0, sizeof(c->head));
12380ee5cbfSDavid du Colombier c->hpos = c->header;
12480ee5cbfSDavid du Colombier c->hstop = c->header;
12580ee5cbfSDavid du Colombier binfree(&c->bin);
12680ee5cbfSDavid du Colombier for(i = 0; i < nelem(mimehead); i++){
12780ee5cbfSDavid du Colombier mimehead[i].seen = 0;
12880ee5cbfSDavid du Colombier mimehead[i].ignore = 0;
12980ee5cbfSDavid du Colombier }
13080ee5cbfSDavid du Colombier }
13180ee5cbfSDavid du Colombier
13280ee5cbfSDavid du Colombier /*
13380ee5cbfSDavid du Colombier * list of tokens
13480ee5cbfSDavid du Colombier * if the client is HTTP/1.0,
13580ee5cbfSDavid du Colombier * ignore headers which match one of the tokens.
13680ee5cbfSDavid du Colombier * restarts parsing if necessary.
13780ee5cbfSDavid du Colombier */
13880ee5cbfSDavid du Colombier static void
mimeconnection(Hlex * h,char *)13980ee5cbfSDavid du Colombier mimeconnection(Hlex *h, char *)
14080ee5cbfSDavid du Colombier {
14180ee5cbfSDavid du Colombier char *u, *p;
14280ee5cbfSDavid du Colombier int reparse, i;
14380ee5cbfSDavid du Colombier
14480ee5cbfSDavid du Colombier reparse = 0;
14580ee5cbfSDavid du Colombier for(;;){
14680ee5cbfSDavid du Colombier while(lex(h) != Word)
14780ee5cbfSDavid du Colombier if(h->tok != ',')
14880ee5cbfSDavid du Colombier goto breakout;
14980ee5cbfSDavid du Colombier
15080ee5cbfSDavid du Colombier if(cistrcmp(h->wordval, "keep-alive") == 0)
15180ee5cbfSDavid du Colombier h->c->head.persist = 1;
15280ee5cbfSDavid du Colombier else if(cistrcmp(h->wordval, "close") == 0)
15380ee5cbfSDavid du Colombier h->c->head.closeit = 1;
15480ee5cbfSDavid du Colombier else if(!http11(h->c)){
15580ee5cbfSDavid du Colombier for(i = 0; i < nelem(mimehead); i++){
15680ee5cbfSDavid du Colombier if(cistrcmp(mimehead[i].name, h->wordval) == 0){
15780ee5cbfSDavid du Colombier reparse = mimehead[i].seen && !mimehead[i].ignore;
15880ee5cbfSDavid du Colombier mimehead[i].ignore = 1;
15980ee5cbfSDavid du Colombier if(cistrcmp(mimehead[i].name, "authorization") == 0){
16080ee5cbfSDavid du Colombier h->c->head.authuser = nil;
16180ee5cbfSDavid du Colombier h->c->head.authpass = nil;
16280ee5cbfSDavid du Colombier }
16380ee5cbfSDavid du Colombier }
16480ee5cbfSDavid du Colombier }
16580ee5cbfSDavid du Colombier }
16680ee5cbfSDavid du Colombier
16780ee5cbfSDavid du Colombier if(lex(h) != ',')
16880ee5cbfSDavid du Colombier break;
16980ee5cbfSDavid du Colombier }
17080ee5cbfSDavid du Colombier
17180ee5cbfSDavid du Colombier breakout:;
17280ee5cbfSDavid du Colombier /*
17380ee5cbfSDavid du Colombier * if need to ignore headers we've already parsed,
17480ee5cbfSDavid du Colombier * reset & start over. need to save authorization
17580ee5cbfSDavid du Colombier * info because it's written over when parsed.
17680ee5cbfSDavid du Colombier */
17780ee5cbfSDavid du Colombier if(reparse){
17880ee5cbfSDavid du Colombier u = h->c->head.authuser;
17980ee5cbfSDavid du Colombier p = h->c->head.authpass;
18080ee5cbfSDavid du Colombier memset(&h->c->head, 0, sizeof(h->c->head));
18180ee5cbfSDavid du Colombier h->c->head.authuser = u;
18280ee5cbfSDavid du Colombier h->c->head.authpass = p;
18380ee5cbfSDavid du Colombier
18480ee5cbfSDavid du Colombier h->c->hpos = h->hstart;
18580ee5cbfSDavid du Colombier longjmp(h->jmp, 1);
18680ee5cbfSDavid du Colombier }
18780ee5cbfSDavid du Colombier }
18880ee5cbfSDavid du Colombier
18980ee5cbfSDavid du Colombier int
hparseheaders(HConnect * c,int timeout)19080ee5cbfSDavid du Colombier hparseheaders(HConnect *c, int timeout)
19180ee5cbfSDavid du Colombier {
19280ee5cbfSDavid du Colombier Hlex h;
19380ee5cbfSDavid du Colombier
19480ee5cbfSDavid du Colombier c->head.fresh_thresh = 0;
19580ee5cbfSDavid du Colombier c->head.fresh_have = 0;
19680ee5cbfSDavid du Colombier c->head.persist = 0;
19780ee5cbfSDavid du Colombier if(c->req.vermaj == 0){
19880ee5cbfSDavid du Colombier c->head.host = hmydomain;
19980ee5cbfSDavid du Colombier return 1;
20080ee5cbfSDavid du Colombier }
20180ee5cbfSDavid du Colombier
20280ee5cbfSDavid du Colombier memset(&h, 0, sizeof(h));
20380ee5cbfSDavid du Colombier h.c = c;
204e059317eSDavid du Colombier if(timeout)
20580ee5cbfSDavid du Colombier alarm(timeout);
206e059317eSDavid du Colombier if(hgethead(c, 1) < 0)
2079a747e4fSDavid du Colombier return -1;
208e059317eSDavid du Colombier if(timeout)
20980ee5cbfSDavid du Colombier alarm(0);
21080ee5cbfSDavid du Colombier h.hstart = c->hpos;
21180ee5cbfSDavid du Colombier
21280ee5cbfSDavid du Colombier if(setjmp(h.jmp) == -1)
21380ee5cbfSDavid du Colombier return -1;
21480ee5cbfSDavid du Colombier
21580ee5cbfSDavid du Colombier h.eol = 0;
21680ee5cbfSDavid du Colombier h.eoh = 0;
21780ee5cbfSDavid du Colombier h.tok = '\n';
21880ee5cbfSDavid du Colombier while(lex(&h) != '\n'){
21980ee5cbfSDavid du Colombier if(h.tok == Word && lex(&h) == ':')
22080ee5cbfSDavid du Colombier parsejump(&h, hstrdup(c, h.wordval));
22180ee5cbfSDavid du Colombier while(h.tok != '\n')
22280ee5cbfSDavid du Colombier lex(&h);
22380ee5cbfSDavid du Colombier h.eol = h.eoh;
22480ee5cbfSDavid du Colombier }
22580ee5cbfSDavid du Colombier
22680ee5cbfSDavid du Colombier if(http11(c)){
22780ee5cbfSDavid du Colombier /*
22880ee5cbfSDavid du Colombier * according to the http/1.1 spec,
22980ee5cbfSDavid du Colombier * these rules must be followed
23080ee5cbfSDavid du Colombier */
23180ee5cbfSDavid du Colombier if(c->head.host == nil){
23280ee5cbfSDavid du Colombier hfail(c, HBadReq, nil);
23380ee5cbfSDavid du Colombier return -1;
23480ee5cbfSDavid du Colombier }
23580ee5cbfSDavid du Colombier if(c->req.urihost != nil)
23680ee5cbfSDavid du Colombier c->head.host = c->req.urihost;
23780ee5cbfSDavid du Colombier /*
23880ee5cbfSDavid du Colombier * also need to check host is actually this one
23980ee5cbfSDavid du Colombier */
24080ee5cbfSDavid du Colombier }else if(c->head.host == nil)
24180ee5cbfSDavid du Colombier c->head.host = hmydomain;
24280ee5cbfSDavid du Colombier return 1;
24380ee5cbfSDavid du Colombier }
24480ee5cbfSDavid du Colombier
24580ee5cbfSDavid du Colombier /*
24680ee5cbfSDavid du Colombier * mimeparams : | mimeparams ";" mimepara
24780ee5cbfSDavid du Colombier * mimeparam : token "=" token | token "=" qstring
24880ee5cbfSDavid du Colombier */
24980ee5cbfSDavid du Colombier static HSPairs*
mimeparams(Hlex * h)25080ee5cbfSDavid du Colombier mimeparams(Hlex *h)
25180ee5cbfSDavid du Colombier {
25280ee5cbfSDavid du Colombier HSPairs *p;
25380ee5cbfSDavid du Colombier char *s;
25480ee5cbfSDavid du Colombier
25580ee5cbfSDavid du Colombier p = nil;
25680ee5cbfSDavid du Colombier for(;;){
25780ee5cbfSDavid du Colombier if(lex(h) != Word)
25880ee5cbfSDavid du Colombier break;
25980ee5cbfSDavid du Colombier s = hstrdup(h->c, h->wordval);
26080ee5cbfSDavid du Colombier if(lex(h) != Word && h->tok != QString)
26180ee5cbfSDavid du Colombier break;
26280ee5cbfSDavid du Colombier p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
26380ee5cbfSDavid du Colombier }
26480ee5cbfSDavid du Colombier return hrevspairs(p);
26580ee5cbfSDavid du Colombier }
26680ee5cbfSDavid du Colombier
26780ee5cbfSDavid du Colombier /*
26880ee5cbfSDavid du Colombier * mimehfields : mimehfield | mimehfields commas mimehfield
26980ee5cbfSDavid du Colombier * mimehfield : token mimeparams
27080ee5cbfSDavid du Colombier * commas : "," | commas ","
27180ee5cbfSDavid du Colombier */
27280ee5cbfSDavid du Colombier static HFields*
mimehfields(Hlex * h)27380ee5cbfSDavid du Colombier mimehfields(Hlex *h)
27480ee5cbfSDavid du Colombier {
27580ee5cbfSDavid du Colombier HFields *f;
27680ee5cbfSDavid du Colombier
27780ee5cbfSDavid du Colombier f = nil;
27880ee5cbfSDavid du Colombier for(;;){
27980ee5cbfSDavid du Colombier while(lex(h) != Word)
28080ee5cbfSDavid du Colombier if(h->tok != ',')
28180ee5cbfSDavid du Colombier goto breakout;
28280ee5cbfSDavid du Colombier
28380ee5cbfSDavid du Colombier f = hmkhfields(h->c, hstrdup(h->c, h->wordval), nil, f);
28480ee5cbfSDavid du Colombier
28580ee5cbfSDavid du Colombier if(lex(h) == ';')
28680ee5cbfSDavid du Colombier f->params = mimeparams(h);
28780ee5cbfSDavid du Colombier if(h->tok != ',')
28880ee5cbfSDavid du Colombier break;
28980ee5cbfSDavid du Colombier }
29080ee5cbfSDavid du Colombier breakout:;
29180ee5cbfSDavid du Colombier return hrevhfields(f);
29280ee5cbfSDavid du Colombier }
29380ee5cbfSDavid du Colombier
29480ee5cbfSDavid du Colombier /*
29580ee5cbfSDavid du Colombier * parse a list of acceptable types, encodings, languages, etc.
29680ee5cbfSDavid du Colombier */
29780ee5cbfSDavid du Colombier static HContent*
mimeok(Hlex * h,char * name,int multipart,HContent * head)29880ee5cbfSDavid du Colombier mimeok(Hlex *h, char *name, int multipart, HContent *head)
29980ee5cbfSDavid du Colombier {
30080ee5cbfSDavid du Colombier char *generic, *specific, *s;
30180ee5cbfSDavid du Colombier float v;
30280ee5cbfSDavid du Colombier
30380ee5cbfSDavid du Colombier /*
30480ee5cbfSDavid du Colombier * each type is separated by one or more commas
30580ee5cbfSDavid du Colombier */
30680ee5cbfSDavid du Colombier while(lex(h) != Word)
30780ee5cbfSDavid du Colombier if(h->tok != ',')
30880ee5cbfSDavid du Colombier return head;
30980ee5cbfSDavid du Colombier
31080ee5cbfSDavid du Colombier generic = hstrdup(h->c, h->wordval);
31180ee5cbfSDavid du Colombier lex(h);
31280ee5cbfSDavid du Colombier if(h->tok == '/' || multipart){
31380ee5cbfSDavid du Colombier /*
31480ee5cbfSDavid du Colombier * at one time, IE5 improperly said '*' for single types
31580ee5cbfSDavid du Colombier */
31680ee5cbfSDavid du Colombier if(h->tok != '/')
31780ee5cbfSDavid du Colombier return nil;
31880ee5cbfSDavid du Colombier if(lex(h) != Word)
31980ee5cbfSDavid du Colombier return head;
32080ee5cbfSDavid du Colombier specific = hstrdup(h->c, h->wordval);
32180ee5cbfSDavid du Colombier if(!multipart && strcmp(specific, "*") != 0)
32280ee5cbfSDavid du Colombier return head;
32380ee5cbfSDavid du Colombier lex(h);
32480ee5cbfSDavid du Colombier }else
32580ee5cbfSDavid du Colombier specific = nil;
32680ee5cbfSDavid du Colombier head = hmkcontent(h->c, generic, specific, head);
32780ee5cbfSDavid du Colombier
32880ee5cbfSDavid du Colombier for(;;){
32980ee5cbfSDavid du Colombier switch(h->tok){
33080ee5cbfSDavid du Colombier case ';':
33180ee5cbfSDavid du Colombier /*
33280ee5cbfSDavid du Colombier * should make a list of these params
33380ee5cbfSDavid du Colombier * for accept, they fall into two classes:
33480ee5cbfSDavid du Colombier * up to a q=..., they modify the media type.
33580ee5cbfSDavid du Colombier * afterwards, they acceptance criteria
33680ee5cbfSDavid du Colombier */
33780ee5cbfSDavid du Colombier if(lex(h) == Word){
33880ee5cbfSDavid du Colombier s = hstrdup(h->c, h->wordval);
33980ee5cbfSDavid du Colombier if(lex(h) != '=' || lex(h) != Word && h->tok != QString)
34080ee5cbfSDavid du Colombier return head;
34180ee5cbfSDavid du Colombier v = strtod(h->wordval, nil);
34280ee5cbfSDavid du Colombier if(strcmp(s, "q") == 0)
34380ee5cbfSDavid du Colombier head->q = v;
34480ee5cbfSDavid du Colombier else if(strcmp(s, "mxb") == 0)
34580ee5cbfSDavid du Colombier head->mxb = v;
34651711cb6SDavid du Colombier else{
34751711cb6SDavid du Colombier /* cope with accept: application/xhtml+xml; profile=http://www.wapforum.org/xhtml, */
34851711cb6SDavid du Colombier while(lex(h) == Word || (h->tok != ',' && h->eol == 0) )
34951711cb6SDavid du Colombier ;
35051711cb6SDavid du Colombier return mimeok(h, name, multipart, head);
35151711cb6SDavid du Colombier }
35280ee5cbfSDavid du Colombier }
35380ee5cbfSDavid du Colombier break;
35480ee5cbfSDavid du Colombier case ',':
35580ee5cbfSDavid du Colombier return mimeok(h, name, multipart, head);
35680ee5cbfSDavid du Colombier default:
35780ee5cbfSDavid du Colombier return head;
35880ee5cbfSDavid du Colombier }
35980ee5cbfSDavid du Colombier lex(h);
36080ee5cbfSDavid du Colombier }
36180ee5cbfSDavid du Colombier }
36280ee5cbfSDavid du Colombier
36380ee5cbfSDavid du Colombier /*
36480ee5cbfSDavid du Colombier * parse a list of entity tags
36580ee5cbfSDavid du Colombier * 1#entity-tag
36680ee5cbfSDavid du Colombier * entity-tag = [weak] opaque-tag
36780ee5cbfSDavid du Colombier * weak = "W/"
36880ee5cbfSDavid du Colombier * opaque-tag = quoted-string
36980ee5cbfSDavid du Colombier */
37080ee5cbfSDavid du Colombier static HETag*
mimeetag(Hlex * h,HETag * head)37180ee5cbfSDavid du Colombier mimeetag(Hlex *h, HETag *head)
37280ee5cbfSDavid du Colombier {
37380ee5cbfSDavid du Colombier HETag *e;
37480ee5cbfSDavid du Colombier int weak;
37580ee5cbfSDavid du Colombier
37680ee5cbfSDavid du Colombier for(;;){
37780ee5cbfSDavid du Colombier while(lex(h) != Word && h->tok != QString)
37880ee5cbfSDavid du Colombier if(h->tok != ',')
37980ee5cbfSDavid du Colombier return head;
38080ee5cbfSDavid du Colombier
38180ee5cbfSDavid du Colombier weak = 0;
38280ee5cbfSDavid du Colombier if(h->tok == Word && strcmp(h->wordval, "*") != 0){
38380ee5cbfSDavid du Colombier if(strcmp(h->wordval, "W") != 0)
38480ee5cbfSDavid du Colombier return head;
38580ee5cbfSDavid du Colombier if(lex(h) != '/' || lex(h) != QString)
38680ee5cbfSDavid du Colombier return head;
38780ee5cbfSDavid du Colombier weak = 1;
38880ee5cbfSDavid du Colombier }
38980ee5cbfSDavid du Colombier
39080ee5cbfSDavid du Colombier e = halloc(h->c, sizeof(HETag));
39180ee5cbfSDavid du Colombier e->etag = hstrdup(h->c, h->wordval);
39280ee5cbfSDavid du Colombier e->weak = weak;
39380ee5cbfSDavid du Colombier e->next = head;
39480ee5cbfSDavid du Colombier head = e;
39580ee5cbfSDavid du Colombier
39680ee5cbfSDavid du Colombier if(lex(h) != ',')
39780ee5cbfSDavid du Colombier return head;
39880ee5cbfSDavid du Colombier }
39980ee5cbfSDavid du Colombier }
40080ee5cbfSDavid du Colombier
40180ee5cbfSDavid du Colombier /*
40280ee5cbfSDavid du Colombier * ranges-specifier = byte-ranges-specifier
40380ee5cbfSDavid du Colombier * byte-ranges-specifier = "bytes" "=" byte-range-set
40480ee5cbfSDavid du Colombier * byte-range-set = 1#(byte-range-spec|suffix-byte-range-spec)
40580ee5cbfSDavid du Colombier * byte-range-spec = byte-pos "-" [byte-pos]
40680ee5cbfSDavid du Colombier * byte-pos = 1*DIGIT
40780ee5cbfSDavid du Colombier * suffix-byte-range-spec = "-" suffix-length
40880ee5cbfSDavid du Colombier * suffix-length = 1*DIGIT
40980ee5cbfSDavid du Colombier *
41080ee5cbfSDavid du Colombier * syntactically invalid range specifiers cause the
41180ee5cbfSDavid du Colombier * entire header field to be ignored.
41280ee5cbfSDavid du Colombier * it is syntactically incorrect for the second byte pos
41380ee5cbfSDavid du Colombier * to be smaller than the first byte pos
41480ee5cbfSDavid du Colombier */
41580ee5cbfSDavid du Colombier static HRange*
mimeranges(Hlex * h,HRange * head)41680ee5cbfSDavid du Colombier mimeranges(Hlex *h, HRange *head)
41780ee5cbfSDavid du Colombier {
41880ee5cbfSDavid du Colombier HRange *r, *rh, *tail;
41980ee5cbfSDavid du Colombier char *w;
42080ee5cbfSDavid du Colombier ulong start, stop;
42180ee5cbfSDavid du Colombier int suf;
42280ee5cbfSDavid du Colombier
42380ee5cbfSDavid du Colombier if(lex(h) != Word || strcmp(h->wordval, "bytes") != 0 || lex(h) != '=')
42480ee5cbfSDavid du Colombier return head;
42580ee5cbfSDavid du Colombier
42680ee5cbfSDavid du Colombier rh = nil;
42780ee5cbfSDavid du Colombier tail = nil;
42880ee5cbfSDavid du Colombier for(;;){
42980ee5cbfSDavid du Colombier while(lex(h) != Word){
43080ee5cbfSDavid du Colombier if(h->tok != ','){
43180ee5cbfSDavid du Colombier if(h->tok == '\n')
43280ee5cbfSDavid du Colombier goto breakout;
43380ee5cbfSDavid du Colombier return head;
43480ee5cbfSDavid du Colombier }
43580ee5cbfSDavid du Colombier }
43680ee5cbfSDavid du Colombier
43780ee5cbfSDavid du Colombier w = h->wordval;
43880ee5cbfSDavid du Colombier start = 0;
43980ee5cbfSDavid du Colombier suf = 1;
44080ee5cbfSDavid du Colombier if(w[0] != '-'){
44180ee5cbfSDavid du Colombier suf = 0;
44280ee5cbfSDavid du Colombier start = digtoul(w, &w);
44380ee5cbfSDavid du Colombier if(w[0] != '-')
44480ee5cbfSDavid du Colombier return head;
44580ee5cbfSDavid du Colombier }
44680ee5cbfSDavid du Colombier w++;
44780ee5cbfSDavid du Colombier stop = ~0UL;
44880ee5cbfSDavid du Colombier if(w[0] != '\0'){
44980ee5cbfSDavid du Colombier stop = digtoul(w, &w);
45080ee5cbfSDavid du Colombier if(w[0] != '\0')
45180ee5cbfSDavid du Colombier return head;
45280ee5cbfSDavid du Colombier if(!suf && stop < start)
45380ee5cbfSDavid du Colombier return head;
45480ee5cbfSDavid du Colombier }
45580ee5cbfSDavid du Colombier
45680ee5cbfSDavid du Colombier r = halloc(h->c, sizeof(HRange));
45780ee5cbfSDavid du Colombier r->suffix = suf;
45880ee5cbfSDavid du Colombier r->start = start;
45980ee5cbfSDavid du Colombier r->stop = stop;
46080ee5cbfSDavid du Colombier r->next = nil;
46180ee5cbfSDavid du Colombier if(rh == nil)
46280ee5cbfSDavid du Colombier rh = r;
46380ee5cbfSDavid du Colombier else
46480ee5cbfSDavid du Colombier tail->next = r;
46580ee5cbfSDavid du Colombier tail = r;
46680ee5cbfSDavid du Colombier
46780ee5cbfSDavid du Colombier if(lex(h) != ','){
46880ee5cbfSDavid du Colombier if(h->tok == '\n')
46980ee5cbfSDavid du Colombier break;
47080ee5cbfSDavid du Colombier return head;
47180ee5cbfSDavid du Colombier }
47280ee5cbfSDavid du Colombier }
47380ee5cbfSDavid du Colombier breakout:;
47480ee5cbfSDavid du Colombier
47580ee5cbfSDavid du Colombier if(head == nil)
47680ee5cbfSDavid du Colombier return rh;
47780ee5cbfSDavid du Colombier
47880ee5cbfSDavid du Colombier for(tail = head; tail->next != nil; tail = tail->next)
47980ee5cbfSDavid du Colombier ;
48080ee5cbfSDavid du Colombier tail->next = rh;
48180ee5cbfSDavid du Colombier return head;
48280ee5cbfSDavid du Colombier }
48380ee5cbfSDavid du Colombier
48480ee5cbfSDavid du Colombier static void
mimeaccept(Hlex * h,char * name)48580ee5cbfSDavid du Colombier mimeaccept(Hlex *h, char *name)
48680ee5cbfSDavid du Colombier {
48780ee5cbfSDavid du Colombier h->c->head.oktype = mimeok(h, name, 1, h->c->head.oktype);
48880ee5cbfSDavid du Colombier }
48980ee5cbfSDavid du Colombier
49080ee5cbfSDavid du Colombier static void
mimeacceptchar(Hlex * h,char * name)49180ee5cbfSDavid du Colombier mimeacceptchar(Hlex *h, char *name)
49280ee5cbfSDavid du Colombier {
49380ee5cbfSDavid du Colombier h->c->head.okchar = mimeok(h, name, 0, h->c->head.okchar);
49480ee5cbfSDavid du Colombier }
49580ee5cbfSDavid du Colombier
49680ee5cbfSDavid du Colombier static void
mimeacceptenc(Hlex * h,char * name)49780ee5cbfSDavid du Colombier mimeacceptenc(Hlex *h, char *name)
49880ee5cbfSDavid du Colombier {
49980ee5cbfSDavid du Colombier h->c->head.okencode = mimeok(h, name, 0, h->c->head.okencode);
50080ee5cbfSDavid du Colombier }
50180ee5cbfSDavid du Colombier
50280ee5cbfSDavid du Colombier static void
mimeacceptlang(Hlex * h,char * name)50380ee5cbfSDavid du Colombier mimeacceptlang(Hlex *h, char *name)
50480ee5cbfSDavid du Colombier {
50580ee5cbfSDavid du Colombier h->c->head.oklang = mimeok(h, name, 0, h->c->head.oklang);
50680ee5cbfSDavid du Colombier }
50780ee5cbfSDavid du Colombier
50880ee5cbfSDavid du Colombier static void
mimemodified(Hlex * h,char *)50980ee5cbfSDavid du Colombier mimemodified(Hlex *h, char *)
51080ee5cbfSDavid du Colombier {
51180ee5cbfSDavid du Colombier lexhead(h);
51280ee5cbfSDavid du Colombier h->c->head.ifmodsince = hdate2sec(h->wordval);
51380ee5cbfSDavid du Colombier }
51480ee5cbfSDavid du Colombier
51580ee5cbfSDavid du Colombier static void
mimeunmodified(Hlex * h,char *)51680ee5cbfSDavid du Colombier mimeunmodified(Hlex *h, char *)
51780ee5cbfSDavid du Colombier {
51880ee5cbfSDavid du Colombier lexhead(h);
51980ee5cbfSDavid du Colombier h->c->head.ifunmodsince = hdate2sec(h->wordval);
52080ee5cbfSDavid du Colombier }
52180ee5cbfSDavid du Colombier
52280ee5cbfSDavid du Colombier static void
mimematch(Hlex * h,char *)52380ee5cbfSDavid du Colombier mimematch(Hlex *h, char *)
52480ee5cbfSDavid du Colombier {
52580ee5cbfSDavid du Colombier h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch);
52680ee5cbfSDavid du Colombier }
52780ee5cbfSDavid du Colombier
52880ee5cbfSDavid du Colombier static void
mimenomatch(Hlex * h,char *)52980ee5cbfSDavid du Colombier mimenomatch(Hlex *h, char *)
53080ee5cbfSDavid du Colombier {
53180ee5cbfSDavid du Colombier h->c->head.ifnomatch = mimeetag(h, h->c->head.ifnomatch);
53280ee5cbfSDavid du Colombier }
53380ee5cbfSDavid du Colombier
53480ee5cbfSDavid du Colombier /*
53580ee5cbfSDavid du Colombier * argument is either etag or date
53680ee5cbfSDavid du Colombier */
53780ee5cbfSDavid du Colombier static void
mimeifrange(Hlex * h,char *)53880ee5cbfSDavid du Colombier mimeifrange(Hlex *h, char *)
53980ee5cbfSDavid du Colombier {
54080ee5cbfSDavid du Colombier int c, d, et;
54180ee5cbfSDavid du Colombier
54280ee5cbfSDavid du Colombier et = 0;
54380ee5cbfSDavid du Colombier c = getc(h);
54480ee5cbfSDavid du Colombier while(c == ' ' || c == '\t')
54580ee5cbfSDavid du Colombier c = getc(h);
54680ee5cbfSDavid du Colombier if(c == '"')
54780ee5cbfSDavid du Colombier et = 1;
54880ee5cbfSDavid du Colombier else if(c == 'W'){
54980ee5cbfSDavid du Colombier d = getc(h);
55080ee5cbfSDavid du Colombier if(d == '/')
55180ee5cbfSDavid du Colombier et = 1;
55280ee5cbfSDavid du Colombier ungetc(h);
55380ee5cbfSDavid du Colombier }
55480ee5cbfSDavid du Colombier ungetc(h);
55580ee5cbfSDavid du Colombier if(et){
55680ee5cbfSDavid du Colombier h->c->head.ifrangeetag = mimeetag(h, h->c->head.ifrangeetag);
55780ee5cbfSDavid du Colombier }else{
55880ee5cbfSDavid du Colombier lexhead(h);
55980ee5cbfSDavid du Colombier h->c->head.ifrangedate = hdate2sec(h->wordval);
56080ee5cbfSDavid du Colombier }
56180ee5cbfSDavid du Colombier }
56280ee5cbfSDavid du Colombier
56380ee5cbfSDavid du Colombier static void
mimerange(Hlex * h,char *)56480ee5cbfSDavid du Colombier mimerange(Hlex *h, char *)
56580ee5cbfSDavid du Colombier {
56680ee5cbfSDavid du Colombier h->c->head.range = mimeranges(h, h->c->head.range);
56780ee5cbfSDavid du Colombier }
56880ee5cbfSDavid du Colombier
56980ee5cbfSDavid du Colombier /*
570*b39189fdSDavid du Colombier * parse it like cookies
571*b39189fdSDavid du Colombier */
572*b39189fdSDavid du Colombier static void
authdigest(Hlex * h,char *)573*b39189fdSDavid du Colombier authdigest(Hlex *h, char *)
574*b39189fdSDavid du Colombier {
575*b39189fdSDavid du Colombier char *s;
576*b39189fdSDavid du Colombier HSPairs *p;
577*b39189fdSDavid du Colombier
578*b39189fdSDavid du Colombier p = nil;
579*b39189fdSDavid du Colombier for(;;){
580*b39189fdSDavid du Colombier while(lex(h) != Word)
581*b39189fdSDavid du Colombier if(h->tok != ';' && h->tok != ',')
582*b39189fdSDavid du Colombier goto breakout;
583*b39189fdSDavid du Colombier s = hstrdup(h->c, h->wordval);
584*b39189fdSDavid du Colombier while (lex(h) != Word && h->tok != QString)
585*b39189fdSDavid du Colombier if (h->tok != '=')
586*b39189fdSDavid du Colombier goto breakout;
587*b39189fdSDavid du Colombier p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
588*b39189fdSDavid du Colombier }
589*b39189fdSDavid du Colombier breakout:
590*b39189fdSDavid du Colombier h->c->head.authinfo = hrevspairs(p);
591*b39189fdSDavid du Colombier }
592*b39189fdSDavid du Colombier
593*b39189fdSDavid du Colombier /*
59480ee5cbfSDavid du Colombier * note: netscape and ie through versions 4.7 and 4
59580ee5cbfSDavid du Colombier * support only basic authorization, so that is all that is supported here
59680ee5cbfSDavid du Colombier *
59780ee5cbfSDavid du Colombier * "Authorization" ":" "Basic" base64-user-pass
59880ee5cbfSDavid du Colombier * where base64-user-pass is the base64 encoding of
59980ee5cbfSDavid du Colombier * username ":" password
60080ee5cbfSDavid du Colombier */
60180ee5cbfSDavid du Colombier static void
authbasic(Hlex * h,char *)602*b39189fdSDavid du Colombier authbasic(Hlex *h, char *)
60380ee5cbfSDavid du Colombier {
60480ee5cbfSDavid du Colombier char *up, *p;
60580ee5cbfSDavid du Colombier int n;
60680ee5cbfSDavid du Colombier
60780ee5cbfSDavid du Colombier n = lexbase64(h);
60880ee5cbfSDavid du Colombier if(!n)
60980ee5cbfSDavid du Colombier return;
61080ee5cbfSDavid du Colombier
61180ee5cbfSDavid du Colombier /*
61280ee5cbfSDavid du Colombier * wipe out source for password, so it won't be logged.
61380ee5cbfSDavid du Colombier * it is replaced by a single =,
61480ee5cbfSDavid du Colombier * which is valid base64, but not ok for an auth reponse.
61580ee5cbfSDavid du Colombier * therefore future parses of the header field will not overwrite
61680ee5cbfSDavid du Colombier * authuser and authpass.
61780ee5cbfSDavid du Colombier */
61880ee5cbfSDavid du Colombier memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos);
61980ee5cbfSDavid du Colombier h->c->hstop -= n - 1;
62080ee5cbfSDavid du Colombier *h->c->hstop = '\0';
62180ee5cbfSDavid du Colombier h->c->hpos -= n - 1;
62280ee5cbfSDavid du Colombier h->c->hpos[-1] = '=';
62380ee5cbfSDavid du Colombier
62480ee5cbfSDavid du Colombier up = halloc(h->c, n + 1);
62580ee5cbfSDavid du Colombier n = dec64((uchar*)up, n, h->wordval, n);
62680ee5cbfSDavid du Colombier up[n] = '\0';
62780ee5cbfSDavid du Colombier p = strchr(up, ':');
62880ee5cbfSDavid du Colombier if(p != nil){
62980ee5cbfSDavid du Colombier *p++ = '\0';
63080ee5cbfSDavid du Colombier h->c->head.authuser = hstrdup(h->c, up);
63180ee5cbfSDavid du Colombier h->c->head.authpass = hstrdup(h->c, p);
63280ee5cbfSDavid du Colombier }
63380ee5cbfSDavid du Colombier }
63480ee5cbfSDavid du Colombier
635*b39189fdSDavid du Colombier /*
636*b39189fdSDavid du Colombier * "Authorization" ":" "Basic" | "Digest" ...
637*b39189fdSDavid du Colombier */
638*b39189fdSDavid du Colombier static void
mimeauthorization(Hlex * h,char *)639*b39189fdSDavid du Colombier mimeauthorization(Hlex *h, char *)
640*b39189fdSDavid du Colombier {
641*b39189fdSDavid du Colombier int i;
642*b39189fdSDavid du Colombier static MimeHead authparser[] = {
643*b39189fdSDavid du Colombier { "basic", authbasic },
644*b39189fdSDavid du Colombier { "digest", authdigest },
645*b39189fdSDavid du Colombier };
646*b39189fdSDavid du Colombier
647*b39189fdSDavid du Colombier if(lex(h) != Word)
648*b39189fdSDavid du Colombier return;
649*b39189fdSDavid du Colombier
650*b39189fdSDavid du Colombier for (i = 0; i < nelem(authparser); i++)
651*b39189fdSDavid du Colombier if (cistrcmp(h->wordval, authparser[i].name) == 0) {
652*b39189fdSDavid du Colombier (*authparser[i].parse)(h, nil);
653*b39189fdSDavid du Colombier break;
654*b39189fdSDavid du Colombier }
655*b39189fdSDavid du Colombier }
656*b39189fdSDavid du Colombier
65780ee5cbfSDavid du Colombier static void
mimeagent(Hlex * h,char *)65880ee5cbfSDavid du Colombier mimeagent(Hlex *h, char *)
65980ee5cbfSDavid du Colombier {
66080ee5cbfSDavid du Colombier lexhead(h);
66180ee5cbfSDavid du Colombier h->c->head.client = hstrdup(h->c, h->wordval);
66280ee5cbfSDavid du Colombier }
66380ee5cbfSDavid du Colombier
66480ee5cbfSDavid du Colombier static void
mimefrom(Hlex * h,char *)66580ee5cbfSDavid du Colombier mimefrom(Hlex *h, char *)
66680ee5cbfSDavid du Colombier {
66780ee5cbfSDavid du Colombier lexhead(h);
66880ee5cbfSDavid du Colombier }
66980ee5cbfSDavid du Colombier
67080ee5cbfSDavid du Colombier static void
mimehost(Hlex * h,char *)67180ee5cbfSDavid du Colombier mimehost(Hlex *h, char *)
67280ee5cbfSDavid du Colombier {
67380ee5cbfSDavid du Colombier char *hd;
67480ee5cbfSDavid du Colombier
67580ee5cbfSDavid du Colombier lexhead(h);
67680ee5cbfSDavid du Colombier for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++)
67780ee5cbfSDavid du Colombier ;
67880ee5cbfSDavid du Colombier h->c->head.host = hlower(hstrdup(h->c, hd));
67980ee5cbfSDavid du Colombier }
68080ee5cbfSDavid du Colombier
68180ee5cbfSDavid du Colombier /*
68280ee5cbfSDavid du Colombier * if present, implies that a message body follows the headers
68380ee5cbfSDavid du Colombier * "content-length" ":" digits
68480ee5cbfSDavid du Colombier */
68580ee5cbfSDavid du Colombier static void
mimecontlen(Hlex * h,char *)68680ee5cbfSDavid du Colombier mimecontlen(Hlex *h, char *)
68780ee5cbfSDavid du Colombier {
68880ee5cbfSDavid du Colombier char *e;
68980ee5cbfSDavid du Colombier ulong v;
69080ee5cbfSDavid du Colombier
69180ee5cbfSDavid du Colombier if(lex(h) != Word)
69280ee5cbfSDavid du Colombier return;
69380ee5cbfSDavid du Colombier e = h->wordval;
69480ee5cbfSDavid du Colombier v = digtoul(e, &e);
69580ee5cbfSDavid du Colombier if(v == ~0UL || *e != '\0')
69680ee5cbfSDavid du Colombier return;
69780ee5cbfSDavid du Colombier h->c->head.contlen = v;
69880ee5cbfSDavid du Colombier }
69980ee5cbfSDavid du Colombier
70080ee5cbfSDavid du Colombier /*
70180ee5cbfSDavid du Colombier * mimexpect : "expect" ":" expects
70280ee5cbfSDavid du Colombier * expects : | expects "," expect
70380ee5cbfSDavid du Colombier * expect : "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams
70480ee5cbfSDavid du Colombier * expectparams : ";" token | ";" token "=" token | token "=" qstring
70580ee5cbfSDavid du Colombier * for now, we merely parse "100-continue" or anything else.
70680ee5cbfSDavid du Colombier */
70780ee5cbfSDavid du Colombier static void
mimeexpect(Hlex * h,char *)70880ee5cbfSDavid du Colombier mimeexpect(Hlex *h, char *)
70980ee5cbfSDavid du Colombier {
71080ee5cbfSDavid du Colombier if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n')
71180ee5cbfSDavid du Colombier h->c->head.expectother = 1;
71280ee5cbfSDavid du Colombier h->c->head.expectcont = 1;
71380ee5cbfSDavid du Colombier }
71480ee5cbfSDavid du Colombier
71580ee5cbfSDavid du Colombier static void
mimetransenc(Hlex * h,char *)71680ee5cbfSDavid du Colombier mimetransenc(Hlex *h, char *)
71780ee5cbfSDavid du Colombier {
71880ee5cbfSDavid du Colombier h->c->head.transenc = mimehfields(h);
71980ee5cbfSDavid du Colombier }
72080ee5cbfSDavid du Colombier
72180ee5cbfSDavid du Colombier static void
mimecookie(Hlex * h,char *)7222bef681aSDavid du Colombier mimecookie(Hlex *h, char *)
7232bef681aSDavid du Colombier {
7242bef681aSDavid du Colombier char *s;
7252bef681aSDavid du Colombier HSPairs *p;
7262bef681aSDavid du Colombier
7272bef681aSDavid du Colombier p = nil;
7282bef681aSDavid du Colombier for(;;){
7292bef681aSDavid du Colombier while(lex(h) != Word)
7302bef681aSDavid du Colombier if(h->tok != ';' && h->tok != ',')
7312bef681aSDavid du Colombier goto breakout;
7322bef681aSDavid du Colombier s = hstrdup(h->c, h->wordval);
7332bef681aSDavid du Colombier while (lex(h) != Word && h->tok != QString)
7342bef681aSDavid du Colombier if (h->tok != '=')
7352bef681aSDavid du Colombier goto breakout;
7362bef681aSDavid du Colombier p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
7372bef681aSDavid du Colombier }
7382bef681aSDavid du Colombier breakout:
7392bef681aSDavid du Colombier h->c->head.cookie = hrevspairs(p);
7402bef681aSDavid du Colombier }
7412bef681aSDavid du Colombier
7422bef681aSDavid du Colombier static void
mimefresh(Hlex * h,char *)74380ee5cbfSDavid du Colombier mimefresh(Hlex *h, char *)
74480ee5cbfSDavid du Colombier {
74580ee5cbfSDavid du Colombier char *s;
74680ee5cbfSDavid du Colombier
74780ee5cbfSDavid du Colombier lexhead(h);
74880ee5cbfSDavid du Colombier for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++)
74980ee5cbfSDavid du Colombier ;
75080ee5cbfSDavid du Colombier if(strncmp(s, "pathstat/", 9) == 0)
75180ee5cbfSDavid du Colombier h->c->head.fresh_thresh = atoi(s+9);
75280ee5cbfSDavid du Colombier else if(strncmp(s, "have/", 5) == 0)
75380ee5cbfSDavid du Colombier h->c->head.fresh_have = atoi(s+5);
75480ee5cbfSDavid du Colombier }
75580ee5cbfSDavid du Colombier
75680ee5cbfSDavid du Colombier static void
mimeignore(Hlex * h,char *)75780ee5cbfSDavid du Colombier mimeignore(Hlex *h, char *)
75880ee5cbfSDavid du Colombier {
75980ee5cbfSDavid du Colombier lexhead(h);
76080ee5cbfSDavid du Colombier }
76180ee5cbfSDavid du Colombier
76280ee5cbfSDavid du Colombier static void
parsejump(Hlex * h,char * k)76380ee5cbfSDavid du Colombier parsejump(Hlex *h, char *k)
76480ee5cbfSDavid du Colombier {
76580ee5cbfSDavid du Colombier int l, r, m;
76680ee5cbfSDavid du Colombier
76780ee5cbfSDavid du Colombier l = 1;
76880ee5cbfSDavid du Colombier r = nelem(mimehead) - 1;
76980ee5cbfSDavid du Colombier while(l <= r){
77080ee5cbfSDavid du Colombier m = (r + l) >> 1;
77180ee5cbfSDavid du Colombier if(cistrcmp(mimehead[m].name, k) <= 0)
77280ee5cbfSDavid du Colombier l = m + 1;
77380ee5cbfSDavid du Colombier else
77480ee5cbfSDavid du Colombier r = m - 1;
77580ee5cbfSDavid du Colombier }
77680ee5cbfSDavid du Colombier m = l - 1;
77780ee5cbfSDavid du Colombier if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){
77880ee5cbfSDavid du Colombier mimehead[m].seen = 1;
77980ee5cbfSDavid du Colombier (*mimehead[m].parse)(h, k);
78080ee5cbfSDavid du Colombier }else
78180ee5cbfSDavid du Colombier mimeignore(h, k);
78280ee5cbfSDavid du Colombier }
78380ee5cbfSDavid du Colombier
78480ee5cbfSDavid du Colombier static int
lex(Hlex * h)78580ee5cbfSDavid du Colombier lex(Hlex *h)
78680ee5cbfSDavid du Colombier {
78780ee5cbfSDavid du Colombier return h->tok = lex1(h, 0);
78880ee5cbfSDavid du Colombier }
78980ee5cbfSDavid du Colombier
79080ee5cbfSDavid du Colombier static int
lexbase64(Hlex * h)79180ee5cbfSDavid du Colombier lexbase64(Hlex *h)
79280ee5cbfSDavid du Colombier {
79380ee5cbfSDavid du Colombier int c, n;
79480ee5cbfSDavid du Colombier
79580ee5cbfSDavid du Colombier n = 0;
79680ee5cbfSDavid du Colombier lex1(h, 1);
79780ee5cbfSDavid du Colombier
79880ee5cbfSDavid du Colombier while((c = getc(h)) >= 0){
799f9e1cf08SDavid du Colombier if(!isalnum(c) && c != '+' && c != '/'){
80080ee5cbfSDavid du Colombier ungetc(h);
80180ee5cbfSDavid du Colombier break;
80280ee5cbfSDavid du Colombier }
80380ee5cbfSDavid du Colombier if(n < HMaxWord-1)
80480ee5cbfSDavid du Colombier h->wordval[n++] = c;
80580ee5cbfSDavid du Colombier }
80680ee5cbfSDavid du Colombier h->wordval[n] = '\0';
80780ee5cbfSDavid du Colombier return n;
80880ee5cbfSDavid du Colombier }
80980ee5cbfSDavid du Colombier
81080ee5cbfSDavid du Colombier /*
81180ee5cbfSDavid du Colombier * rfc 822/rfc 1521 lexical analyzer
81280ee5cbfSDavid du Colombier */
81380ee5cbfSDavid du Colombier static int
lex1(Hlex * h,int skipwhite)81480ee5cbfSDavid du Colombier lex1(Hlex *h, int skipwhite)
81580ee5cbfSDavid du Colombier {
81680ee5cbfSDavid du Colombier int level, c;
81780ee5cbfSDavid du Colombier
81880ee5cbfSDavid du Colombier if(h->eol)
81980ee5cbfSDavid du Colombier return '\n';
82080ee5cbfSDavid du Colombier
82180ee5cbfSDavid du Colombier top:
82280ee5cbfSDavid du Colombier c = getc(h);
82380ee5cbfSDavid du Colombier switch(c){
82480ee5cbfSDavid du Colombier case '(':
82580ee5cbfSDavid du Colombier level = 1;
82680ee5cbfSDavid du Colombier while((c = getc(h)) >= 0){
82780ee5cbfSDavid du Colombier if(c == '\\'){
82880ee5cbfSDavid du Colombier c = getc(h);
82980ee5cbfSDavid du Colombier if(c < 0)
83080ee5cbfSDavid du Colombier return '\n';
83180ee5cbfSDavid du Colombier continue;
83280ee5cbfSDavid du Colombier }
83380ee5cbfSDavid du Colombier if(c == '(')
83480ee5cbfSDavid du Colombier level++;
83580ee5cbfSDavid du Colombier else if(c == ')' && --level == 0)
83680ee5cbfSDavid du Colombier break;
83780ee5cbfSDavid du Colombier else if(c == '\n'){
83880ee5cbfSDavid du Colombier c = getc(h);
83980ee5cbfSDavid du Colombier if(c < 0)
84080ee5cbfSDavid du Colombier return '\n';
84180ee5cbfSDavid du Colombier if(c == ')' && --level == 0)
84280ee5cbfSDavid du Colombier break;
84380ee5cbfSDavid du Colombier if(c != ' ' && c != '\t'){
84480ee5cbfSDavid du Colombier ungetc(h);
84580ee5cbfSDavid du Colombier return '\n';
84680ee5cbfSDavid du Colombier }
84780ee5cbfSDavid du Colombier }
84880ee5cbfSDavid du Colombier }
84980ee5cbfSDavid du Colombier goto top;
85080ee5cbfSDavid du Colombier
85180ee5cbfSDavid du Colombier case ' ': case '\t':
85280ee5cbfSDavid du Colombier goto top;
85380ee5cbfSDavid du Colombier
85480ee5cbfSDavid du Colombier case '\r':
85580ee5cbfSDavid du Colombier c = getc(h);
85680ee5cbfSDavid du Colombier if(c != '\n'){
85780ee5cbfSDavid du Colombier ungetc(h);
85880ee5cbfSDavid du Colombier goto top;
85980ee5cbfSDavid du Colombier }
86080ee5cbfSDavid du Colombier
86180ee5cbfSDavid du Colombier case '\n':
86280ee5cbfSDavid du Colombier if(h->tok == '\n'){
86380ee5cbfSDavid du Colombier h->eol = 1;
86480ee5cbfSDavid du Colombier h->eoh = 1;
86580ee5cbfSDavid du Colombier return '\n';
86680ee5cbfSDavid du Colombier }
86780ee5cbfSDavid du Colombier c = getc(h);
86880ee5cbfSDavid du Colombier if(c < 0){
86980ee5cbfSDavid du Colombier h->eol = 1;
87080ee5cbfSDavid du Colombier return '\n';
87180ee5cbfSDavid du Colombier }
87280ee5cbfSDavid du Colombier if(c != ' ' && c != '\t'){
87380ee5cbfSDavid du Colombier ungetc(h);
87480ee5cbfSDavid du Colombier h->eol = 1;
87580ee5cbfSDavid du Colombier return '\n';
87680ee5cbfSDavid du Colombier }
87780ee5cbfSDavid du Colombier goto top;
87880ee5cbfSDavid du Colombier
87980ee5cbfSDavid du Colombier case ')':
88080ee5cbfSDavid du Colombier case '<': case '>':
88180ee5cbfSDavid du Colombier case '[': case ']':
88280ee5cbfSDavid du Colombier case '@': case '/':
88380ee5cbfSDavid du Colombier case ',': case ';': case ':': case '?': case '=':
88480ee5cbfSDavid du Colombier if(skipwhite){
88580ee5cbfSDavid du Colombier ungetc(h);
88680ee5cbfSDavid du Colombier return c;
88780ee5cbfSDavid du Colombier }
88880ee5cbfSDavid du Colombier return c;
88980ee5cbfSDavid du Colombier
89080ee5cbfSDavid du Colombier case '"':
89180ee5cbfSDavid du Colombier if(skipwhite){
89280ee5cbfSDavid du Colombier ungetc(h);
89380ee5cbfSDavid du Colombier return c;
89480ee5cbfSDavid du Colombier }
89580ee5cbfSDavid du Colombier word(h, "\"");
89680ee5cbfSDavid du Colombier getc(h); /* skip the closing quote */
89780ee5cbfSDavid du Colombier return QString;
89880ee5cbfSDavid du Colombier
89980ee5cbfSDavid du Colombier default:
90080ee5cbfSDavid du Colombier ungetc(h);
90180ee5cbfSDavid du Colombier if(skipwhite)
90280ee5cbfSDavid du Colombier return c;
90380ee5cbfSDavid du Colombier word(h, "\"(){}<>@,;:/[]?=\r\n \t");
90480ee5cbfSDavid du Colombier if(h->wordval[0] == '\0'){
90580ee5cbfSDavid du Colombier h->c->head.closeit = 1;
90680ee5cbfSDavid du Colombier hfail(h->c, HSyntax);
90780ee5cbfSDavid du Colombier longjmp(h->jmp, -1);
90880ee5cbfSDavid du Colombier }
90980ee5cbfSDavid du Colombier return Word;
91080ee5cbfSDavid du Colombier }
911b85a8364SDavid du Colombier /* not reached */
91280ee5cbfSDavid du Colombier }
91380ee5cbfSDavid du Colombier
91480ee5cbfSDavid du Colombier /*
91580ee5cbfSDavid du Colombier * return the rest of an rfc 822, including \n
91680ee5cbfSDavid du Colombier * do not map to lower case
91780ee5cbfSDavid du Colombier */
91880ee5cbfSDavid du Colombier static void
lexhead(Hlex * h)91980ee5cbfSDavid du Colombier lexhead(Hlex *h)
92080ee5cbfSDavid du Colombier {
92180ee5cbfSDavid du Colombier int c, n;
92280ee5cbfSDavid du Colombier
92380ee5cbfSDavid du Colombier n = 0;
92480ee5cbfSDavid du Colombier while((c = getc(h)) >= 0){
92580ee5cbfSDavid du Colombier if(c == '\r')
92680ee5cbfSDavid du Colombier c = wordcr(h);
92780ee5cbfSDavid du Colombier else if(c == '\n')
92880ee5cbfSDavid du Colombier c = wordnl(h);
92980ee5cbfSDavid du Colombier if(c == '\n')
93080ee5cbfSDavid du Colombier break;
93180ee5cbfSDavid du Colombier if(c == '\\'){
93280ee5cbfSDavid du Colombier c = getc(h);
93380ee5cbfSDavid du Colombier if(c < 0)
93480ee5cbfSDavid du Colombier break;
93580ee5cbfSDavid du Colombier }
93680ee5cbfSDavid du Colombier
93780ee5cbfSDavid du Colombier if(n < HMaxWord-1)
93880ee5cbfSDavid du Colombier h->wordval[n++] = c;
93980ee5cbfSDavid du Colombier }
94080ee5cbfSDavid du Colombier h->tok = '\n';
94180ee5cbfSDavid du Colombier h->eol = 1;
94280ee5cbfSDavid du Colombier h->wordval[n] = '\0';
94380ee5cbfSDavid du Colombier }
94480ee5cbfSDavid du Colombier
94580ee5cbfSDavid du Colombier static void
word(Hlex * h,char * stop)94680ee5cbfSDavid du Colombier word(Hlex *h, char *stop)
94780ee5cbfSDavid du Colombier {
94880ee5cbfSDavid du Colombier int c, n;
94980ee5cbfSDavid du Colombier
95080ee5cbfSDavid du Colombier n = 0;
95180ee5cbfSDavid du Colombier while((c = getc(h)) >= 0){
95280ee5cbfSDavid du Colombier if(c == '\r')
95380ee5cbfSDavid du Colombier c = wordcr(h);
95480ee5cbfSDavid du Colombier else if(c == '\n')
95580ee5cbfSDavid du Colombier c = wordnl(h);
95680ee5cbfSDavid du Colombier if(c == '\\'){
95780ee5cbfSDavid du Colombier c = getc(h);
95880ee5cbfSDavid du Colombier if(c < 0)
95980ee5cbfSDavid du Colombier break;
96080ee5cbfSDavid du Colombier }else if(c < 32 || strchr(stop, c) != nil){
96180ee5cbfSDavid du Colombier ungetc(h);
96280ee5cbfSDavid du Colombier break;
96380ee5cbfSDavid du Colombier }
96480ee5cbfSDavid du Colombier
96580ee5cbfSDavid du Colombier if(n < HMaxWord-1)
96680ee5cbfSDavid du Colombier h->wordval[n++] = c;
96780ee5cbfSDavid du Colombier }
96880ee5cbfSDavid du Colombier h->wordval[n] = '\0';
96980ee5cbfSDavid du Colombier }
97080ee5cbfSDavid du Colombier
97180ee5cbfSDavid du Colombier static int
wordcr(Hlex * h)97280ee5cbfSDavid du Colombier wordcr(Hlex *h)
97380ee5cbfSDavid du Colombier {
97480ee5cbfSDavid du Colombier int c;
97580ee5cbfSDavid du Colombier
97680ee5cbfSDavid du Colombier c = getc(h);
97780ee5cbfSDavid du Colombier if(c == '\n')
97880ee5cbfSDavid du Colombier return wordnl(h);
97980ee5cbfSDavid du Colombier ungetc(h);
98080ee5cbfSDavid du Colombier return ' ';
98180ee5cbfSDavid du Colombier }
98280ee5cbfSDavid du Colombier
98380ee5cbfSDavid du Colombier static int
wordnl(Hlex * h)98480ee5cbfSDavid du Colombier wordnl(Hlex *h)
98580ee5cbfSDavid du Colombier {
98680ee5cbfSDavid du Colombier int c;
98780ee5cbfSDavid du Colombier
98880ee5cbfSDavid du Colombier c = getc(h);
98980ee5cbfSDavid du Colombier if(c == ' ' || c == '\t')
99080ee5cbfSDavid du Colombier return c;
99180ee5cbfSDavid du Colombier ungetc(h);
99280ee5cbfSDavid du Colombier
99380ee5cbfSDavid du Colombier return '\n';
99480ee5cbfSDavid du Colombier }
99580ee5cbfSDavid du Colombier
99680ee5cbfSDavid du Colombier static int
getc(Hlex * h)99780ee5cbfSDavid du Colombier getc(Hlex *h)
99880ee5cbfSDavid du Colombier {
99980ee5cbfSDavid du Colombier if(h->eoh)
100080ee5cbfSDavid du Colombier return -1;
100180ee5cbfSDavid du Colombier if(h->c->hpos < h->c->hstop)
100280ee5cbfSDavid du Colombier return *h->c->hpos++;
100380ee5cbfSDavid du Colombier h->eoh = 1;
100480ee5cbfSDavid du Colombier h->eol = 1;
100580ee5cbfSDavid du Colombier return -1;
100680ee5cbfSDavid du Colombier }
100780ee5cbfSDavid du Colombier
100880ee5cbfSDavid du Colombier static void
ungetc(Hlex * h)100980ee5cbfSDavid du Colombier ungetc(Hlex *h)
101080ee5cbfSDavid du Colombier {
101180ee5cbfSDavid du Colombier if(h->eoh)
101280ee5cbfSDavid du Colombier return;
101380ee5cbfSDavid du Colombier h->c->hpos--;
101480ee5cbfSDavid du Colombier }
101580ee5cbfSDavid du Colombier
101680ee5cbfSDavid du Colombier static ulong
digtoul(char * s,char ** e)101780ee5cbfSDavid du Colombier digtoul(char *s, char **e)
101880ee5cbfSDavid du Colombier {
101980ee5cbfSDavid du Colombier ulong v;
102080ee5cbfSDavid du Colombier int c, ovfl;
102180ee5cbfSDavid du Colombier
102280ee5cbfSDavid du Colombier v = 0;
102380ee5cbfSDavid du Colombier ovfl = 0;
102480ee5cbfSDavid du Colombier for(;;){
102580ee5cbfSDavid du Colombier c = *s;
102680ee5cbfSDavid du Colombier if(c < '0' || c > '9')
102780ee5cbfSDavid du Colombier break;
102880ee5cbfSDavid du Colombier s++;
102980ee5cbfSDavid du Colombier c -= '0';
103080ee5cbfSDavid du Colombier if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10)
103180ee5cbfSDavid du Colombier ovfl = 1;
103280ee5cbfSDavid du Colombier v = v * 10 + c;
103380ee5cbfSDavid du Colombier }
103480ee5cbfSDavid du Colombier
103580ee5cbfSDavid du Colombier if(e)
103680ee5cbfSDavid du Colombier *e = s;
103780ee5cbfSDavid du Colombier if(ovfl)
103880ee5cbfSDavid du Colombier return UlongMax;
103980ee5cbfSDavid du Colombier return v;
104080ee5cbfSDavid du Colombier }
104180ee5cbfSDavid du Colombier
104280ee5cbfSDavid du Colombier int
http11(HConnect * c)104380ee5cbfSDavid du Colombier http11(HConnect *c)
104480ee5cbfSDavid du Colombier {
104580ee5cbfSDavid du Colombier return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
104680ee5cbfSDavid du Colombier }
104780ee5cbfSDavid du Colombier
104880ee5cbfSDavid du Colombier char*
hmkmimeboundary(HConnect * c)104980ee5cbfSDavid du Colombier hmkmimeboundary(HConnect *c)
105080ee5cbfSDavid du Colombier {
105180ee5cbfSDavid du Colombier char buf[32];
105280ee5cbfSDavid du Colombier int i;
105380ee5cbfSDavid du Colombier
105480ee5cbfSDavid du Colombier srand((time(0)<<16)|getpid());
105580ee5cbfSDavid du Colombier strcpy(buf, "upas-");
105680ee5cbfSDavid du Colombier for(i = 5; i < sizeof(buf)-1; i++)
105780ee5cbfSDavid du Colombier buf[i] = 'a' + nrand(26);
105880ee5cbfSDavid du Colombier buf[i] = 0;
105980ee5cbfSDavid du Colombier return hstrdup(c, buf);
106080ee5cbfSDavid du Colombier }
106180ee5cbfSDavid du Colombier
106280ee5cbfSDavid du Colombier HSPairs*
hmkspairs(HConnect * c,char * s,char * t,HSPairs * next)106380ee5cbfSDavid du Colombier hmkspairs(HConnect *c, char *s, char *t, HSPairs *next)
106480ee5cbfSDavid du Colombier {
106580ee5cbfSDavid du Colombier HSPairs *sp;
106680ee5cbfSDavid du Colombier
106780ee5cbfSDavid du Colombier sp = halloc(c, sizeof *sp);
106880ee5cbfSDavid du Colombier sp->s = s;
106980ee5cbfSDavid du Colombier sp->t = t;
107080ee5cbfSDavid du Colombier sp->next = next;
107180ee5cbfSDavid du Colombier return sp;
107280ee5cbfSDavid du Colombier }
107380ee5cbfSDavid du Colombier
107480ee5cbfSDavid du Colombier HSPairs*
hrevspairs(HSPairs * sp)107580ee5cbfSDavid du Colombier hrevspairs(HSPairs *sp)
107680ee5cbfSDavid du Colombier {
107780ee5cbfSDavid du Colombier HSPairs *last, *next;
107880ee5cbfSDavid du Colombier
107980ee5cbfSDavid du Colombier last = nil;
108080ee5cbfSDavid du Colombier for(; sp != nil; sp = next){
108180ee5cbfSDavid du Colombier next = sp->next;
108280ee5cbfSDavid du Colombier sp->next = last;
108380ee5cbfSDavid du Colombier last = sp;
108480ee5cbfSDavid du Colombier }
108580ee5cbfSDavid du Colombier return last;
108680ee5cbfSDavid du Colombier }
108780ee5cbfSDavid du Colombier
108880ee5cbfSDavid du Colombier HFields*
hmkhfields(HConnect * c,char * s,HSPairs * p,HFields * next)108980ee5cbfSDavid du Colombier hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next)
109080ee5cbfSDavid du Colombier {
109180ee5cbfSDavid du Colombier HFields *hf;
109280ee5cbfSDavid du Colombier
109380ee5cbfSDavid du Colombier hf = halloc(c, sizeof *hf);
109480ee5cbfSDavid du Colombier hf->s = s;
109580ee5cbfSDavid du Colombier hf->params = p;
109680ee5cbfSDavid du Colombier hf->next = next;
109780ee5cbfSDavid du Colombier return hf;
109880ee5cbfSDavid du Colombier }
109980ee5cbfSDavid du Colombier
110080ee5cbfSDavid du Colombier HFields*
hrevhfields(HFields * hf)110180ee5cbfSDavid du Colombier hrevhfields(HFields *hf)
110280ee5cbfSDavid du Colombier {
110380ee5cbfSDavid du Colombier HFields *last, *next;
110480ee5cbfSDavid du Colombier
110580ee5cbfSDavid du Colombier last = nil;
110680ee5cbfSDavid du Colombier for(; hf != nil; hf = next){
110780ee5cbfSDavid du Colombier next = hf->next;
110880ee5cbfSDavid du Colombier hf->next = last;
110980ee5cbfSDavid du Colombier last = hf;
111080ee5cbfSDavid du Colombier }
111180ee5cbfSDavid du Colombier return last;
111280ee5cbfSDavid du Colombier }
111380ee5cbfSDavid du Colombier
111480ee5cbfSDavid du Colombier HContent*
hmkcontent(HConnect * c,char * generic,char * specific,HContent * next)111580ee5cbfSDavid du Colombier hmkcontent(HConnect *c, char *generic, char *specific, HContent *next)
111680ee5cbfSDavid du Colombier {
111780ee5cbfSDavid du Colombier HContent *ct;
111880ee5cbfSDavid du Colombier
111980ee5cbfSDavid du Colombier ct = halloc(c, sizeof(HContent));
112080ee5cbfSDavid du Colombier ct->generic = generic;
112180ee5cbfSDavid du Colombier ct->specific = specific;
112280ee5cbfSDavid du Colombier ct->next = next;
112380ee5cbfSDavid du Colombier ct->q = 1;
112480ee5cbfSDavid du Colombier ct->mxb = 0;
112580ee5cbfSDavid du Colombier return ct;
112680ee5cbfSDavid du Colombier }
1127