nc_uri.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*********************************************************************
  2. * Copyright 2010, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. * $Header$
  5. *********************************************************************/
  6. #include "config.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include "nc_uri.h"
  11. #define NC_URIDEBUG
  12. #define LBRACKET '['
  13. #define RBRACKET ']'
  14. #ifndef FIX
  15. #define FIX(s) ((s)==NULL?"":(s))
  16. #endif
  17. #ifndef NILLEN
  18. #define NILLEN(s) ((s)==NULL?0:strlen(s))
  19. #endif
  20. static char* legalprotocols[] = {
  21. "file:",
  22. "http:",
  23. "https:",
  24. "ftp:",
  25. NULL /* NULL terminate*/
  26. };
  27. static void nc_paramfree(char** params);
  28. static int nc_find(char** params, const char* key);
  29. /* Do a simple uri parse: return 0 if fail, 1 otherwise*/
  30. int
  31. nc_uriparse(const char* uri0, NC_URI** nc_urip)
  32. {
  33. NC_URI* nc_uri = NULL;
  34. char* uri;
  35. char** pp;
  36. char* p;
  37. char* p1;
  38. int c;
  39. /* accumulate parse points*/
  40. char* protocol = NULL;
  41. char* params = NULL;
  42. char* host = NULL;
  43. char* port = NULL;
  44. char* constraint = NULL;
  45. char* user = NULL;
  46. char* pwd = NULL;
  47. char* file = NULL;
  48. nc_uri = (NC_URI*)calloc(1,sizeof(NC_URI));
  49. if(nc_uri == NULL) return 0;
  50. /* Temporary hack to remove escape characters inserted by Windows or MinGW */
  51. if(strchr(uri0,'\\') != NULL) {
  52. char* u = strdup(uri0);
  53. if(u == NULL) return 0;
  54. p = u;
  55. p1 = u;
  56. while((c=*p1++)) {if(c != '\\') *p++ = c;}
  57. uri0 = (const char*)u;
  58. }
  59. /* make local copy of uri */
  60. uri = strdup(uri0);
  61. /* remove all whitespace*/
  62. p = uri;
  63. p1 = uri;
  64. while((c=*p1++)) {if(c != ' ' && c != '\t') *p++ = c;}
  65. p = uri;
  66. /* break up the uri string into pieces*/
  67. /* 1. leading bracketed parameters */
  68. if(*p == LBRACKET) {
  69. params = p+1;
  70. /* find end of the clientparams*/
  71. for(;*p;p++) {if(p[0] == RBRACKET && p[1] != LBRACKET) break;}
  72. if(*p == 0) goto fail; /* malformed client params*/
  73. *p = '\0'; /* leave off the trailing rbracket for now */
  74. p++; /* move past the params*/
  75. }
  76. /* verify that the uri starts with an acceptable protocol*/
  77. for(pp=legalprotocols;*pp;pp++) {
  78. if(strncmp(p,*pp,strlen(*pp))==0) break;
  79. }
  80. if(*pp == NULL) goto fail; /* illegal protocol*/
  81. /* save the protocol */
  82. protocol = *pp;
  83. /* 4. skip protocol */
  84. p += strlen(protocol);
  85. /* 5. skip // */
  86. if(*p != '/' && *(p+1) != '/')
  87. goto fail;
  88. p += 2;
  89. /* 6. Mark the end of the host section */
  90. file = strchr(p,'/');
  91. if(file) {
  92. *file++ = '\0'; /* warning: we just overwrote the leading / */
  93. } else
  94. goto fail; /* url only has host part, no path */
  95. /* 7. extract any user:pwd */
  96. p1 = strchr(p,'@');
  97. if(p1) {/* Assume we have user:pwd@ */
  98. *p1 = '\0';
  99. user = p;
  100. pwd = strchr(p,':');
  101. if(!pwd) goto fail; /* malformed */
  102. *pwd++ = '\0';
  103. p = pwd+strlen(pwd)+1;
  104. }
  105. /* 8. extract host and port */
  106. host = p;
  107. port = strchr(p,':');
  108. if(port) {
  109. *port++ = '\0';
  110. }
  111. /* 9. Look for '?' */
  112. constraint = strchr(file,'?');
  113. if(constraint) {
  114. *constraint++ = '\0';
  115. }
  116. /* assemble the component pieces*/
  117. if(uri0 && strlen(uri0) > 0)
  118. nc_uri->uri = strdup(uri0);
  119. if(protocol && strlen(protocol) > 0) {
  120. nc_uri->protocol = strdup(protocol);
  121. /* remove trailing ':' */
  122. nc_uri->protocol[strlen(protocol)-1] = '\0';
  123. }
  124. if(user && strlen(user) > 0)
  125. nc_uri->user = strdup(user);
  126. if(pwd && strlen(pwd) > 0)
  127. nc_uri->password = strdup(pwd);
  128. if(host && strlen(host) > 0)
  129. nc_uri->host = strdup(host);
  130. if(port && strlen(port) > 0)
  131. nc_uri->port = strdup(port);
  132. if(file && strlen(file) > 0) {
  133. /* Add back the leading / */
  134. nc_uri->file = malloc(strlen(file)+2);
  135. strcpy(nc_uri->file,"/");
  136. strcat(nc_uri->file,file);
  137. }
  138. if(constraint && strlen(constraint) > 0)
  139. nc_uri->constraint = strdup(constraint);
  140. nc_urisetconstraints(nc_uri,constraint);
  141. if(params != NULL && strlen(params) > 0) {
  142. nc_uri->params = (char*)malloc(1+2+strlen(params));
  143. strcpy(nc_uri->params,"[");
  144. strcat(nc_uri->params,params);
  145. strcat(nc_uri->params,"]");
  146. }
  147. #ifdef NC_XDEBUG
  148. {
  149. fprintf(stderr,"nc_uri:");
  150. fprintf(stderr," params=|%s|",FIX(nc_uri->params));
  151. fprintf(stderr," protocol=|%s|",FIX(nc_uri->protocol));
  152. fprintf(stderr," host=|%s|",FIX(nc_uri->host));
  153. fprintf(stderr," port=|%s|",FIX(nc_uri->port));
  154. fprintf(stderr," file=|%s|",FIX(nc_uri->file));
  155. fprintf(stderr," constraint=|%s|",FIX(nc_uri->constraint));
  156. fprintf(stderr,"\n");
  157. }
  158. #endif
  159. free(uri);
  160. if(nc_urip != NULL) *nc_urip = nc_uri;
  161. return 1;
  162. fail:
  163. if(nc_uri) nc_urifree(nc_uri);
  164. if(uri != NULL) free(uri);
  165. return 0;
  166. }
  167. void
  168. nc_urifree(NC_URI* nc_uri)
  169. {
  170. if(nc_uri == NULL) return;
  171. if(nc_uri->uri != NULL) {free(nc_uri->uri);}
  172. if(nc_uri->protocol != NULL) {free(nc_uri->protocol);}
  173. if(nc_uri->user != NULL) {free(nc_uri->user);}
  174. if(nc_uri->password != NULL) {free(nc_uri->password);}
  175. if(nc_uri->host != NULL) {free(nc_uri->host);}
  176. if(nc_uri->port != NULL) {free(nc_uri->port);}
  177. if(nc_uri->file != NULL) {free(nc_uri->file);}
  178. if(nc_uri->constraint != NULL) {free(nc_uri->constraint);}
  179. if(nc_uri->projection != NULL) {free(nc_uri->projection);}
  180. if(nc_uri->selection != NULL) {free(nc_uri->selection);}
  181. if(nc_uri->params != NULL) {free(nc_uri->params);}
  182. if(nc_uri->paramlist != NULL) nc_paramfree(nc_uri->paramlist);
  183. free(nc_uri);
  184. }
  185. /* Replace the constraints */
  186. void
  187. nc_urisetconstraints(NC_URI* duri,const char* constraints)
  188. {
  189. char* proj = NULL;
  190. char* select = NULL;
  191. const char* p;
  192. if(duri->constraint == NULL) free(duri->constraint);
  193. if(duri->projection != NULL) free(duri->projection);
  194. if(duri->selection != NULL) free(duri->selection);
  195. duri->constraint = NULL;
  196. duri->projection = NULL;
  197. duri->selection = NULL;
  198. if(constraints == NULL || strlen(constraints)==0) return;
  199. duri->constraint = strdup(constraints);
  200. if(*duri->constraint == '?')
  201. strcpy(duri->constraint,duri->constraint+1);
  202. p = duri->constraint;
  203. proj = (char*) p;
  204. select = strchr(proj,'&');
  205. if(select != NULL) {
  206. size_t plen = (select - proj);
  207. if(plen == 0) {
  208. proj = NULL;
  209. } else {
  210. proj = (char*)malloc(plen+1);
  211. memcpy((void*)proj,p,plen);
  212. proj[plen] = '\0';
  213. }
  214. select = nulldup(select);
  215. } else {
  216. proj = nulldup(proj);
  217. select = NULL;
  218. }
  219. duri->projection = proj;
  220. duri->selection = select;
  221. }
  222. /* Construct a complete NC_ URI without the client params
  223. and optionally with the constraints;
  224. caller frees returned string
  225. */
  226. char*
  227. nc_uribuild(NC_URI* duri, const char* prefix, const char* suffix, int pieces)
  228. {
  229. size_t len = 0;
  230. char* newuri;
  231. int withparams = ((pieces&NC_URIPARAMS)
  232. && duri->params != NULL);
  233. int withuserpwd = ((pieces&NC_URIUSERPWD)
  234. && duri->user != NULL && duri->password != NULL);
  235. int withconstraints = ((pieces&NC_URICONSTRAINTS)
  236. && duri->constraint != NULL);
  237. if(prefix != NULL) len += NILLEN(prefix);
  238. if(withparams) {
  239. len += NILLEN(duri->params);
  240. }
  241. len += (NILLEN(duri->protocol)+NILLEN("://"));
  242. if(withuserpwd) {
  243. len += (NILLEN(duri->user)+NILLEN(duri->password)+NILLEN(":@"));
  244. }
  245. len += (NILLEN(duri->host));
  246. if(duri->port != NULL) {
  247. len += (NILLEN(":")+NILLEN(duri->port));
  248. }
  249. len += (NILLEN(duri->file));
  250. if(suffix != NULL) len += NILLEN(suffix);
  251. if(withconstraints) {
  252. len += (NILLEN("?")+NILLEN(duri->constraint));
  253. }
  254. len += 1; /* null terminator */
  255. newuri = (char*)malloc(len);
  256. if(!newuri) return NULL;
  257. newuri[0] = '\0';
  258. if(prefix != NULL) strcat(newuri,prefix);
  259. if(withparams) {
  260. strcat(newuri,duri->params);
  261. }
  262. strcat(newuri,duri->protocol);
  263. strcat(newuri,"://");
  264. if(withuserpwd) {
  265. strcat(newuri,duri->user);
  266. strcat(newuri,":");
  267. strcat(newuri,duri->password);
  268. strcat(newuri,"@");
  269. }
  270. if(duri->host != NULL) { /* may be null if using file: protocol */
  271. strcat(newuri,duri->host);
  272. }
  273. if(duri->port != NULL) {
  274. strcat(newuri,":");
  275. strcat(newuri,duri->port);
  276. }
  277. strcat(newuri,duri->file);
  278. if(suffix != NULL) strcat(newuri,suffix);
  279. if(withconstraints) {
  280. strcat(newuri,"?");
  281. strcat(newuri,duri->constraint);
  282. }
  283. return newuri;
  284. }
  285. /**************************************************/
  286. /* Parameter support */
  287. /*
  288. Client parameters are assumed to be
  289. one or more instances of bracketed pairs:
  290. e.g "[...][...]...".
  291. The bracket content in turn is assumed to be a
  292. comma separated list of <name>=<value> pairs.
  293. e.g. x=y,z=,a=b.
  294. If the same parameter is specifed more than once,
  295. then the first occurrence is used; this is so that
  296. is possible to forcibly override user specified
  297. parameters by prefixing.
  298. IMPORTANT: client parameter string is assumed to
  299. have blanks compress out.
  300. Returns 1 if parse suceeded, 0 otherwise;
  301. */
  302. int
  303. nc_uridecodeparams(NC_URI* nc_uri)
  304. {
  305. char* cp;
  306. char* cq;
  307. int c;
  308. int i;
  309. int nparams;
  310. char* params0;
  311. char* params;
  312. char* params1;
  313. char** plist;
  314. if(nc_uri == NULL) return 0;
  315. if(nc_uri->params == NULL) return 1;
  316. params0 = nc_uri->params;
  317. /* Pass 1 to replace beginning '[' and ending ']' */
  318. if(params0[0] == '[')
  319. params = strdup(params0+1);
  320. else
  321. params = strdup(params0);
  322. if(params[strlen(params)-1] == ']')
  323. params[strlen(params)-1] = '\0';
  324. /* Pass 2 to replace "][" pairs with ','*/
  325. params1 = strdup(params);
  326. cp=params; cq = params1;
  327. while((c=*cp++)) {
  328. if(c == RBRACKET && *cp == LBRACKET) {cp++; c = ',';}
  329. *cq++ = c;
  330. }
  331. *cq = '\0';
  332. free(params);
  333. params = params1;
  334. /* Pass 3 to break string into pieces and count # of pairs */
  335. nparams=0;
  336. for(cp=params;(c=*cp);cp++) {
  337. if(c == ',') {*cp = '\0'; nparams++;}
  338. }
  339. nparams++; /* for last one */
  340. /* plist is an env style list */
  341. plist = (char**)calloc(1,sizeof(char*)*(2*nparams+1)); /* +1 for null termination */
  342. /* Pass 4 to break up each pass into a (name,value) pair*/
  343. /* and insert into the param list */
  344. /* parameters of the form name name= are converted to name=""*/
  345. cp = params;
  346. for(i=0;i<nparams;i++) {
  347. char* next = cp+strlen(cp)+1; /* save ptr to next pair*/
  348. char* vp;
  349. /*break up the ith param*/
  350. vp = strchr(cp,'=');
  351. if(vp != NULL) {*vp = '\0'; vp++;} else {vp = "";}
  352. plist[2*i] = strdup(cp);
  353. plist[2*i+1] = strdup(vp);
  354. cp = next;
  355. }
  356. plist[2*nparams] = NULL;
  357. free(params);
  358. if(nc_uri->paramlist != NULL)
  359. nc_paramfree(nc_uri->paramlist);
  360. nc_uri->paramlist = plist;
  361. return 1;
  362. }
  363. int
  364. nc_urilookup(NC_URI* uri, const char* key, const char** resultp)
  365. {
  366. int i;
  367. char* value = NULL;
  368. if(uri == NULL || key == NULL || uri->params == NULL) return 0;
  369. if(uri->paramlist == NULL) {
  370. i = nc_uridecodeparams(uri);
  371. if(!i) return 0;
  372. }
  373. i = nc_find(uri->paramlist,key);
  374. if(i < 0) return 0;
  375. value = uri->paramlist[(2*i)+1];
  376. if(resultp) *resultp = value;
  377. return 1;
  378. }
  379. int
  380. nc_urisetparams(NC_URI* uri, const char* newparams)
  381. {
  382. if(uri == NULL) return 0;
  383. if(uri->paramlist != NULL) nc_paramfree(uri->paramlist);
  384. uri->paramlist = NULL;
  385. if(uri->params != NULL) free(uri->params);
  386. uri->params = nulldup(newparams);
  387. return 1;
  388. }
  389. /* Internal version of lookup; returns the paired index of the key */
  390. static int
  391. nc_find(char** params, const char* key)
  392. {
  393. int i;
  394. char** p;
  395. for(i=0,p=params;*p;p+=2,i++) {
  396. if(strcmp(key,*p)==0) return i;
  397. }
  398. return -1;
  399. }
  400. static void
  401. nc_paramfree(char** params)
  402. {
  403. char** p;
  404. if(params == NULL) return;
  405. for(p=params;*p;p+=2) {
  406. free(*p);
  407. if(p[1] != NULL) free(p[1]);
  408. }
  409. free(params);
  410. }