spa/url.c

351 lines
8.3 KiB
C

#include <stdio.h>
#include <string.h>
#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);
//}