source: XIOS3/trunk/extern/src_netcdf4/ocrc.c @ 2534

Last change on this file since 2534 was 409, checked in by ymipsl, 12 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 15.6 KB
Line 
1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2   See the COPYRIGHT file for more information. */
3
4#include "config.h"
5#ifdef HAVE_UNISTD_H
6#include <unistd.h>
7#endif
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "ocinternal.h"
13#include "ocdebug.h"
14#include "ocdata.h"
15#include "occontent.h"
16#include "oclog.h"
17
18#include "ocrc.h"
19
20#define RTAG ']'
21#define LTAG '['
22
23#define TRIMCHARS " \t\r\n"
24
25#define TRIM(x) rctrimright(rctrimleft((x),TRIMCHARS),TRIMCHARS)
26
27#define HTTPPREFIXDEPRECATED "CURL."
28#define HTTPPREFIX           "HTTP."
29
30/* the .dodsrc triple store */
31struct OCTriplestore* ocdodsrc = NULL;
32
33static int parseproxy(OCstate* state, char* v);
34static int rcreadline(FILE* f, char* more, int morelen);
35static char* rctrimright(char* more, char* trimchars);
36static char* rctrimleft(char* more, char* trimchars);
37
38static void ocdodsrcdump(char* msg, struct OCTriple*, int ntriples);
39
40static char* curllookup(char* suffix,char* url);
41
42/* The Username and password are in the URL if the URL is of the form:
43 * http://<name>:<passwd>@<host>/....
44 */
45int
46occredentials_in_url(const char *url)
47{
48        char *pos = strstr(url, "http://");
49        if (!pos)
50                return 0;
51        pos += 7;
52        if (strchr(pos, '@') && strchr(pos, ':'))
53                return 1;
54
55        return 0;
56}
57
58int
59ocextract_credentials(const char *url, char **name, char **pw, char **result_url)
60{
61        char *pos;
62        char *end;
63        char *middle;
64        int up_len = 0;
65        int mid_len = 0;
66        int midpas_len = 0;
67        int url_len = 0;
68
69        if (strchr(url, '@')) {
70                pos = strstr(url, "http://");
71                if (pos)
72                        pos += 7;
73                middle = strchr(pos, ':');
74                mid_len = middle - pos;
75                *name = malloc(sizeof(char) * (mid_len + 1));
76                strncpy(*name, pos, mid_len);
77                (*name)[mid_len] = '\0';
78
79                if (middle)
80                        middle += 1;
81
82                end = strchr(middle, '@');
83                midpas_len = end - middle;
84                *pw = malloc(sizeof(char) * (midpas_len + 1));
85                strncpy(*pw, middle, midpas_len);
86                (*pw)[midpas_len] = '\0';
87
88                up_len = end - pos;
89                url_len = strlen(url) - up_len;
90
91                *result_url = malloc(sizeof(char) * (url_len + 1));
92                if (!result_url)
93                        return OC_ENOMEM;
94
95                strncpy(*result_url, url, pos - url);
96                strncpy(*result_url + (pos - url), end + 1, url_len - (pos - url));
97
98#if 0
99                fprintf(stderr, "URL without username and password: %s:%d\n", sURL, url_len );
100                fprintf(stderr, "URL username and password: %s:%d\n", sUP, up_len);
101                fprintf(stderr, "URL username: %s:%d\n", sUser, mid_len);
102                fprintf(stderr, "URL password: %s:%d\n", sPassword, midpas_len);
103#endif
104                (*result_url)[url_len] = '\0';
105
106                return OC_NOERR;
107        }
108        else {
109                return OC_EIO;
110        }
111}
112
113static int
114rcreadline(FILE* f, char* more, int morelen)
115{
116    int i = 0;
117    int c = getc(f);
118    if(c < 0) return 0;
119    for(;;) {
120        if(i < morelen)  /* ignore excess characters */
121            more[i++]=c;
122        c = getc(f);
123        if(c < 0) break; /* eof */
124        if(c == '\n') break; /* eol */
125    }
126    /* null terminate more */
127    more[i] = '\0';
128    return 1;
129}
130
131/* Trim specified characters from front/left */
132static char*
133rctrimleft(char* more, char* trimchars)
134{
135    char* p = more;
136    int c;
137    while((c=*p) != '\0') {if(strchr(trimchars,c) != NULL) p++; else break;}
138    return p;
139}
140
141/* Trim specified characters from end/right */
142static char*
143rctrimright(char* more, char* trimchars)
144{
145    int len = strlen(more);
146    char* p = more + (len - 1);
147    while(p != more) {if(strchr(trimchars,*p) != NULL) p--; else break;}
148    /* null terminate */
149    p[1] = '\0';
150    return more;
151}
152
153static int
154parseproxy(OCstate* state, char* v)
155{
156    char *host_pos = NULL;
157    char *port_pos = NULL;
158
159    if(strlen(v) == 0) return OC_NOERR; /* nothing there*/
160    if (occredentials_in_url(v)) {
161        char *result_url = NULL;
162        ocextract_credentials(v, &state->creds.username,
163                            &state->creds.password,
164                            &result_url);
165        v = result_url;
166    }
167    /* allocating a bit more than likely needed ... */
168    host_pos = strstr(v, "http://");
169    if (host_pos)
170        host_pos += strlen("http://");
171    else
172        host_pos = v;
173    port_pos = strchr(host_pos, ':');
174    if (port_pos) {
175        int host_len;
176        char *port_sep = port_pos;
177        port_pos++;
178        *port_sep = '\0';
179        host_len = strlen(host_pos);
180        state->proxy.host = malloc(sizeof(char) * host_len + 1);
181        if (!state->proxy.host)
182            return OC_ENOMEM;
183
184        strncpy(state->proxy.host, host_pos, host_len);
185        state->proxy.host[host_len + 1] = '\0';
186
187        state->proxy.port = atoi(port_pos);
188    } else {
189        int host_len = strlen(host_pos);
190        state->proxy.host = malloc(sizeof(char) * host_len + 1);
191        if (!state->proxy.host)
192            return OC_ENOMEM;
193
194        strncpy(state->proxy.host, host_pos, host_len);
195        state->proxy.host[host_len + 1] = '\0';
196
197        state->proxy.port = 80;
198    }
199#if 0
200    state->proxy.host[v_len] = '\0';
201    state->proxy.port = atoi(v);
202    s_len = strlen(v);
203    state->proxy.user = malloc(sizeof(char) * s_len + 1);
204    if (!state->proxy.user)
205        return OC_ENOMEM;
206     strncpy(state->proxy.user, v, s_len);
207     state->proxy.user[s_len] = '\0';
208     p_len = strlen(v);
209     state->proxy.password = malloc(sizeof(char) * p_len + 1);
210     if (!state->proxy.password)
211         return OC_ENOMEM;
212     strncpy(state->proxy.password, v, p_len);
213     state->proxy.password[p_len] = '\0';
214#endif /*0*/
215     if (ocdebug > 1) {
216         oc_log(LOGNOTE,"host name: %s", state->proxy.host);
217         oc_log(LOGNOTE,"user name: %s", state->creds.username);
218#ifdef INSECURE
219         oc_log(LOGNOTE,"password: %s", state->creds.password);
220#endif
221         oc_log(LOGNOTE,"port number: %d", state->proxy.port);
222    }
223    if(v) free(v);
224    return OC_NOERR;
225}
226
227/* insertion sort the triplestore based on url */
228static void
229sorttriplestore(void)
230{
231    int i, nsorted;
232    struct OCTriple* sorted = NULL;
233
234    if(ocdodsrc->ntriples <= 1) return; /* nothing to sort */
235   if(ocdebug > 2)
236        ocdodsrcdump("initial:",ocdodsrc->triples,ocdodsrc->ntriples);
237
238    sorted = (struct OCTriple*)malloc(sizeof(struct OCTriple)*ocdodsrc->ntriples);
239    if(sorted == NULL) {
240        oc_log(LOGERR,"sorttriplestore: out of memory");
241        return;
242    }
243
244    nsorted = 0;
245    while(nsorted < ocdodsrc->ntriples) {
246        int largest;
247        /* locate first non killed entry */
248        for(largest=0;largest<ocdodsrc->ntriples;largest++) {
249            if(ocdodsrc->triples[largest].key[0] != '\0') break;
250        }
251        OCASSERT(ocdodsrc->triples[largest].key[0] != '\0');
252        for(i=0;i<ocdodsrc->ntriples;i++) {
253            if(ocdodsrc->triples[i].key[0] != '\0') { /* avoid empty slots */
254                int lexorder = strcmp(ocdodsrc->triples[i].url,ocdodsrc->triples[largest].url);
255                int leni = strlen(ocdodsrc->triples[i].url);
256                int lenlarge = strlen(ocdodsrc->triples[largest].url);
257                /* this defines the ordering */
258                if(leni == 0 && lenlarge == 0) continue; /* if no urls, then leave in order */
259                if(leni != 0 && lenlarge == 0) largest = i;
260                else if(lexorder > 0) largest = i;
261            }
262        }
263        /* Move the largest entry */
264        OCASSERT(ocdodsrc->triples[largest].key[0] != 0);
265        sorted[nsorted] = ocdodsrc->triples[largest];
266        ocdodsrc->triples[largest].key[0] = '\0'; /* kill entry */
267        nsorted++;
268      if(ocdebug > 2)
269            ocdodsrcdump("pass:",sorted,nsorted);
270    }   
271
272    memcpy((void*)ocdodsrc->triples,(void*)sorted,sizeof(struct OCTriple)*nsorted);
273    free(sorted);
274
275    if(ocdebug > 0)
276        ocdodsrcdump("final .dodsrc order:",ocdodsrc->triples,ocdodsrc->ntriples);
277}
278
279/* Create a triple store from a file */
280int
281ocdodsrc_read(char* basename, char* path)
282{
283    char line0[MAXRCLINESIZE];
284    FILE *in_file = NULL;
285    int linecount = 0;
286
287    if(ocdodsrc == NULL) {
288        ocdodsrc = (struct OCTriplestore*)malloc(sizeof(struct OCTriplestore));
289        if(ocdodsrc == NULL) {
290            oc_log(LOGERR,"ocdodsrc_read: out of memory");
291            return 0;
292        }
293    }
294    ocdodsrc->ntriples = 0;
295
296    in_file = fopen(path, "r"); /* Open the file to read it */
297    if (in_file == NULL) {
298        oc_log(LOGERR, "Could not open configuration file: %s",basename);
299        return OC_EPERM;
300    }
301
302    for(;;) {
303        char *line,*key,*value;
304        if(!rcreadline(in_file,line0,sizeof(line0))) break;
305        linecount++;
306        if(linecount >= MAXRCLINES) {
307            oc_log(LOGERR, ".dodsrc has too many lines");
308            return 0;
309        }               
310        line = line0;
311        /* check for comment */
312        if (line[0] == '#') continue;
313        /* trim leading blanks */
314        line = rctrimleft(line,TRIMCHARS);
315        if(strlen(line) >= MAXRCLINESIZE) {
316            oc_log(LOGERR, "%s line too long: %s",basename,line0);
317            return 0;
318        }               
319        /* parse the line */
320        ocdodsrc->triples[ocdodsrc->ntriples].url[0] = '\0'; /*assume no url*/
321        if(line[0] == LTAG) {
322            char* url = ++line;
323            char* rtag = strchr(line,RTAG);
324            if(rtag == NULL) {
325                oc_log(LOGERR, "Malformed [url] in %s entry: %s",basename,line);
326                continue;
327            }       
328            line = rtag + 1;
329            *rtag = '\0';
330            /* trim again */
331            line = rctrimleft(line,TRIMCHARS);
332            /* save the url */
333            strcpy(ocdodsrc->triples[ocdodsrc->ntriples].url,TRIM(url));
334        }
335        if(strlen(line)==0) continue; /* empty line */
336        /* split off key and value */
337        key=line;
338        value = strchr(line, '=');
339        if(value == NULL) {
340            /* add fake '=1' */
341            if(strlen(line) + strlen("=1") >= MAXRCLINESIZE) {
342                oc_log(LOGERR, "%s entry too long: %s",basename,line);
343                continue;
344            }
345            strcat(line,"=1");
346            value = strchr(line,'=');
347        }
348        *value = '\0';
349        value++;
350        strcpy(ocdodsrc->triples[ocdodsrc->ntriples].key,TRIM(key));
351        strcpy(ocdodsrc->triples[ocdodsrc->ntriples].value,TRIM(value));
352        ocdodsrc->ntriples++;
353    }
354    fclose(in_file);
355    sorttriplestore();
356    return 1;
357}
358
359
360int
361ocdodsrc_process(OCstate* state)
362{
363    int stat = 0;
364    char* value;
365    char* url = ocuribuild(state->uri,NULL,NULL,OCURIENCODE);
366    if(ocdodsrc == NULL) goto done;
367    value = curllookup("DEFLATE",url);
368    if(value != NULL) {
369        if(atoi(value)) state->curlflags.compress = 1;
370        if(ocdebug > 0)
371            oc_log(LOGNOTE,"Compression: %ld", state->curlflags.compress);
372    }
373    if((value = curllookup("VERBOSE",url)) != NULL) {
374        if(atoi(value)) state->curlflags.verbose = 1;
375        if(ocdebug > 0)
376            oc_log(LOGNOTE,"curl.verbose: %ld", state->curlflags.verbose);
377    }
378    if((value = curllookup("TIMEOUT",url)) != NULL) {
379        if(atoi(value)) state->curlflags.timeout = atoi(value);
380        if(ocdebug > 0)
381            oc_log(LOGNOTE,"curl.timeout: %ld", state->curlflags.timeout);
382    }
383
384    if((value = curllookup("COOKIEFILE",url)) != NULL) {
385        state->curlflags.cookiefile = strdup(TRIM(value));
386        if(!state->curlflags.cookiefile) {stat = OC_ENOMEM; goto done;}
387        if(ocdebug > 0)
388            oc_log(LOGNOTE,"COOKIEFILE: %s", state->curlflags.cookiefile);
389    }
390    if((value = curllookup("COOKIEJAR",url))
391       || (value = curllookup("COOKIE_JAR",url))) {
392        state->curlflags.cookiejar = strdup(TRIM(value));
393        if(!state->curlflags.cookiejar) {stat = OC_ENOMEM; goto done;}
394        if(ocdebug > 0)
395            oc_log(LOGNOTE,"COOKIEJAR: %s", state->curlflags.cookiejar);
396    }
397
398    /* Some servers (e.g. thredds) appear to require a place
399       to put cookies in order for some security functions to work
400    */
401    if(state->curlflags.cookiejar == NULL
402       && state->curlflags.cookiefile == NULL) {
403        state->curlflags.cookiefile = strdup("");
404    }
405
406    if((value = curllookup("PROXY_SERVER",url)) != NULL) {
407        stat = parseproxy(state,TRIM(value));
408        if(stat != OC_NOERR) goto done;
409    }
410
411    if((value = curllookup("SSL.VALIDATE",url)) != NULL) {
412        if(atoi(value)) state->ssl.validate = 1;
413        if(ocdebug > 0)
414            oc_log(LOGNOTE,"CURL.SSL.VALIDATE: %ld", state->ssl.validate);
415    }
416
417    if((value = curllookup("SSL.CERTIFICATE",url)) != NULL) {
418        state->ssl.certificate = strdup(TRIM(value));
419        if(!state->ssl.certificate) {stat = OC_ENOMEM; goto done;}
420        if(ocdebug > 0)
421            oc_log(LOGNOTE,"CREDENTIALS.SSL.CERTIFICATE: %s", state->ssl.certificate);
422    }
423
424    if((value = curllookup("SSL.KEY",url)) != NULL) {
425        state->ssl.key = strdup(TRIM(value));
426        if(!state->ssl.key) {stat = OC_ENOMEM; goto done;}
427        if(ocdebug > 0)
428            oc_log(LOGNOTE,"CREDENTIALS.SSL.KEY: %s", state->ssl.key);
429    }
430
431    if((value = curllookup("SSL.KEYPASSWORD",url)) != NULL) {
432        state->ssl.keypasswd = strdup(TRIM(value));
433        if(!state->ssl.keypasswd) {stat = OC_ENOMEM; goto done;}
434#ifdef INSECURE
435        if(ocdebug > 0)
436            oc_log(LOGNOTE,"CREDENTIALS.SSL.KEYPASSWORD: %s", state->ssl.keypasswd);
437#endif
438    }
439
440    if((value = curllookup("SSL.CAINFO",url)) != NULL) {
441        state->ssl.cainfo = strdup(TRIM(value));
442        if(!state->ssl.cainfo) {stat = OC_ENOMEM; goto done;}
443        if(ocdebug > 0)
444            oc_log(LOGNOTE,"SSL.CAINFO: %s", state->ssl.cainfo);
445    }
446
447    if((value = curllookup("SSL.CAPATH",url)) != NULL) {
448        state->ssl.capath = strdup(TRIM(value));
449        if(!state->ssl.capath) {stat = OC_ENOMEM; goto done;}
450        if(ocdebug > 0)
451            oc_log(LOGNOTE,"SSL.CAPATH: %s", state->ssl.capath);
452    }
453
454    if((value = curllookup("SSL.VERIFYPEER",url)) != NULL) {
455        char* s = strdup(TRIM(value));
456        int tf = 0;
457        if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
458            tf = 0;
459        else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
460            tf = 1;
461        else
462            tf = 1; /* default if not null */
463        state->ssl.verifypeer = tf;
464        if(ocdebug > 0)
465            oc_log(LOGNOTE,"SSL.VERIFYPEER: %d", state->ssl.verifypeer);
466    }
467
468    if((value = curllookup("CREDENTIALS.USER",url)) != NULL) {
469        state->creds.username = strdup(TRIM(value));
470        if(!state->creds.username) {stat = OC_ENOMEM; goto done;}
471        if(ocdebug > 0)
472            oc_log(LOGNOTE,"CREDENTIALS.USER: %s", state->creds.username);
473    }
474
475    if((value = curllookup("CREDENTIALS.PASSWORD",url)) != NULL) {
476        state->creds.password = strdup(TRIM(value));
477        if(!state->creds.password) {stat = OC_ENOMEM; goto done;}
478    }
479    /* else ignore */   
480
481done:
482    if(url != NULL) free(url);
483    return stat;
484}
485   
486char*
487ocdodsrc_lookup(char* key, char* url)
488{
489    int i,found;
490    struct OCTriple* triple = ocdodsrc->triples;
491    if(key == NULL || ocdodsrc == NULL) return NULL;
492    if(url == NULL) url = "";
493    /* Assume that the triple store has been properly sorted */
494    for(found=0,i=0;i<ocdodsrc->ntriples;i++,triple++) {
495        int triplelen = strlen(triple->url);
496        int t;
497        if(strcmp(key,triple->key) != 0) continue; /* keys do not match */
498        /* If the triple entry has no url, then use it (because we have checked all other cases)*/
499        if(triplelen == 0) {found=1;break;}
500        /* do url prefix comparison */
501        t = ocstrncmp(url,triple->url,triplelen);
502        if(t ==  0) {found=1; break;}
503    }
504    if(ocdebug > 2)
505    {
506        if(found) {
507            fprintf(stderr,"lookup %s: [%s]%s = %s\n",url,triple->url,triple->key,triple->value);
508        }
509    }   
510    return (found ? triple->value : NULL);
511}
512
513
514static void
515ocdodsrcdump(char* msg, struct OCTriple* triples, int ntriples)
516{
517    int i;
518    if(msg != NULL) fprintf(stderr,"%s\n",msg);
519    if(ocdodsrc == NULL) {
520        fprintf(stderr,"<EMPTY>\n");
521        return;
522    }
523    if(triples == NULL) triples= ocdodsrc->triples;
524    if(ntriples < 0 ) ntriples= ocdodsrc->ntriples;
525    for(i=0;i<ntriples;i++) {
526        fprintf(stderr,"\t%s\t%s\t%s\n",
527                (strlen(triples[i].url)==0?"--":triples[i].url),
528                triples[i].key,
529                triples[i].value);
530    }
531}
532
533/* Isolate the "CURL." prefix to allow changing to something else */
534static char*
535curllookup(char* suffix, char* url)
536{
537    char key[2048];
538    char* value = NULL;
539    strcpy(key,HTTPPREFIX);
540    strcat(key,suffix);
541    value = ocdodsrc_lookup(key,url);
542    if(value == NULL) {
543        strcpy(key,HTTPPREFIXDEPRECATED);
544        strcat(key,suffix);
545        value = ocdodsrc_lookup(key,url);
546    }
547    return value;
548}
Note: See TracBrowser for help on using the repository browser.