URI:
       tparsereq.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tparsereq.c (5112B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bin.h>
            4 #include <httpd.h>
            5 
            6 typedef struct Strings                Strings;
            7 
            8 struct Strings
            9 {
           10         char        *s1;
           11         char        *s2;
           12 };
           13 
           14 static        char*                abspath(HConnect *cc, char *origpath, char *curdir);
           15 static        int                getc(HConnect*);
           16 static        char*                getword(HConnect*);
           17 static        Strings                parseuri(HConnect *c, char*);
           18 static        Strings                stripsearch(char*);
           19 
           20 /*
           21  * parse the next request line
           22  * returns:
           23  *        1 ok
           24  *        0 eof
           25  *        -1 error
           26  */
           27 int
           28 hparsereq(HConnect *c, int timeout)
           29 {
           30         Strings ss;
           31         char *vs, *v, *search, *uri, *origuri, *extra;
           32 
           33         if(c->bin != nil){
           34                 hfail(c, HInternal);
           35                 return -1;
           36         }
           37 
           38         /*
           39          * serve requests until a magic request.
           40          * later requests have to come quickly.
           41          * only works for http/1.1 or later.
           42          */
           43         if(timeout)
           44                 alarm(timeout);
           45         if(hgethead(c, 0) < 0)
           46                 return -1;
           47         if(timeout)
           48                 alarm(0);
           49         c->reqtime = time(nil);
           50         c->req.meth = getword(c);
           51         if(c->req.meth == nil){
           52                 hfail(c, HSyntax);
           53                 return -1;
           54         }
           55         uri = getword(c);
           56         if(uri == nil || strlen(uri) == 0){
           57                 hfail(c, HSyntax);
           58                 return -1;
           59         }
           60         v = getword(c);
           61         if(v == nil){
           62                 if(strcmp(c->req.meth, "GET") != 0){
           63                         hfail(c, HUnimp, c->req.meth);
           64                         return -1;
           65                 }
           66                 c->req.vermaj = 0;
           67                 c->req.vermin = 9;
           68         }else{
           69                 vs = v;
           70                 if(strncmp(vs, "HTTP/", 5) != 0){
           71                         hfail(c, HUnkVers, vs);
           72                         return -1;
           73                 }
           74                 vs += 5;
           75                 c->req.vermaj = strtoul(vs, &vs, 10);
           76                 if(*vs != '.' || c->req.vermaj != 1){
           77                         hfail(c, HUnkVers, vs);
           78                         return -1;
           79                 }
           80                 vs++;
           81                 c->req.vermin = strtoul(vs, &vs, 10);
           82                 if(*vs != '\0'){
           83                         hfail(c, HUnkVers, vs);
           84                         return -1;
           85                 }
           86 
           87                 extra = getword(c);
           88                 if(extra != nil){
           89                         hfail(c, HSyntax);
           90                         return -1;
           91                 }
           92         }
           93 
           94         /*
           95          * the fragment is not supposed to be sent
           96          * strip it 'cause some clients send it
           97          */
           98         origuri = uri;
           99         uri = strchr(origuri, '#');
          100         if(uri != nil)
          101                 *uri = 0;
          102 
          103         /*
          104          * http/1.1 requires the server to accept absolute
          105          * or relative uri's.  convert to relative with an absolute path
          106          */
          107         if(http11(c)){
          108                 ss = parseuri(c, origuri);
          109                 uri = ss.s1;
          110                 c->req.urihost = ss.s2;
          111                 if(uri == nil){
          112                         hfail(c, HBadReq, uri);
          113                         return -1;
          114                 }
          115                 origuri = uri;
          116         }
          117 
          118         /*
          119          * munge uri for search, protection, and magic
          120          */
          121         ss = stripsearch(origuri);
          122         origuri = ss.s1;
          123         search = ss.s2;
          124         uri = hurlunesc(c, origuri);
          125         uri = abspath(c, uri, "/");
          126         if(uri == nil || uri[0] == '\0'){
          127                 hfail(c, HNotFound, "no object specified");
          128                 return -1;
          129         }
          130 
          131         c->req.uri = uri;
          132         c->req.search = search;
          133         if(search)
          134                 c->req.searchpairs = hparsequery(c, hstrdup(c, search));
          135 
          136         return 1;
          137 }
          138 
          139 static Strings
          140 parseuri(HConnect *c, char *uri)
          141 {
          142         Strings ss;
          143         char *urihost, *p;
          144 
          145         urihost = nil;
          146         if(uri[0] != '/'){
          147                 if(cistrncmp(uri, "http://", 7) != 0){
          148                         ss.s1 = nil;
          149                         ss.s2 = nil;
          150                         return ss;
          151                 }
          152                 uri += 5;        /* skip http: */
          153         }
          154 
          155         /*
          156          * anything starting with // is a host name or number
          157          * hostnames consists of letters, digits, - and .
          158          * for now, just ignore any port given
          159          */
          160         if(uri[0] == '/' && uri[1] == '/'){
          161                 urihost = uri + 2;
          162                 p = strchr(urihost, '/');
          163                 if(p == nil)
          164                         uri = hstrdup(c, "/");
          165                 else{
          166                         uri = hstrdup(c, p);
          167                         *p = '\0';
          168                 }
          169                 p = strchr(urihost, ':');
          170                 if(p != nil)
          171                         *p = '\0';
          172         }
          173 
          174         if(uri[0] != '/' || uri[1] == '/'){
          175                 ss.s1 = nil;
          176                 ss.s2 = nil;
          177                 return ss;
          178         }
          179 
          180         ss.s1 = uri;
          181         ss.s2 = hlower(urihost);
          182         return ss;
          183 }
          184 static Strings
          185 stripsearch(char *uri)
          186 {
          187         Strings ss;
          188         char *search;
          189 
          190         search = strchr(uri, '?');
          191         if(search != nil)
          192                 *search++ = 0;
          193         ss.s1 = uri;
          194         ss.s2 = search;
          195         return ss;
          196 }
          197 
          198 /*
          199  *  to circumscribe the accessible files we have to eliminate ..'s
          200  *  and resolve all names from the root.
          201  */
          202 static char*
          203 abspath(HConnect *cc, char *origpath, char *curdir)
          204 {
          205         char *p, *sp, *path, *work, *rpath;
          206         int len, n, c;
          207 
          208         if(curdir == nil)
          209                 curdir = "/";
          210         if(origpath == nil)
          211                 origpath = "";
          212         work = hstrdup(cc, origpath);
          213         path = work;
          214 
          215         /*
          216          * remove any really special characters
          217          */
          218         for(sp = "`;| "; *sp; sp++){
          219                 p = strchr(path, *sp);
          220                 if(p)
          221                         *p = 0;
          222         }
          223 
          224         len = strlen(curdir) + strlen(path) + 2 + UTFmax;
          225         if(len < 10)
          226                 len = 10;
          227         rpath = halloc(cc, len);
          228         if(*path == '/')
          229                 rpath[0] = 0;
          230         else
          231                 strcpy(rpath, curdir);
          232         n = strlen(rpath);
          233 
          234         while(path){
          235                 p = strchr(path, '/');
          236                 if(p)
          237                         *p++ = 0;
          238                 if(strcmp(path, "..") == 0){
          239                         while(n > 1){
          240                                 n--;
          241                                 c = rpath[n];
          242                                 rpath[n] = 0;
          243                                 if(c == '/')
          244                                         break;
          245                         }
          246                 }else if(strcmp(path, ".") == 0){
          247                         ;
          248                 }else if(n == 1)
          249                         n += snprint(rpath+n, len-n, "%s", path);
          250                 else
          251                         n += snprint(rpath+n, len-n, "/%s", path);
          252                 path = p;
          253         }
          254 
          255         if(strncmp(rpath, "/bin/", 5) == 0)
          256                 strcpy(rpath, "/");
          257         return rpath;
          258 }
          259 
          260 static char*
          261 getword(HConnect *c)
          262 {
          263         char *buf;
          264         int ch, n;
          265 
          266         while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r')
          267                 ;
          268         if(ch == '\n')
          269                 return nil;
          270         n = 0;
          271         buf = halloc(c, 1);
          272         for(;;){
          273                 switch(ch){
          274                 case ' ':
          275                 case '\t':
          276                 case '\r':
          277                 case '\n':
          278                         buf[n] = '\0';
          279                         return hstrdup(c, buf);
          280                 }
          281 
          282                 if(n < HMaxWord-1){
          283                         buf = bingrow(&c->bin, buf, n, n + 1, 0);
          284                         if(buf == nil)
          285                                 return nil;
          286                         buf[n++] = ch;
          287                 }
          288                 ch = getc(c);
          289         }
          290 }
          291 
          292 static int
          293 getc(HConnect *c)
          294 {
          295         if(c->hpos < c->hstop)
          296                 return *c->hpos++;
          297         return '\n';
          298 }