#include #include #include "global.h" #include "url.h" /* [scheme[p://] [host[:port]] [/path] [?query] */ /******************************************************************************* URL processing URLs start their life as strings from the user or links embedded in gmi files. sUrl structure encapsulate a local copy of the URL and facilitate normalization. An sUrl may be initialized in one of the following ways: * copied from another sUrl; * set from a full sUrl; * set from a partial url using another, base sUrl. It is processed in order to set internal component offsets. It is normalized to eliminate . and .. components. Notes: port is tracked as an actual port and not an offset! oFile is used only for base sUrls, and is normally not searched/initialized. ******************************************************************************/ int url_is_spartan(char* url){ return !(strncmp("spartan://",url,10)); } int url_is_full(char* url){ return (NULL != strstr(url,"://")); } char* sUrl_path(sUrl* purl){ return purl->buf + purl->oPath; } U16 sUrl_port(sUrl* purl){ return purl->port; } /******************************************************************************* print the sUrl ******************************************************************************/ void sUrl_dump(sUrl* purl){ printf("sUrl at %p\n",purl); int ohost = purl->oHost; int opath = purl->oPath; char* buf = purl->buf; if(opath){ printf("scheme: %*.*s\n",ohost,ohost,buf); printf("host: %*.*s\n",opath-ohost,opath-ohost,buf+ohost); printf("port: %d\n",purl->port); printf("path: %s\n",buf+opath); } else { printf("invalid:[%s]\n",buf); } } // fputs(purl->buf,f); /******************************************************************************* Set the sUrl to the string fragment provided. The sUrl is reset and needs further processing! ******************************************************************************/ int sUrl_set(sUrl*p,char*str,U32 len){ if(!len) len = strlen(str); if (len > URL_MAX) return 1; // didn't fit p->oHost = 0; p->oPath = 0; p->oFile = 0; p->port = 300; strncpy(p->buf,str,len); p->buf[len]=0; return 0; } /******************************************************************************* Copy the src sUrl into the destingation sUrl, along with all components. ******************************************************************************/ sUrl* sUrl_copy(sUrl* dst, sUrl* src){ memcpy(dst,src,sizeof(sUrl)); return dst; } /******************************************************************************* file Return the pointer to the file component of this URL, and set the internal offset. ******************************************************************************/ char* sUrl_file(sUrl*p){ char* pfile = strrchr(p->buf,'/') + 1; p->oFile = pfile - (p->buf); return pfile; } U32 host_port(char* p){ char c; do { c=*p++; if(!c) return 300; // at end? default if('/'==c) return 300; // at /? default if(':'==c) break; // at : parse } while (1); U32 val = 0; while((c=*p++)) { c-= '0'; if( (c<0) || (c>9)) return 0; //invalid port val = (val * 10) + c; } return val; } /******************************************************************************* full - parse the buffer of this sUrl to set the internal offsets (but not file), assuming a full URL (it must have a ://). Return: 0 on success; 1 if not a full URL. ******************************************************************************/ /* url_do_full -- Try to parse a full URL */ // int sUrl_full(sUrl* purl){ char* p = strstr(purl->buf,"://"); //if scheme is there it ends with spartan|://|host|/| if(!p) return 1; //no scheme sigil = error! p+=3; U32 port = host_port(p); if(!p) return 1; //invalid port purl->port = port; purl->oHost = p-(purl->buf); char* path = strchr(p+3,'/'); //host ends with a /path if(!path) { // if no path provided, path = p + 3 + (strlen(p+3)); *path = '/'; *(path+1)=0; } purl->oPath = path - purl->buf; return 0; } /******************************************************************************* rel - given a base sUrl and a string with local url, mutate sUrl into a full rul ******************************************************************************/ void sUrl_rel(sUrl*base,char* str,U32 len){ char* dst = base->buf + (('/'==*str) ? base->oPath : base->oFile); strncpy(dst,str,len); dst[len]=0; } /******************************************************************************* norm - given a full but not canonical sUrl, process to eliminate ./ and ../ return: 0 success 1 error ******************************************************************************/ // backup from p to the previous '/' char* _norm_backup(char* p,char* start){ while(--p >= start) if('/'==*p) return p; return NULL; } int sUrl_norm(sUrl* purl){ char* start = purl->buf + purl->oPath; char* src = start; char* dst = start; //printf("normalizing[%s]\n",src); char c; while((c = (*dst++ = *src++))){ // printf("c=%c[%s]\n",c,src-1); if('/'==c){ if(!strncmp(src,"../",3)){ if(!(dst = _norm_backup(dst-1,start))) return 1; else src += 2; //src and dest at respecive '/'s } else if(!strncmp(src,"./",2)) { src += 2; } else if(!strcmp(src,"..")){ if(!(dst = _norm_backup(dst-1,start))) return 2; dst++; // leave the slash src += 2; *dst++=0; // printf("src:[%s]; dst:[%s];\n",src,dst); } else if(!strcmp(src,".")){ *dst++=0; } } } *start = '/'; // printf("postnorm[%s]\n",start); return 0; } /******************************************************************************* ******************************************************************************/ U32 sUrl_host_length(sUrl* purl){ return (purl->oPath - purl->oHost); } /* char URL_base[1024]; int baselen; int bhost_off; int bpath_off; */ /* char buf[2048]; char* scheme; char* host; char* path; int url_make_base(){ strcpy(URL_base,scheme); baselen = strlen(URL_base); bhost_off = host - scheme; bpath_off = path - scheme; return 0; } int url_do_part(char*src){ scheme = src-baselen; strncpy(scheme,URL_base,baselen); host = scheme + bhost_off; path = scheme + bpath_off; return 0; } */ /* url_do_full -- Try to parse a full URL */ /* int url_do_full(char*src){ char* p = strstr(src,"://"); //if scheme is there it ends with spartan|://|host|/| if(!p) return 1; //no scheme sigil = error! scheme = src; //scheme at start host = p+3; //host starts after :// path = strchr(host,'/'); //host ends with a /path if(!path) { // if no path provided, int i = strlen(host); // append a '/' and make one. path = host+i; *path='/'; *(path+1)=0; } return 0; } //int url_is_full(char*src){ char* path_norm(char* path){ *(path-1) = 0; char* src = path; char* dst = path; char c; while((c=(*dst++ = *src++))){ if('/'==c){ if(!strncmp(src,"../",3)){ if(!(dst = path_backup(dst-1))) return NULL; src += 2; } else if(!strncmp(src,"./",2)) { src += 2; } else if(!strcmp(src,"..")){ if(!(dst = path_backup(dst-1))) return NULL; dst++; // leave the slash src += 2; // printf("src:[%s]; dst:[%s];\n",src,dst); } else if(!strcmp(src,".")){ src++; } } } return path; } */ /* int main(int argc,char**argv) { sUrl base; sUrl_set(&base,"spartan://192.168.0.2:8888/servlet/rece/holo"); sUrl_full(&base); printf("FILE: %s\n",sUrl_file(&base)); sUrl url; sUrl_copy(&url, &base); sUrl_rel(&url,argv[1]); int q = sUrl_norm(&url); printf("normalize returned %d\n",q); sUrl_print(&url); return 0; // strcpy(URL_base,"spartan://192.168.0.2:8888/servlet/rece/"); //baselen = strlen(URL_base); //bhost_off = 10; //bpath_off = 26; */ /* memset(buf,0,2048); strcpy(buf+256,argv[1]); q = url_do_full(buf+256); int lScheme = (int)(host-scheme); printf("Returned %d\n",q); printf("scheme: %*.*s\n",lScheme,lScheme,scheme); printf("host: %s\n",host); printf("path: %s\n",path); */ // char* p = path_norm(path); //printf("norm: %s\n",p); //}