示例#1
0
文件: ncuri.c 项目: SiggyF/netcdf-c
/* Do a simple uri parse: return 0 if fail, 1 otherwise*/
int
ncuriparse(const char* uri0, NCURI** durip)
{
    NCURI* duri = NULL;
    char* uri = NULL;
    char* p;
    struct NC_ProtocolInfo* proto;
    int i,nprotos;

    /* accumulate parse points*/
    char* protocol = NULL;
    char* host = NULL;
    char* port = NULL;
    char* constraint = NULL;
    char* user = NULL;
    char* pwd = NULL;
    char* file = NULL;
    char* prefixparams = NULL;
    char* suffixparams = NULL;

    if(uri0 == NULL || strlen(uri0) == 0)
	{THROW(1); goto fail;}

    duri = (NCURI*)calloc(1,sizeof(NCURI));
    if(duri == NULL)
	{THROW(2); goto fail;}
	
    /* save original uri */
    duri->uri = nulldup(uri0);

    /* make local copy of uri */
    uri = (char*)malloc(strlen(uri0)+1+PADDING); /* +1 for trailing null,
                                                    +PADDING for shifting */
    if(uri == NULL)
	{THROW(3); goto fail;}

    /* strings will be broken into pieces with intermixed '\0; characters;
       first char is guaranteed to be '\0' */

    duri->strings = uri;
    uri++; 

    /* dup the incoming url */
    strcpy(uri,uri0);

    /* Walk the uri and do the following:
	1. remove all whitespace
	2. remove all '\\' (Temp hack to remove escape characters
                            inserted by Windows or MinGW)
    */
    for(p=uri;*p;p++) {
	if(*p == '\\' || *p < ' ')
	    nclshift1(p); /* compress out */
    }	

    p = uri;

    /* break up the uri string into big chunks: prefixparams, protocol,
       host section, and the file section (i.e. remainder)
    */

    /* collect any prefix bracketed parameters */
    if(*p == LBRACKET) {
	prefixparams = p+1;
	/* find end of the clientparams; convert LB,RB to '&' */
        for(;*p;p++) {
	    if(p[0] == RBRACKET && p[1] == LBRACKET) {
		p[0] = '&';
		nclshift1(p+1);
	    } else if(p[0] == RBRACKET && p[1] != LBRACKET)
		break;
	}
	if(*p == 0)
	    {THROW(4); goto fail; /* malformed client params*/}
        terminate(p); /* nul term the prefixparams (overwrites
                         the final RBRACKET) */
	p++; /* move past the final RBRACKET */
    }

    /* Tag the protocol */
    protocol = p;    
    p = strchr(p,':');
    if(!p)
	{THROW(5); goto fail;}
    terminate(p); /*overwrite colon*/
    p++; /* skip the colon */

    /* verify that the uri starts with an acceptable protocol*/
    nprotos = (sizeof(legalprotocols)/sizeof(struct NC_ProtocolInfo));
    proto = NULL;
    for(i=0;i<nprotos;i++) {
        if(strcmp(protocol,legalprotocols[i].name)==0) {
	    proto = &legalprotocols[i];
	    break;	    
	}
    }
    if(proto == NULL)
	{THROW(6); goto fail; /* illegal protocol*/}

    /* skip // */
    if(p[0] != '/' && p[1] != '/')
	{THROW(7); goto fail;}
    p += 2;

    /* If this is all we have (proto://) then fail */
    if(*p == EOFCHAR)
	{THROW(8); goto fail;}

    /* establish the start of the file section */
    if(proto->filelike) {/* everything after proto:// */
	file = p;
	host = NULL; /* and no host section */
    } else { /*!proto->filelike => This means there should be a host section */
        /* locate the end of the host section and therefore the start
           of the file section */
	host = p;
        p  = nclocate(p,"/?#");
	if(p == NULL) {
	    file = endof(host); /* there is no file section */
	} else {
	    ncrshift1(p); /* make room to terminate the host section
                             without overwriting the leading character */
	    terminate(p); /* terminate the host section */
	    file = p+1; /* +1 becauseof the shift */
	}
    }
    
    /* If you shift in the code below, you must reset file beginning */

    if(host != NULL) {/* Parse the host section */
	/* Check for leading user:pwd@ */
        p = strchr(host,'@');
        if(p) {
	    if(p == host)
		{THROW(9); goto fail; /* we have proto://@ */}
	    user = host;
	    terminate(p); /* overwrite '@' */
	    host = p+1; /* start of host ip name */
	    p = strchr(user,':');
 	    if(p == NULL)
		{THROW(10); goto fail; /* malformed */}
	    terminate(p); /*overwrite colon */
	    pwd = p+1;
	}

        /* extract host and port */
	p = host;
        p = strchr(p,':');
        if(p != NULL) {
	    terminate(p);
	    p++;
	    port = p;
	    if(*port == EOFCHAR)
		{THROW(11); goto fail; /* we have proto://...:/ */}
	    /* The port must look something like a number */
	    for(;*p;p++) {
	        if(strchr("0123456789-",*p) == NULL)
		    {THROW(12); goto fail;  /* probably not a real port, fail */}
	    }
	} /* else *p == NULL */


        /* check for empty host section */
	if(*host == EOFCHAR)
	    {THROW(13); goto fail;}

    }

    assert(file != NULL);
    p = file;

    /* find the end of the file section and the start of the
       constraints and/or suffixparams
    */
    p = nclocate(p,"?#");
    if(p != NULL) { /* we have constraint and/or suffixparams */
	char* fileend = p; /* save the end of the file section */
	char* constraintend = NULL; 
	if(*p == '?')
            constraint = p+1;
	else
	    constraint = NULL;
	p = strchr(p,'#'); /* may repeat effect of nclocate above */
	if(p != NULL) {
	    constraintend = p;
	    suffixparams = p+1;
	} else
	    suffixparams = NULL;
	/* Ok, terminate the pieces */
	terminate(fileend); /* terminate file section */
	if(constraint != NULL && constraintend != NULL)
	    terminate(constraintend);
	/* Suffix params are already terminated
           since they should be the last section
           of the original url
        */
    }

    /* check for empty sections */
    if(file != NULL && *file == EOFCHAR)
	file = NULL; /* empty file section */
    if(constraint != NULL && *constraint == EOFCHAR)
	constraint = NULL; /* empty constraint section */
    if(suffixparams != NULL && *suffixparams == EOFCHAR)
	suffixparams = NULL; /* empty suffixparams section */

    if(suffixparams != NULL) {
	/* there really are suffix params; so rebuild the suffix params */
	if(*suffixparams == LBRACKET) suffixparams++;
        p = suffixparams;
	/* convert RBRACKET LBRACKET to '&' */
        for(;*p;p++) {
	    if(p[0] == RBRACKET && p[1] == LBRACKET) {
	        p[0] = '&';
		nclshift1(p+1);
	    } else if(p[0] == RBRACKET && p[1] != LBRACKET) {
		/* terminate suffixparams */
		*p = EOFCHAR;
		break;
	    }
	}
	if(*suffixparams == EOFCHAR)
	    suffixparams = NULL; /* suffixparams are empty */
    }

    /* do last minute empty check */
    
    if(protocol != NULL && *protocol == EOFCHAR) protocol = NULL;
    if(user != NULL && *user == EOFCHAR) user = NULL;
    if(pwd != NULL && *pwd == EOFCHAR) pwd = NULL;
    if(host != NULL && *host == EOFCHAR) host = NULL;
    if(port != NULL && *port == EOFCHAR) port = NULL;
    if(file != NULL && *file == EOFCHAR) file = NULL;
    if(constraint != NULL && *constraint == EOFCHAR) constraint = NULL;

    /* assemble the component pieces */
    duri->protocol = protocol;
    duri->user = user;
    duri->password = pwd;
    duri->host = host;
    duri->port = port;
    duri->file = file;

    ncurisetconstraints(duri,constraint);

    /* concat suffix and prefix params */
    if(prefixparams != NULL || suffixparams != NULL) {
	int plen = prefixparams ? strlen(prefixparams) : 0;
	int slen = suffixparams ? strlen(suffixparams) : 0;
	int space = plen + slen + 1;
	/* add 1 for an extra ampersand if both are defined */
        space++;
        duri->params = (char*)malloc(space);
	duri->params[0] = EOFCHAR; /* so we can use strcat */
	if(plen > 0) {
            strcat(duri->params,prefixparams);
	    if(slen > 0)
		strcat(duri->params,"&");
	}
	if(slen > 0)
            strcat(duri->params,suffixparams);
    }

#ifdef NCXDEBUG
	{
        fprintf(stderr,"duri:");
        fprintf(stderr," params=|%s|",FIX(duri->params));
        fprintf(stderr," protocol=|%s|",FIX(duri->protocol));
        fprintf(stderr," host=|%s|",FIX(duri->host));
        fprintf(stderr," port=|%s|",FIX(duri->port));
        fprintf(stderr," file=|%s|",FIX(duri->file));
        fprintf(stderr," constraint=|%s|",FIX(duri->constraint));
        fprintf(stderr,"\n");
    }
#endif
    if(durip != NULL) 
      *durip = duri;
    else
      ncurifree(duri);

    return 1;

fail:
    if(duri != NULL) {
	ncurifree(duri);
    }
    return 0;
}
示例#2
0
文件: ncuri.c 项目: jpouderoux/VTK
/* Do a simple uri parse: return NCU_OK if success, NCU_XXX if failed */
int
ncuriparse(const char* uri0, NCURI** durip)
{
    int ret = NCU_OK;
    NCURI tmp;
    char* p;
    char* q;
    int isfile;
    int hashost;
    char* uri = NULL;
    NCURI* duri = NULL;
    char* prefix = NULL;
    char* next = NULL;
    NClist* params = nclistnew();
    NClist* querylist = nclistnew();
    size_t len0;
    int pathchar;

    if(uri0 == NULL)
	{THROW(NCU_EBADURL);}

    len0 = strlen(uri0);
    if(len0 == 0)
	{THROW(NCU_EBADURL);}

    /* Create a local NCURI instance to hold
       pointers into the parsed string
    */
    memset(&tmp,0,sizeof(tmp));

    /* make mutable copy. Add some extra space
       because we will need to null terminate the host section
       without losing the first character of the path section.
    */
    uri = (char*)malloc(len0+1+1); /* +2 for nul term and for host section terminator */
    if(uri == NULL)
	{THROW(NCU_ENOMEM);}
    strncpy(uri,uri0,len0+1);

    /* Walk the uri and do the following:
	1. remove leading and trailing whitespace
	2. convert all '\\' -> '\' (Temp hack to remove escape characters
                                    inserted by Windows or MinGW)
    */
    for(q=uri,p=uri;*p;p++) {if((*p == '\\' && p[1] == '\\') || *p < ' ') {continue;} else {*q++ = *p;}}
    *q = '\0';

    p = uri;

    /* break up the url into coarse pieces */
    if(*p == LBRACKET) {
        prefix = p;
        ret = collectprefixparams(p,&next); /* collect the prefix */
        if(ret != NCU_OK)
            {THROW(NCU_EBADURL);}
         p = next;
    } else {
	prefix = NULL;
    }
    tmp.uri = p; /* will be the core */
    /* Skip past the core of the url */
    next = nclocate(p,"?#");
    if(next != NULL) {
	int c = *next;
	terminate(next);
	next++;
	if(c == '?') {
	    tmp.query = next;
	    next = nclocate(next,"#");
	    if(next == NULL)
		tmp.fragment = NULL;
	    else {
		terminate(next);
		next++;
	        tmp.fragment = next;
	    }
	} else { /*c == '#'*/
	    tmp.fragment = next;
	}	    
    }

    /* Parse the prefix parameters */
    if(prefix != NULL) {
        if(parselist(prefix,params) != NCU_OK)
            {THROW(NCU_EBADURL);}
    }
    /* Parse the fragment parameters */
    if(tmp.fragment != NULL) {
        if(parselist(tmp.fragment,params) != NCU_OK)
            {THROW(NCU_EBADURL);}
    }
    if(nclistlength(params) > 0) {
	nclistpush(params,NULL);
        tmp.fraglist = nclistextract(params);
    } else
	tmp.fraglist = NULL;
    /* Parse the query */
    if(tmp.query != NULL) {
        if(parselist(tmp.query,querylist) != NCU_OK)
            {THROW(NCU_EBADURL);}
        if(nclistlength(querylist) > 0) {
	    nclistpush(querylist,NULL);
            tmp.querylist = nclistextract(querylist);
	}
    }    

    /* Now parse the core of the url */
    p = tmp.uri;

    /* Mark the protocol */
    tmp.protocol = p;
    p = strchr(p,':');
    if(!p)
	{THROW(NCU_EBADURL);}
    terminate(p); /*overwrite colon*/
    p++; /* skip the colon */
    if(strlen(tmp.protocol)==0)
	{THROW(NCU_EBADURL);}
    /*
       The legal formats for file: urls are a problem since
       many variants are often accepted.
       By RFC, the proper general format is: file://host/path,
       where the 'host' can be omitted and defaults to 'localhost'.
       and the path includes the leading '/'.
       So, assuming no host, the format is: "file:///path".
       Some implementations, however, ignore the host, and allow
       the format: file:/path.
       We also simplify things by assuming the host part is always empty.
       which means we can have file:///path, but not file://..../path.
       Note in all cases, the leading '/' is considered part of the path,
       which is then assumed to be an absolute path. But also note that
       the windows drive letter has to be taken into account. Our rule is that
       if the path looks like D:..., 
       where D is a single alphabetic letter (a-z or A-Z),
       then it is a windows path and can be use in place of a /path.
       The rules implemented here (for file:) are then as follows
       1. file:D:... : assume D: is a windows drive letter and treat D:... as the path
       2. file:/X, where X does not start with a slash: treat /X as the path.
       3. file://D:... : assume D: is a windows drive letter and treat as the path
       4. file:///X, where X does not start with a slash: treat /X as the path.
       All other cases are disallowed: specifically including file://X.
    */

    isfile = (strcmp(tmp.protocol,"file")==0);
    if(isfile) {
	int l = strlen(p); /* to test if we have enough characters */
	hashost = 0; /* always */
	if(l >= 2 && p[1] == ':' && strchr(DRIVELETTERS,p[0]) != NULL) { /* case 1 */
	    p = p; /* p points to the start of the path */
        } else if(l >= 2 && p[0] == '/' && p[1] != '/') { /* case 2 */
	    p = p; /* p points to the start of the path */
	} else if(l >= 4 && p[0] == '/' && p[1] == '/'
		&& p[3] == ':' && strchr(DRIVELETTERS,p[2]) != NULL) { /* case 3 */
	    p = p+2; /* points to the start of the windows path */
        } else if(l >= 4 && p[0] == '/' && p[1] == '/' && p[2] == '/' && p[3] != '/') { /* case 4 */
	    p += 2; /* points to the start of the path */
        } else /* everything else is illegal */
	    {THROW(NCU_EPATH);}
    } else {
        if(p[0] != '/' || p[1] != '/') /* must be proto:// */
	    {THROW(NCU_EPATH);}
	p += 2;
        hashost = 1; /* Assume we have a hostname */
    }
    if(!hashost) {
        tmp.path = p;
	pathchar = EOFCHAR;
    } else { /* assume there should be a host section */
	/* We already extracted the query and/or fragment sections above,
           splocate the end of the host section and therefore the start
           of the path.
        */
	tmp.host = p;
        p  = nclocate(p,"/");
	if(p == NULL) { /* no path */
	    tmp.path = NULL; /* default */
	    pathchar = EOFCHAR;
	} else {
	    tmp.path = p; /* save ptr to rest of the path */
	    pathchar = *p; /* save leading char of the path */
	    terminate(p); /* overwrite the leading char of the path; restored below */
	}
    }
    /* Nullify tmp.host for consistency */
    if(tmp.host != NULL && strlen(tmp.host)==0) {tmp.host = NULL;}

    if(tmp.host != NULL) {/* Parse the host section */
        char* pp;
	/* Check for leading user:pwd@ */
        char* newhost = strchr(tmp.host,'@');
        if(newhost != NULL) {
	    size_t rem;
	    if(newhost == tmp.host)
		{THROW(NCU_EUSRPWD);} /* we have proto://@ */
	    terminate(newhost); /* overwrite '@' */
	    newhost++; /* should point past usr+pwd */
	    tmp.user = tmp.host;
	    /* Break user+pwd into two pieces */
	    pp = strchr(tmp.user,':');
	    if(pp == NULL)
		{THROW(NCU_EUSRPWD);} /* we have user only */
	    terminate(pp); /* overwrite ':' */
	    pp++;
	    if(strlen(tmp.user)==0)
		{THROW(NCU_EUSRPWD);} /* we have empty user */
	    if(strlen(pp)==0)
		{THROW(NCU_EUSRPWD);} /* we have empty password */
	    tmp.password = pp;	    
	    tmp.host = newhost;
	}
	/* Breakup host into host + port */
	pp = tmp.host;
        pp = strchr(pp,':');
        if(pp != NULL) { /* there is a port */
	    terminate(pp); /* overwrite ':' */
	    pp++; /* skip colon */
	    if(strlen(tmp.host) == 0)
		{THROW(NCU_EBADURL);} /* empty host */
	    if(strlen(pp)==0)
		{THROW(NCU_EBADURL);} /* empty port */
	    tmp.port = pp;
	    /* The port must look something like a number */
	    for(pp=tmp.port;*pp;pp++) {
	        if(strchr("0123456789-",*pp) == NULL)
		    {THROW(NCU_EPORT);}  /* probably not a real port, fail */
	    }
	} /* else no port */
    }

    /* Fill in duri from tmp */
    duri = (NCURI*)calloc(1,sizeof(NCURI));
    if(duri == NULL)
      {THROW(NCU_ENOMEM);}
    /* save original uri */
    duri->uri = strdup(uri0);
    duri->protocol = nulldup(tmp.protocol);
    /* before saving, we need to decode the user+pwd */
    duri->user = NULL;
    duri->password = NULL;
    if(tmp.user != NULL) 
        duri->user = ncuridecode(tmp.user);
    if(tmp.password != NULL)
        duri->password = ncuridecode(tmp.password);
    duri->host = nulldup(tmp.host);
    duri->port = nulldup(tmp.port);
    if(tmp.path != NULL) {
	/* We need to add back the previously overwritten path lead char (if necessary);
           this must be done after all host section related pieces have been captured */
	if(pathchar != EOFCHAR)
	    *tmp.path = pathchar;
        duri->path = nulldup(tmp.path);
    }
    duri->query = nulldup(tmp.query);
    duri->fragment = nulldup(tmp.fragment);
    duri->fraglist = tmp.fraglist; tmp.fraglist = NULL;
    duri->querylist = tmp.querylist; tmp.querylist = NULL;
    if(durip) *durip = duri;

#ifdef NCXDEBUG
	{
        fprintf(stderr,"duri:");
	fprintf(stderr," protocol=|%s|",FIX(duri->protocol));
	fprintf(stderr," user=|%s|",FIX(duri->user));
	fprintf(stderr," password=|%s|",FIX(duri->password));
	fprintf(stderr," host=|%s|",FIX(duri->host));
	fprintf(stderr," port=|%s|",FIX(duri->port));
	fprintf(stderr," path=|%s|",FIX(duri->path));
	fprintf(stderr," query=|%s|",FIX(duri->query));
	fprintf(stderr," fragment=|%s|",FIX(duri->fragment));
        fprintf(stderr,"\n");
    }
#endif

done:
    if(uri != NULL)
	free(uri);
    freestringlist(params);
    freestringlist(querylist);
    freestringvec(tmp.fraglist);
    freestringvec(tmp.querylist);
    return ret;
}