[409] | 1 | /* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc. |
---|
| 2 | See the COPYRIGHT file for more information. */ |
---|
| 3 | |
---|
| 4 | #include "config.h" |
---|
| 5 | #include <stdio.h> |
---|
| 6 | #include <fcntl.h> |
---|
| 7 | #include <errno.h> |
---|
| 8 | |
---|
| 9 | #ifdef HAVE_UNISTD_H |
---|
| 10 | #include <unistd.h> |
---|
| 11 | #endif |
---|
| 12 | |
---|
| 13 | #include "ocinternal.h" |
---|
| 14 | #include "ocdebug.h" |
---|
| 15 | #include "ocdata.h" |
---|
| 16 | #include "occontent.h" |
---|
| 17 | #include "occlientparams.h" |
---|
| 18 | #include "ocrc.h" |
---|
| 19 | #include "occurlfunctions.h" |
---|
| 20 | |
---|
| 21 | #include "ochttp.h" |
---|
| 22 | #include "ocread.h" |
---|
| 23 | |
---|
| 24 | /* Note: TMPPATH must end in '/' */ |
---|
| 25 | #ifdef __CYGWIN__ |
---|
| 26 | #define TMPPATH1 "/cygdrive/c/temp/" |
---|
| 27 | #define TMPPATH2 "./" |
---|
| 28 | #elifdef WIN32 |
---|
| 29 | #define TMPPATH1 "c:\\temp/" |
---|
| 30 | #define TMPPATH2 ".\\" |
---|
| 31 | #else |
---|
| 32 | #define TMPPATH1 "/tmp/" |
---|
| 33 | #define TMPPATH2 "./" |
---|
| 34 | #endif |
---|
| 35 | |
---|
| 36 | /* Define default rc files and aliases*/ |
---|
| 37 | static char* rcfilenames[3] = {".dodsrc",".ocrc",NULL}; |
---|
| 38 | |
---|
| 39 | static int ocextractddsinmemory(OCstate*,OCtree*,int); |
---|
| 40 | static int ocextractddsinfile(OCstate*,OCtree*,int); |
---|
| 41 | static char* constraintescape(const char* url); |
---|
| 42 | static OCerror createtempfile(OCstate*,OCtree*); |
---|
| 43 | static int createtempfile1(char*,char**); |
---|
| 44 | |
---|
| 45 | static void ocsetcurlproperties(OCstate*); |
---|
| 46 | |
---|
| 47 | extern OCnode* makeunlimiteddimension(void); |
---|
| 48 | |
---|
| 49 | #ifdef WIN32 |
---|
| 50 | #include <fcntl.h> |
---|
| 51 | #define _S_IREAD 256 |
---|
| 52 | #define _S_IWRITE 128 |
---|
| 53 | #else |
---|
| 54 | #include <sys/stat.h> |
---|
| 55 | #endif |
---|
| 56 | |
---|
| 57 | /* Global flags*/ |
---|
| 58 | int oc_curl_file_supported; |
---|
| 59 | int oc_curl_https_supported; |
---|
| 60 | |
---|
| 61 | int |
---|
| 62 | ocinternalinitialize(void) |
---|
| 63 | { |
---|
| 64 | int stat = OC_NOERR; |
---|
| 65 | |
---|
| 66 | /* Compute some xdr related flags */ |
---|
| 67 | xxdr_init(); |
---|
| 68 | |
---|
| 69 | oc_loginit(); |
---|
| 70 | |
---|
| 71 | /* Determine if this version of curl supports |
---|
| 72 | "file://..." &/or "https://..." urls. |
---|
| 73 | */ |
---|
| 74 | { |
---|
| 75 | const char* const* proto; /*weird*/ |
---|
| 76 | curl_version_info_data* curldata; |
---|
| 77 | curldata = curl_version_info(CURLVERSION_NOW); |
---|
| 78 | oc_curl_file_supported = 0; |
---|
| 79 | oc_curl_https_supported = 0; |
---|
| 80 | for(proto=curldata->protocols;*proto;proto++) { |
---|
| 81 | if(strcmp("file",*proto)==0) {oc_curl_file_supported=1;break;} |
---|
| 82 | if(strcmp("https",*proto)==0) {oc_curl_https_supported=1;break;} |
---|
| 83 | } |
---|
| 84 | if(ocdebug > 0) { |
---|
| 85 | oc_log(LOGNOTE,"Curl file:// support = %d",oc_curl_file_supported); |
---|
| 86 | oc_log(LOGNOTE,"Curl https:// support = %d",oc_curl_file_supported); |
---|
| 87 | } |
---|
| 88 | } |
---|
| 89 | |
---|
| 90 | /* compile the .dodsrc, if any */ |
---|
| 91 | { |
---|
| 92 | char* path = NULL; |
---|
| 93 | char* homepath = NULL; |
---|
| 94 | char** alias; |
---|
| 95 | FILE* f = NULL; |
---|
| 96 | /* locate the configuration files: . first in '.', then $HOME */ |
---|
| 97 | for(alias=rcfilenames;*alias;alias++) { |
---|
| 98 | path = (char*)malloc(strlen("./")+strlen(*alias)+1); |
---|
| 99 | if(path == NULL) return OC_ENOMEM; |
---|
| 100 | strcpy(path,"./"); |
---|
| 101 | strcat(path,*alias); |
---|
| 102 | /* see if file is readable */ |
---|
| 103 | f = fopen(path,"r"); |
---|
| 104 | if(f != NULL) break; |
---|
| 105 | if(path != NULL) {free(path); path = NULL;} /* cleanup */ |
---|
| 106 | } |
---|
| 107 | if(f == NULL) { /* try $HOME */ |
---|
| 108 | OCASSERT(path == NULL); |
---|
| 109 | homepath = getenv("HOME"); |
---|
| 110 | if (homepath!= NULL) { |
---|
| 111 | for(alias=rcfilenames;*alias;alias++) { |
---|
| 112 | path = (char*)malloc(strlen(homepath)+1+strlen(*alias)+1); |
---|
| 113 | if(path == NULL) return OC_ENOMEM; |
---|
| 114 | strcpy(path,homepath); |
---|
| 115 | strcat(path,"/"); |
---|
| 116 | strcat(path,*alias); |
---|
| 117 | f = fopen(path,"r"); |
---|
| 118 | if(f != NULL) break; |
---|
| 119 | if(path != NULL) {free(path); path=NULL;} |
---|
| 120 | } |
---|
| 121 | } |
---|
| 122 | } |
---|
| 123 | if(f == NULL) { |
---|
| 124 | oc_log(LOGDBG,"Cannot find runtime configuration file"); |
---|
| 125 | } else { |
---|
| 126 | OCASSERT(path != NULL); |
---|
| 127 | fclose(f); |
---|
| 128 | if(ocdebug > 1) |
---|
| 129 | fprintf(stderr, "DODS RC file: %s\n", path); |
---|
| 130 | if(ocdodsrc_read(*alias,path) == 0) |
---|
| 131 | oc_log(LOGERR, "Error parsing %s\n",path); |
---|
| 132 | } |
---|
| 133 | if(path != NULL) free(path); |
---|
| 134 | } |
---|
| 135 | return OCTHROW(stat); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | /**************************************************/ |
---|
| 139 | OCerror |
---|
| 140 | ocopen(OCstate** statep, const char* url) |
---|
| 141 | { |
---|
| 142 | int stat = OC_NOERR; |
---|
| 143 | OCstate * state = NULL; |
---|
| 144 | OCURI* tmpurl = NULL; |
---|
| 145 | CURL* curl = NULL; /* curl handle*/ |
---|
| 146 | |
---|
| 147 | if(!ocuriparse(url,&tmpurl)) {OCTHROWCHK(stat=OC_EBADURL); goto fail;} |
---|
| 148 | |
---|
| 149 | stat = occurlopen(&curl); |
---|
| 150 | if(stat != OC_NOERR) {OCTHROWCHK(stat); goto fail;} |
---|
| 151 | |
---|
| 152 | state = (OCstate*)ocmalloc(sizeof(OCstate)); /* ocmalloc zeros memory*/ |
---|
| 153 | if(state == NULL) {OCTHROWCHK(stat=OC_ENOMEM); goto fail;} |
---|
| 154 | |
---|
| 155 | /* Setup DAP state*/ |
---|
| 156 | state->magic = OCMAGIC; |
---|
| 157 | state->curl = curl; |
---|
| 158 | state->trees = oclistnew(); |
---|
| 159 | state->uri = tmpurl; |
---|
| 160 | if(!ocuridecodeparams(state->uri)) { |
---|
| 161 | oc_log(LOGWARN,"Could not parse client parameters"); |
---|
| 162 | } |
---|
| 163 | state->packet = ocbytesnew(); |
---|
| 164 | ocbytessetalloc(state->packet,DFALTPACKETSIZE); /*initial reasonable size*/ |
---|
| 165 | |
---|
| 166 | /* set curl properties for this link */ |
---|
| 167 | ocsetcurlproperties(state); |
---|
| 168 | |
---|
| 169 | /* Set up list to support reuse/reclamation of OCcontent objects. */ |
---|
| 170 | state->contentlist = NULL; |
---|
| 171 | |
---|
| 172 | if(statep) *statep = state; |
---|
| 173 | return OCTHROW(stat); |
---|
| 174 | |
---|
| 175 | fail: |
---|
| 176 | ocurifree(tmpurl); |
---|
| 177 | if(state != NULL) ocfree(state); |
---|
| 178 | if(curl != NULL) occurlclose(curl); |
---|
| 179 | return OCTHROW(stat); |
---|
| 180 | } |
---|
| 181 | |
---|
| 182 | OCerror |
---|
| 183 | ocfetchf(OCstate* state, const char* constraint, OCdxd kind, OCflags flags, |
---|
| 184 | OCnode** rootp) |
---|
| 185 | { |
---|
| 186 | OCtree* tree = NULL; |
---|
| 187 | OCnode* root = NULL; |
---|
| 188 | OCerror stat = OC_NOERR; |
---|
| 189 | |
---|
| 190 | tree = (OCtree*)ocmalloc(sizeof(OCtree)); |
---|
| 191 | MEMCHECK(tree,OC_ENOMEM); |
---|
| 192 | memset((void*)tree,0,sizeof(OCtree)); |
---|
| 193 | tree->dxdclass = kind; |
---|
| 194 | tree->state = state; |
---|
| 195 | tree->constraint = constraintescape(constraint); |
---|
| 196 | if(tree->constraint == NULL) |
---|
| 197 | tree->constraint = nulldup(constraint); |
---|
| 198 | |
---|
| 199 | /* Set curl properties: pwd, flags, proxies, ssl */ |
---|
| 200 | if((stat=ocset_user_password(state))!= OC_NOERR) goto fail; |
---|
| 201 | if((stat=ocset_curl_flags(state)) != OC_NOERR) goto fail; |
---|
| 202 | if((stat=ocset_proxy(state)) != OC_NOERR) goto fail; |
---|
| 203 | if((stat=ocset_ssl(state)) != OC_NOERR) goto fail; |
---|
| 204 | |
---|
| 205 | ocbytesclear(state->packet); |
---|
| 206 | |
---|
| 207 | switch (kind) { |
---|
| 208 | case OCDAS: |
---|
| 209 | stat = readDAS(state,tree); |
---|
| 210 | if(stat == OC_NOERR) { |
---|
| 211 | tree->text = ocbytesdup(state->packet); |
---|
| 212 | if(tree->text == NULL) stat = OC_EDAS; |
---|
| 213 | } |
---|
| 214 | break; |
---|
| 215 | case OCDDS: |
---|
| 216 | stat = readDDS(state,tree); |
---|
| 217 | if(stat == OC_NOERR) { |
---|
| 218 | tree->text = ocbytesdup(state->packet); |
---|
| 219 | if(tree->text == NULL) stat = OC_EDDS; |
---|
| 220 | } |
---|
| 221 | break; |
---|
| 222 | case OCDATADDS: |
---|
| 223 | if((flags & OCONDISK) != 0) {/* store in file */ |
---|
| 224 | /* Create the datadds file immediately |
---|
| 225 | so that DRNO can reference it*/ |
---|
| 226 | /* Make the tmp file*/ |
---|
| 227 | stat = createtempfile(state,tree); |
---|
| 228 | if(stat) {OCTHROWCHK(stat); goto unwind;} |
---|
| 229 | stat = readDATADDS(state,tree,flags); |
---|
| 230 | if(stat == OC_NOERR) { |
---|
| 231 | /* Separate the DDS from data and return the dds; |
---|
| 232 | will modify packet */ |
---|
| 233 | stat = ocextractddsinfile(state,tree,flags); |
---|
| 234 | } |
---|
| 235 | } else { /*in memory*/ |
---|
| 236 | stat = readDATADDS(state,tree,flags); |
---|
| 237 | if(stat == OC_NOERR) { |
---|
| 238 | /* Separate the DDS from data and return the dds; |
---|
| 239 | will modify packet */ |
---|
| 240 | stat = ocextractddsinmemory(state,tree,flags); |
---|
| 241 | } |
---|
| 242 | } |
---|
| 243 | break; |
---|
| 244 | }/*switch*/ |
---|
| 245 | if(stat != OC_NOERR) { |
---|
| 246 | /* Obtain any http code */ |
---|
| 247 | state->error.httpcode = ocfetchhttpcode(state->curl); |
---|
| 248 | if(state->error.httpcode >= 400) { |
---|
| 249 | oc_log(LOGWARN,"oc_open: Could not read url; http error = %l",state->error.httpcode); |
---|
| 250 | } else { |
---|
| 251 | oc_log(LOGWARN,"oc_open: Could not read url"); |
---|
| 252 | } |
---|
| 253 | return OCTHROW(stat); |
---|
| 254 | } |
---|
| 255 | |
---|
| 256 | tree->nodes = NULL; |
---|
| 257 | stat = DAPparse(state,tree,tree->text); |
---|
| 258 | /* Check and report on an error return from the server */ |
---|
| 259 | if(stat == OC_EDAPSVC && state->error.code != NULL) { |
---|
| 260 | oc_log(LOGERR,"oc_open: server error retrieving url: code=%s message=\"%s\"", |
---|
| 261 | state->error.code, |
---|
| 262 | (state->error.message?state->error.message:"")); |
---|
| 263 | } |
---|
| 264 | if(stat) {OCTHROWCHK(stat); goto unwind;} |
---|
| 265 | root = tree->root; |
---|
| 266 | /* make sure */ |
---|
| 267 | tree->root = root; |
---|
| 268 | root->tree = tree; |
---|
| 269 | |
---|
| 270 | /* Verify the parse */ |
---|
| 271 | switch (kind) { |
---|
| 272 | case OCDAS: |
---|
| 273 | if(root->octype != OC_Attributeset) |
---|
| 274 | {OCTHROWCHK(stat=OC_EDAS); goto unwind;} |
---|
| 275 | break; |
---|
| 276 | case OCDDS: |
---|
| 277 | if(root->octype != OC_Dataset) |
---|
| 278 | {OCTHROWCHK(stat=OC_EDDS); goto unwind;} |
---|
| 279 | break; |
---|
| 280 | case OCDATADDS: |
---|
| 281 | if(root->octype != OC_Dataset) |
---|
| 282 | {OCTHROWCHK(stat=OC_EDATADDS); goto unwind;} |
---|
| 283 | /* Modify the tree kind */ |
---|
| 284 | tree->dxdclass = OCDATADDS; |
---|
| 285 | break; |
---|
| 286 | default: return OC_EINVAL; |
---|
| 287 | } |
---|
| 288 | |
---|
| 289 | if(kind != OCDAS) { |
---|
| 290 | /* Process ocnodes to assign offsets and sizes where possible */ |
---|
| 291 | occomputeskipdata(state,root); |
---|
| 292 | /* Process ocnodes to mark those that are cacheable */ |
---|
| 293 | ocmarkcacheable(state,root); |
---|
| 294 | /* Process ocnodes to handle various semantic issues*/ |
---|
| 295 | occomputesemantics(tree->nodes); |
---|
| 296 | } |
---|
| 297 | |
---|
| 298 | /* Process ocnodes to compute name info*/ |
---|
| 299 | occomputefullnames(tree->root); |
---|
| 300 | |
---|
| 301 | if(kind == OCDATADDS) { |
---|
| 302 | if((flags & OCONDISK) != 0) { |
---|
| 303 | tree->data.xdrs = xxdr_filecreate(tree->data.file,tree->data.bod); |
---|
| 304 | } else { |
---|
| 305 | /* Switch to zero based memory */ |
---|
| 306 | tree->data.xdrs |
---|
| 307 | = xxdr_memcreate(tree->data.memory,tree->data.datasize,tree->data.bod); |
---|
| 308 | } |
---|
| 309 | MEMCHECK(tree->data.xdrs,OC_ENOMEM); |
---|
| 310 | } |
---|
| 311 | |
---|
| 312 | /* Put root into the state->trees list */ |
---|
| 313 | oclistpush(state->trees,(ocelem)root); |
---|
| 314 | |
---|
| 315 | if(rootp) *rootp = root; |
---|
| 316 | return stat; |
---|
| 317 | |
---|
| 318 | unwind: |
---|
| 319 | ocfreetree(tree); |
---|
| 320 | fail: |
---|
| 321 | return OCTHROW(stat); |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | void |
---|
| 325 | occlose(OCstate* state) |
---|
| 326 | { |
---|
| 327 | unsigned int i; |
---|
| 328 | if(state == NULL) return; |
---|
| 329 | |
---|
| 330 | /* Warning: ocfreeroot will attempt to remove the root from state->trees */ |
---|
| 331 | /* Ok in this case because we are popping the root out of state->trees */ |
---|
| 332 | for(i=0;i<oclistlength(state->trees);i++) { |
---|
| 333 | OCnode* root = (OCnode*)oclistpop(state->trees); |
---|
| 334 | ocfreeroot(root); |
---|
| 335 | } |
---|
| 336 | oclistfree(state->trees); |
---|
| 337 | ocurifree(state->uri); |
---|
| 338 | ocbytesfree(state->packet); |
---|
| 339 | ocfree(state->error.code); |
---|
| 340 | ocfree(state->error.message); |
---|
| 341 | if(state->contentlist != NULL) { |
---|
| 342 | struct OCcontent* next; |
---|
| 343 | struct OCcontent* curr = state->contentlist; |
---|
| 344 | while(curr != NULL) { |
---|
| 345 | next = curr->next; |
---|
| 346 | ocfree(curr); |
---|
| 347 | curr = next; |
---|
| 348 | } |
---|
| 349 | } |
---|
| 350 | ocfree(state->curlflags.useragent); |
---|
| 351 | ocfree(state->curlflags.cookiejar); |
---|
| 352 | ocfree(state->curlflags.cookiefile); |
---|
| 353 | ocfree(state->ssl.certificate); |
---|
| 354 | ocfree(state->ssl.key); |
---|
| 355 | ocfree(state->ssl.keypasswd); |
---|
| 356 | ocfree(state->ssl.cainfo); |
---|
| 357 | ocfree(state->ssl.capath); |
---|
| 358 | ocfree(state->proxy.host); |
---|
| 359 | ocfree(state->creds.username); |
---|
| 360 | ocfree(state->creds.password); |
---|
| 361 | if(state->curl != NULL) occurlclose(state->curl); |
---|
| 362 | ocfree(state); |
---|
| 363 | } |
---|
| 364 | |
---|
| 365 | static OCerror |
---|
| 366 | ocextractddsinmemory(OCstate* state, OCtree* tree, OCflags flags) |
---|
| 367 | { |
---|
| 368 | OCerror stat = OC_NOERR; |
---|
| 369 | size_t ddslen, bod, bodfound; |
---|
| 370 | /* Read until we find the separator (or EOF)*/ |
---|
| 371 | bodfound = findbod(state->packet,&bod,&ddslen); |
---|
| 372 | if(!bodfound) {/* No BOD; pretend */ |
---|
| 373 | bod = tree->data.bod; |
---|
| 374 | ddslen = tree->data.datasize; |
---|
| 375 | } |
---|
| 376 | tree->data.bod = bod; |
---|
| 377 | tree->data.ddslen = ddslen; |
---|
| 378 | /* copy out the dds */ |
---|
| 379 | if(ddslen > 0) { |
---|
| 380 | tree->text = (char*)ocmalloc(ddslen+1); |
---|
| 381 | memcpy((void*)tree->text,(void*)ocbytescontents(state->packet),ddslen); |
---|
| 382 | tree->text[ddslen] = '\0'; |
---|
| 383 | } else |
---|
| 384 | tree->text = NULL; |
---|
| 385 | /* Extract the inmemory contents */ |
---|
| 386 | tree->data.memory = ocbytesextract(state->packet); |
---|
| 387 | #ifdef OCIGNORE |
---|
| 388 | /* guarantee the data part is on an 8 byte boundary */ |
---|
| 389 | if(tree->data.bod % 8 != 0) { |
---|
| 390 | unsigned long count = tree->data.datasize - tree->data.bod; |
---|
| 391 | memcpy(tree->xdrmemory,tree->xdrmemory+tree->data.bod,count); |
---|
| 392 | tree->data.datasize = count; |
---|
| 393 | tree->data.bod = 0; |
---|
| 394 | tree->data.ddslen = 0; |
---|
| 395 | } |
---|
| 396 | #endif |
---|
| 397 | if(tree->text == NULL) stat = OC_EDATADDS; |
---|
| 398 | return OCTHROW(stat); |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | static OCerror |
---|
| 402 | ocextractddsinfile(OCstate* state, OCtree* tree, OCflags flags) |
---|
| 403 | { |
---|
| 404 | OCerror stat = OC_NOERR; |
---|
| 405 | size_t ddslen, bod, bodfound; |
---|
| 406 | |
---|
| 407 | /* Read until we find the separator (or EOF)*/ |
---|
| 408 | ocbytesclear(state->packet); |
---|
| 409 | rewind(tree->data.file); |
---|
| 410 | bodfound = 0; |
---|
| 411 | do { |
---|
| 412 | char chunk[1024]; |
---|
| 413 | size_t count; |
---|
| 414 | /* read chunks of the file until we find the separator*/ |
---|
| 415 | count = fread(chunk,1,sizeof(chunk),tree->data.file); |
---|
| 416 | if(count <= 0) break; /* EOF;*/ |
---|
| 417 | ocbytesappendn(state->packet,chunk,count); |
---|
| 418 | bodfound = findbod(state->packet,&bod,&ddslen); |
---|
| 419 | } while(!bodfound); |
---|
| 420 | if(!bodfound) {/* No BOD; pretend */ |
---|
| 421 | bod = tree->data.bod; |
---|
| 422 | ddslen = tree->data.datasize; |
---|
| 423 | } |
---|
| 424 | tree->data.bod = bod; |
---|
| 425 | tree->data.ddslen = ddslen; |
---|
| 426 | /* copy out the dds */ |
---|
| 427 | if(ddslen > 0) { |
---|
| 428 | tree->text = (char*)ocmalloc(ddslen+1); |
---|
| 429 | memcpy((void*)tree->text,(void*)ocbytescontents(state->packet),ddslen); |
---|
| 430 | tree->text[ddslen] = '\0'; |
---|
| 431 | } else |
---|
| 432 | tree->text = NULL; |
---|
| 433 | /* reset the position of the tmp file*/ |
---|
| 434 | fseek(tree->data.file,tree->data.bod,SEEK_SET); |
---|
| 435 | if(tree->text == NULL) stat = OC_EDATADDS; |
---|
| 436 | return OCTHROW(stat); |
---|
| 437 | } |
---|
| 438 | |
---|
| 439 | static OCerror |
---|
| 440 | createtempfile(OCstate* state, OCtree* tree) |
---|
| 441 | { |
---|
| 442 | int fd; |
---|
| 443 | char* name = NULL; |
---|
| 444 | fd = createtempfile1(TMPPATH1,&name); |
---|
| 445 | if(fd < 0) |
---|
| 446 | fd = createtempfile1(TMPPATH2,&name); |
---|
| 447 | if(fd < 0) { |
---|
| 448 | oc_log(LOGERR,"oc_open: attempt to open tmp file failed: %s",name); |
---|
| 449 | return errno; |
---|
| 450 | } |
---|
| 451 | #ifdef OCDEBUG |
---|
| 452 | oc_log(LOGNOTE,"oc_open: using tmp file: %s",name); |
---|
| 453 | #endif |
---|
| 454 | tree->data.filename = name; /* remember our tmp file name */ |
---|
| 455 | tree->data.file = fdopen(fd,"w+"); |
---|
| 456 | if(tree->data.file == NULL) return OC_EOPEN; |
---|
| 457 | /* unlink the temp file so it will automatically be reclaimed */ |
---|
| 458 | if(ocdebug == 0) unlink(tree->data.filename); |
---|
| 459 | return OC_NOERR; |
---|
| 460 | } |
---|
| 461 | |
---|
| 462 | int |
---|
| 463 | createtempfile1(char* tmppath, char** tmpnamep) |
---|
| 464 | { |
---|
| 465 | int fd = 0; |
---|
| 466 | char* tmpname = NULL; |
---|
| 467 | tmpname = (char*)malloc(strlen(tmppath)+strlen("dataddsXXXXXX")+1); |
---|
| 468 | if(tmpname == NULL) return -1; |
---|
| 469 | strcpy(tmpname,tmppath); |
---|
| 470 | #ifdef HAVE_MKSTEMP |
---|
| 471 | strcat(tmpname,"dataddsXXXXXX"); |
---|
| 472 | /* Note Potential problem: old versions of this function |
---|
| 473 | leave the file in mode 0666 instead of 0600 */ |
---|
| 474 | fd = mkstemp(tmpname); |
---|
| 475 | #else /* !HAVE_MKSTEMP */ |
---|
| 476 | /* Need to simulate by using some kind of pseudo-random number */ |
---|
| 477 | strcat(tmpname,"datadds"); |
---|
| 478 | { |
---|
| 479 | int rno = rand(); |
---|
| 480 | char spid[7]; |
---|
| 481 | if(rno < 0) rno = -rno; |
---|
| 482 | sprintf(spid,"%06d",rno); |
---|
| 483 | strcat(tmpname,spid); |
---|
| 484 | # ifdef WIN32 |
---|
| 485 | fd=open(tmpname,O_RDWR|O_BINARY|O_CREAT|O_EXCL|FILE_ATTRIBUTE_TEMPORARY, _S_IREAD|_S_IWRITE); |
---|
| 486 | # else |
---|
| 487 | fd=open(tmpname,O_RDWR|O_CREAT|O_EXCL, S_IRWXU); |
---|
| 488 | # endif |
---|
| 489 | } |
---|
| 490 | #endif /* !HAVE_MKSTEMP */ |
---|
| 491 | if(tmpname == NULL) return -1; |
---|
| 492 | if(tmpnamep) *tmpnamep = tmpname; |
---|
| 493 | return fd; |
---|
| 494 | } |
---|
| 495 | |
---|
| 496 | /* Allow these (non-alpha-numerics) to pass thru */ |
---|
| 497 | static char okchars[] = "&/:;,.=?@'\"<>{}!|\\^[]`~"; |
---|
| 498 | static char hexdigits[] = "0123456789abcdef"; |
---|
| 499 | |
---|
| 500 | |
---|
| 501 | /* Modify constraint to use %XX escapes */ |
---|
| 502 | static char* |
---|
| 503 | constraintescape(const char* url) |
---|
| 504 | { |
---|
| 505 | size_t len; |
---|
| 506 | char* p; |
---|
| 507 | int c; |
---|
| 508 | char* eurl; |
---|
| 509 | |
---|
| 510 | if(url == NULL) return NULL; |
---|
| 511 | len = strlen(url); |
---|
| 512 | eurl = ocmalloc(1+3*len); /* worst case: c -> %xx */ |
---|
| 513 | MEMCHECK(eurl,NULL); |
---|
| 514 | p = eurl; |
---|
| 515 | *p = '\0'; |
---|
| 516 | while((c=*url++)) { |
---|
| 517 | if(c >= '0' && c <= '9') {*p++ = c;} |
---|
| 518 | else if(c >= 'a' && c <= 'z') {*p++ = c;} |
---|
| 519 | else if(c >= 'A' && c <= 'Z') {*p++ = c;} |
---|
| 520 | else if(strchr(okchars,c) != NULL) {*p++ = c;} |
---|
| 521 | else { |
---|
| 522 | *p++ = '%'; |
---|
| 523 | *p++ = hexdigits[(c & 0xf0)>>4]; |
---|
| 524 | *p++ = hexdigits[(c & 0xf)]; |
---|
| 525 | } |
---|
| 526 | } |
---|
| 527 | *p = '\0'; |
---|
| 528 | return eurl; |
---|
| 529 | } |
---|
| 530 | |
---|
| 531 | OCerror |
---|
| 532 | ocupdatelastmodifieddata(OCstate* state) |
---|
| 533 | { |
---|
| 534 | OCerror status = OC_NOERR; |
---|
| 535 | long lastmodified; |
---|
| 536 | char* base = NULL; |
---|
| 537 | base = ocuribuild(state->uri,NULL,NULL,OCURIENCODE); |
---|
| 538 | status = ocfetchlastmodified(state->curl, base, &lastmodified); |
---|
| 539 | free(base); |
---|
| 540 | if(status == OC_NOERR) { |
---|
| 541 | state->datalastmodified = lastmodified; |
---|
| 542 | } |
---|
| 543 | return status; |
---|
| 544 | } |
---|
| 545 | |
---|
| 546 | /* |
---|
| 547 | Set curl properties for link based on rc files |
---|
| 548 | */ |
---|
| 549 | static void |
---|
| 550 | ocsetcurlproperties(OCstate* state) |
---|
| 551 | { |
---|
| 552 | CURLcode cstat = CURLE_OK; |
---|
| 553 | |
---|
| 554 | /* process the triple store wrt to this state */ |
---|
| 555 | if(ocdodsrc_process(state) != OC_NOERR) { |
---|
| 556 | oc_log(LOGERR,"Malformed .opendaprc configuration file"); |
---|
| 557 | goto fail; |
---|
| 558 | } |
---|
| 559 | if(state->creds.username == NULL && state->creds.password == NULL) { |
---|
| 560 | if(state->uri->user != NULL && state->uri->password != NULL) { |
---|
| 561 | /* this overrides .dodsrc */ |
---|
| 562 | if(state->creds.password) free(state->creds.password); |
---|
| 563 | state->creds.password = nulldup(state->uri->password); |
---|
| 564 | if(state->creds.username) free(state->creds.username); |
---|
| 565 | state->creds.username = nulldup(state->uri->user); |
---|
| 566 | } |
---|
| 567 | } |
---|
| 568 | return; |
---|
| 569 | |
---|
| 570 | fail: |
---|
| 571 | if(cstat != CURLE_OK) |
---|
| 572 | oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat)); |
---|
| 573 | return; |
---|
| 574 | } |
---|