source: TI12-security/trunk/NDGSecurity/C/openDapPatch/http.c @ 6876

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/C/openDapPatch/http.c@6876
Revision 6876, 9.9 KB checked in by pjkersha, 10 years ago (diff)

Added

  • shell scripts to set the environment variables and run the executable
  • Makefile
  • main program ncopen.c to test the code
  • more info in README
  • a new patch for the netCDF 4.1.1.
  • Property svn:executable set to *
Line 
1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2 See the COPYRIGHT file for more information. */
3
4#include <sys/stat.h>
5#include <unistd.h>
6#include <fcntl.h>
7#include "ocinternal.h"
8#include "ocdebug.h"
9#include "http.h"
10#include "rc.h"
11
12static size_t WriteFileCallback(void*, size_t, size_t, void*);
13static size_t WriteMemoryCallback(void*, size_t, size_t, void*);
14static int ocsetcurlproperties(CURL* curl, const char*);
15
16struct Fetchdata {
17        FILE* stream;
18        size_t size;
19};
20
21long
22ocfetchhttpcode(CURL* curl)
23{
24    long httpcode;
25    CURLcode cstat = CURLE_OK;
26    /* Extract the http code */
27    cstat = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&httpcode);
28    if(cstat != CURLE_OK) httpcode = 0;
29    return httpcode;
30}
31
32int
33ocfetchurl_file(CURL* curl, char* url, FILE* stream,
34                unsigned long* sizep, long* filetime)
35{
36        int stat = OC_NOERR;
37        CURLcode cstat = CURLE_OK;
38        struct Fetchdata fetchdata;
39
40
41        if((stat = ocsetcurlproperties(curl,url)) != OC_NOERR) goto fail;
42
43        /* Set the URL */
44        cstat = curl_easy_setopt(curl, CURLOPT_URL, (void*)url);
45        if (cstat != CURLE_OK)
46                goto fail;
47
48        /* send all data to this function  */
49        cstat = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteFileCallback);
50        if (cstat != CURLE_OK)
51                goto fail;
52
53        /* we pass our file to the callback function */
54        cstat = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&fetchdata);
55        if (cstat != CURLE_OK)
56                goto fail;
57
58        /* One last thing; always try to get the last modified time */
59        cstat = curl_easy_setopt(curl, CURLOPT_FILETIME, (long)1);
60
61        fetchdata.stream = stream;
62        fetchdata.size = 0;
63        cstat = curl_easy_perform(curl);
64        if (cstat != CURLE_OK) {
65            goto fail;
66        }
67
68        if (stat == OC_NOERR) {
69                /* return the file size*/
70                if (sizep != NULL)
71                        *sizep = fetchdata.size;
72                /* Get the last modified time */
73                if(filetime != NULL)
74                    cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
75                if(cstat != CURLE_OK) goto fail;
76        }
77        return THROW(stat);
78
79fail: oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
80        return THROW(OC_ECURL);
81}
82
83int
84ocfetchurl(CURL* curl, char* url, OCbytes* buf, long* filetime)
85{
86        int stat = OC_NOERR;
87        CURLcode cstat = CURLE_OK;
88        size_t len;
89
90        if((stat = ocsetcurlproperties(curl,url)) != OC_NOERR) goto fail;
91
92        /* Set the URL */
93        cstat = curl_easy_setopt(curl, CURLOPT_URL, (void*)url);
94        if (cstat != CURLE_OK)
95                goto fail;
96
97        /* send all data to this function  */
98        cstat = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
99        if (cstat != CURLE_OK)
100                goto fail;
101
102        /* we pass our file to the callback function */
103        cstat = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)buf);
104        if (cstat != CURLE_OK)
105                goto fail;
106
107        /* One last thing; always try to get the last modified time */
108        cstat = curl_easy_setopt(curl, CURLOPT_FILETIME, (long)1);
109
110        cstat = curl_easy_perform(curl);
111        if(cstat == CURLE_PARTIAL_FILE) {
112            /* Log it but otherwise ignore */
113            oc_log(LOGWARN, "curl error: %s; ignored",
114                   curl_easy_strerror(cstat));
115            cstat = CURLE_OK;
116        }
117        if(cstat != CURLE_OK) goto fail;
118
119        /* Get the last modified time */
120        if(filetime != NULL)
121            cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
122        if(cstat != CURLE_OK) goto fail;
123
124        /* Null terminate the buffer*/
125        len = ocbyteslength(buf);
126        ocbytesappend(buf, '\0');
127        ocbytessetlength(buf, len); /* dont count null in buffer size*/
128
129        return THROW(stat);
130
131fail:
132        oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
133        return THROW(OC_ECURL);
134}
135
136static size_t
137WriteFileCallback(void* ptr, size_t size, size_t nmemb, void* data)
138{
139        size_t count;
140        struct Fetchdata* fetchdata;
141        fetchdata = (struct Fetchdata*) data;
142        count = fwrite(ptr, size, nmemb, fetchdata->stream);
143        if (count > 0) {
144                fetchdata->size += (count * size);
145        }
146#ifdef OCPROGRESS
147        oc_log(LOGNOTE,"callback: %lu bytes",(unsigned long)(size*nmemb));
148#endif
149        return count;
150}
151
152static size_t
153WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
154{
155        size_t realsize = size * nmemb;
156        OCbytes* buf = (OCbytes*) data;
157if(realsize == 0)
158oc_log(LOGWARN,"WriteMemoryCallback: zero sized chunk");
159        /* Optimize for reading potentially large dods datasets */
160        if(!ocbytesavail(buf,realsize)) {
161            /* double the size of the packet */
162            ocbytessetalloc(buf,2*ocbytesalloc(buf));
163        }
164        ocbytesappendn(buf, ptr, realsize);
165        return realsize;
166}
167
168#if 0
169static void
170assembleurl(DAPURL* durl, OCbytes* buf, int what)
171{
172        encodeurltext(durl->url,buf);
173        if(what & WITHPROJ) {
174                ocbytescat(buf,"?");
175                encodeurltext(durl->projection,buf);
176        }
177        if(what & WITHSEL) encodeurltext(durl->selection,buf);
178
179}
180
181static char mustencode="";
182static char hexchars[16] = {
183        '0', '1', '2', '3',
184        '4', '5', '6', '7',
185        '8', '9', 'a', 'b',
186        'c', 'd', 'e', 'f',
187};
188
189static void
190encodeurltext(char* text, OCbytes* buf)
191{
192        /* Encode the URL to handle illegal characters */
193        len = strlen(url);
194        encoded = ocmalloc(len*4+1); /* should never be larger than this*/
195        if(encoded==NULL) return;
196        p = url; q = encoded;
197        while((c=*p++)) {
198                if(strchr(mustencode,c) != NULL) {
199                        char tmp[8];
200                        int hex1, hex2;
201                        hex1 = (c & 0x0F);
202                        hex2 = (c & 0xF0) >> 4;
203                        tmp[0] = '0'; tmp[1] = 'x';
204                        tmp[2] = hexchars[hex2]; tmp[3] = hexchars[hex1];
205                        tmp[4] = '\0';
206                        ocbytescat(buf,tmp);
207                } else *q++ = (char)c;
208        }
209
210}
211
212#endif
213
214/* hack for adding extra curl options via env variables */
215
216CURLcode curl_getenv_opt(CURL* curl) {
217        CURLcode cstat=CURLE_OK;
218        char *envVar;
219        long envVal;
220
221        if ((envVar=getenv("CURLOPT_SSLCERT"))!=NULL) {
222                cstat = curl_easy_setopt(curl,CURLOPT_SSLCERT,envVar);
223                if (cstat != CURLE_OK ) return cstat;
224        }
225        if ((envVar=getenv("CURLOPT_SSLKEY"))!=NULL) {
226                cstat = curl_easy_setopt(curl,CURLOPT_SSLKEY,envVar);
227                if (cstat != CURLE_OK ) return cstat;
228        }
229        if ((envVar=getenv("CURLOPT_CAINFO"))!=NULL) {
230                cstat = curl_easy_setopt(curl,CURLOPT_CAINFO,envVar);
231                if (cstat != CURLE_OK ) return cstat;
232        }
233        if ((envVar=getenv("CURLOPT_CAPATH"))!=NULL) {
234                cstat = curl_easy_setopt(curl,CURLOPT_CAPATH,envVar);
235                if (cstat != CURLE_OK ) return cstat;
236        }
237        if ((envVar=getenv("CURLOPT_COOKIEFILE"))!=NULL) {
238                cstat = curl_easy_setopt(curl,CURLOPT_COOKIEFILE,envVar);
239                if (cstat != CURLE_OK ) return cstat;
240        }
241        if ((envVar=getenv("CURLOPT_COOKIEJAR"))!=NULL) {
242                cstat = curl_easy_setopt(curl,CURLOPT_COOKIEJAR,envVar);
243                if (cstat != CURLE_OK ) return cstat;
244        }
245        if ((envVar=getenv("CURLOPT_VERBOSE"))!=NULL) {
246                if(sscanf(envVar,"%ld",&envVal)==1) {
247                        cstat = curl_easy_setopt(curl,CURLOPT_VERBOSE,envVal);
248                } else {
249                        cstat = CURLE_BAD_FUNCTION_ARGUMENT;
250                }
251                if (cstat != CURLE_OK ) return cstat;
252        }
253        if ((envVar=getenv("CURLOPT_FOLLOWLOCATION"))!=NULL) {
254                if(sscanf(envVar,"%ld",&envVal)==1) {
255                        cstat = curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,envVal);
256                } else {
257                        cstat = CURLE_BAD_FUNCTION_ARGUMENT;
258                }
259                if (cstat != CURLE_OK ) return cstat;
260        }
261        if ((envVar=getenv("CURLOPT_MAXREDIRS"))!=NULL) {
262                if(sscanf(envVar,"%ld",&envVal)==1) {
263                        cstat = curl_easy_setopt(curl,CURLOPT_MAXREDIRS,envVal);
264                } else {
265                        cstat = CURLE_BAD_FUNCTION_ARGUMENT;
266                }
267                if (cstat != CURLE_OK ) return cstat;
268        }
269}
270 
271/* end hack for adding extra curl options via env variables */
272
273int
274occurlopen(CURL** curlp)
275{
276        int stat = OC_NOERR;
277        CURLcode cstat;
278        CURL* curl;
279        /* initialize curl*/
280        curl = curl_easy_init();
281        if (curl == NULL)
282                stat = OC_ECURL;
283        else {
284                cstat = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
285                if (cstat != CURLE_OK)
286                        stat = OC_ECURL;
287                /* some servers don't like requests that are made without a user-agent */
288                cstat = curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
289/* hack for adding extra curl options via env variables */
290                if (cstat == CURLE_OK) cstat=curl_getenv_opt(curl);
291/* end */
292
293                if (cstat != CURLE_OK)
294                        stat = OC_ECURL;
295        }
296        if (curlp)
297                *curlp = curl;
298        return THROW(stat);
299}
300
301void
302occurlclose(CURL* curl)
303{
304        if (curl != NULL)
305                curl_easy_cleanup(curl);
306}
307
308static int
309ocsetcurlproperties(CURL* curl, const char* url)
310{
311    CURLcode cstat = CURLE_OK;
312    /* These conditionals look for value in four globals set when the
313     * .dodsrc file was read.
314     */
315    if (dods_verify) {
316        if (set_verify(curl) != OC_NOERR)
317            goto fail;
318    }
319    if (dods_compress) {
320        if (set_compression(curl) != OC_NOERR)
321            goto fail;
322    }
323    if (pstructProxy) {
324        if (set_proxy(curl, pstructProxy) != OC_NOERR)
325            goto fail;
326    }
327    if (cook) {
328        if (set_cookies(curl, cook) != OC_NOERR)
329            goto fail;
330    }
331
332    if (credentials_in_url(url)) {
333        char *result_url = NULL;
334        if (extract_credentials(url, &userName, &password, &result_url) != OC_NOERR)
335            goto fail;
336        url = result_url;
337    }
338
339    if (userName && password) {
340        if (set_user_password(curl, userName, password) != OC_NOERR)
341            goto fail;
342    }
343    return OC_NOERR;
344
345fail:
346    oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
347    return THROW(OC_ECURL);
348}
349
350int
351ocfetchlastmodified(CURL* curl, char* url, long* filetime)
352{
353    int stat = OC_NOERR;
354    CURLcode cstat = CURLE_OK;
355    size_t len;
356
357    if((stat = ocsetcurlproperties(curl,url)) != OC_NOERR) goto fail;
358
359    /* Set the URL */
360    cstat = curl_easy_setopt(curl, CURLOPT_URL, (void*)url);
361    if (cstat != CURLE_OK)
362        goto fail;
363
364    /* Ask for head */
365    cstat = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30); /* 30sec timeout*/
366    cstat = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2);
367    cstat = curl_easy_setopt(curl, CURLOPT_HEADER, 1);
368    cstat = curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
369    cstat = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
370    cstat = curl_easy_setopt(curl, CURLOPT_FILETIME, (long)1);
371
372    cstat = curl_easy_perform(curl);
373    if(cstat != CURLE_OK) goto fail;
374    if(filetime != NULL)
375        cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
376    if(cstat != CURLE_OK) goto fail;
377
378    return THROW(stat);
379
380fail:
381    oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
382    return THROW(OC_ECURL);
383}
Note: See TracBrowser for help on using the repository browser.