Annotation of embedaddon/strongswan/src/libstrongswan/plugins/curl/curl_fetcher.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * Copyright (C) 2007 Andreas Steffen
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #include <curl/curl.h>
                     18: 
                     19: #include <library.h>
                     20: #include <utils/debug.h>
                     21: 
                     22: #include "curl_fetcher.h"
                     23: 
                     24: #define CONNECT_TIMEOUT 10
                     25: 
                     26: typedef struct private_curl_fetcher_t private_curl_fetcher_t;
                     27: 
                     28: /**
                     29:  * private data of a curl_fetcher_t object.
                     30:  */
                     31: struct private_curl_fetcher_t {
                     32:        /**
                     33:         * Public data
                     34:         */
                     35:        curl_fetcher_t public;
                     36: 
                     37:        /**
                     38:         * CURL handle
                     39:         */
                     40:        CURL* curl;
                     41: 
                     42:        /**
                     43:         * Optional HTTP headers
                     44:         */
                     45:        struct curl_slist *headers;
                     46: 
                     47:        /**
                     48:         * Callback function
                     49:         */
                     50:        fetcher_callback_t cb;
                     51: 
                     52:        /**
                     53:         * Variable that receives the response code
                     54:         */
                     55:        u_int *result;
                     56: 
                     57:        /**
                     58:         * Timeout for a transfer
                     59:         */
                     60:        long timeout;
                     61: 
                     62:        /**
                     63:         * Maximum number of redirects to follow
                     64:         */
                     65:        long redir;
                     66: };
                     67: 
                     68: /**
                     69:  * Data to pass to curl callback
                     70:  */
                     71: typedef struct {
                     72:        fetcher_callback_t cb;
                     73:        void *user;
                     74: } cb_data_t;
                     75: 
                     76: /**
                     77:  * Curl callback function, invokes fetcher_callback_t function
                     78:  */
                     79: static size_t curl_cb(void *ptr, size_t size, size_t nmemb, cb_data_t *data)
                     80: {
                     81:        size_t realsize = size * nmemb;
                     82: 
                     83:        if (data->cb(data->user, chunk_create(ptr, realsize)))
                     84:        {
                     85:                return realsize;
                     86:        }
                     87:        return 0;
                     88: }
                     89: 
                     90: METHOD(fetcher_t, fetch, status_t,
                     91:        private_curl_fetcher_t *this, char *uri, void *userdata)
                     92: {
                     93:        char error[CURL_ERROR_SIZE], *enc_uri, *p1, *p2;
                     94:        CURLcode curl_status;
                     95:        status_t status;
                     96:        long result = 0;
                     97:        cb_data_t data = {
                     98:                .cb = this->cb,
                     99:                .user = userdata,
                    100:        };
                    101: 
                    102:        if (this->cb == fetcher_default_callback)
                    103:        {
                    104:                *(chunk_t*)userdata = chunk_empty;
                    105:        }
                    106: 
                    107:        /* the URI has to be URL-encoded, we only replace spaces as replacing other
                    108:         * characters (e.g. '/' or ':') would render the URI invalid */
                    109:        enc_uri = strreplace(uri, " ", "%20");
                    110: 
                    111:        if (curl_easy_setopt(this->curl, CURLOPT_URL, enc_uri) != CURLE_OK)
                    112:        {       /* URL type not supported by curl */
                    113:                status = NOT_SUPPORTED;
                    114:                goto out;
                    115:        }
                    116:        curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, error);
                    117:        curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, FALSE);
                    118:        curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE);
                    119:        if (this->timeout)
                    120:        {
                    121:                curl_easy_setopt(this->curl, CURLOPT_TIMEOUT, this->timeout);
                    122:        }
                    123:        curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, CONNECT_TIMEOUT);
                    124:        curl_easy_setopt(this->curl, CURLOPT_FOLLOWLOCATION, TRUE);
                    125:        curl_easy_setopt(this->curl, CURLOPT_MAXREDIRS, this->redir);
                    126:        curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, (void*)curl_cb);
                    127:        curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, &data);
                    128:        if (this->headers)
                    129:        {
                    130:                curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, this->headers);
                    131:        }
                    132: 
                    133:        /* if the URI contains a username[:password] prefix then mask it */
                    134:        p1 = strstr(uri, "://");
                    135:        p2 = strchr(uri, '@');
                    136:        if (p1 && p2)
                    137:        {
                    138:                DBG2(DBG_LIB, "  sending request to '%.*sxxxx%s'...", p1+3-uri, uri, p2);
                    139:        }
                    140:        else
                    141:        {
                    142:                DBG2(DBG_LIB, "  sending request to '%s'...", uri);
                    143:        }
                    144:        curl_status = curl_easy_perform(this->curl);
                    145:        switch (curl_status)
                    146:        {
                    147:                case CURLE_UNSUPPORTED_PROTOCOL:
                    148:                        status = NOT_SUPPORTED;
                    149:                        break;
                    150:                case CURLE_OK:
                    151:                        curl_easy_getinfo(this->curl, CURLINFO_RESPONSE_CODE,
                    152:                                                          &result);
                    153:                        if (this->result)
                    154:                        {
                    155:                                *this->result = result;
                    156:                        }
                    157:                        status = (result < 400) ? SUCCESS : FAILED;
                    158:                        break;
                    159:                default:
                    160:                        DBG1(DBG_LIB, "libcurl request failed [%d]: %s", curl_status,
                    161:                                 error);
                    162:                        status = FAILED;
                    163:                        break;
                    164:        }
                    165: 
                    166: out:
                    167:        if (enc_uri != uri)
                    168:        {
                    169:                free(enc_uri);
                    170:        }
                    171:        return status;
                    172: }
                    173: 
                    174: METHOD(fetcher_t, set_option, bool,
                    175:        private_curl_fetcher_t *this, fetcher_option_t option, ...)
                    176: {
                    177:        bool supported = TRUE;
                    178:        va_list args;
                    179: 
                    180:        va_start(args, option);
                    181:        switch (option)
                    182:        {
                    183:                case FETCH_REQUEST_DATA:
                    184:                {
                    185:                        chunk_t data = va_arg(args, chunk_t);
                    186: 
                    187:                        curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, (char*)data.ptr);
                    188:                        curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, data.len);
                    189:                        break;
                    190:                }
                    191:                case FETCH_REQUEST_TYPE:
                    192:                {
                    193:                        char header[BUF_LEN];
                    194:                        char *request_type = va_arg(args, char*);
                    195: 
                    196:                        snprintf(header, BUF_LEN, "Content-Type: %s", request_type);
                    197:                        this->headers = curl_slist_append(this->headers, header);
                    198:                        break;
                    199:                }
                    200:                case FETCH_REQUEST_HEADER:
                    201:                {
                    202:                        char *header = va_arg(args, char*);
                    203: 
                    204:                        this->headers = curl_slist_append(this->headers, header);
                    205:                        break;
                    206:                }
                    207:                case FETCH_HTTP_VERSION_1_0:
                    208:                {
                    209:                        curl_easy_setopt(this->curl, CURLOPT_HTTP_VERSION,
                    210:                                                         CURL_HTTP_VERSION_1_0);
                    211:                        break;
                    212:                }
                    213:                case FETCH_TIMEOUT:
                    214:                {
                    215:                        this->timeout = va_arg(args, u_int);
                    216:                        break;
                    217:                }
                    218:                case FETCH_CALLBACK:
                    219:                {
                    220:                        this->cb = va_arg(args, fetcher_callback_t);
                    221:                        break;
                    222:                }
                    223:                case FETCH_RESPONSE_CODE:
                    224:                {
                    225:                        this->result = va_arg(args, u_int*);
                    226:                        break;
                    227:                }
                    228:                case FETCH_SOURCEIP:
                    229:                {
                    230:                        char buf[64];
                    231: 
                    232:                        snprintf(buf, sizeof(buf), "%H", va_arg(args, host_t*));
                    233:                        supported = curl_easy_setopt(this->curl, CURLOPT_INTERFACE,
                    234:                                                                                 buf) == CURLE_OK;
                    235:                        break;
                    236:                }
                    237:                default:
                    238:                        supported = FALSE;
                    239:                        break;
                    240:        }
                    241:        va_end(args);
                    242:        return supported;
                    243: }
                    244: 
                    245: METHOD(fetcher_t, destroy, void,
                    246:        private_curl_fetcher_t *this)
                    247: {
                    248:        curl_slist_free_all(this->headers);
                    249:        curl_easy_cleanup(this->curl);
                    250:        free(this);
                    251: }
                    252: 
                    253: /*
                    254:  * Described in header.
                    255:  */
                    256: curl_fetcher_t *curl_fetcher_create()
                    257: {
                    258:        private_curl_fetcher_t *this;
                    259: 
                    260:        INIT(this,
                    261:                .public = {
                    262:                        .interface = {
                    263:                                .fetch = _fetch,
                    264:                                .set_option = _set_option,
                    265:                                .destroy = _destroy,
                    266:                        },
                    267:                },
                    268:                .curl = curl_easy_init(),
                    269:                .cb = fetcher_default_callback,
                    270:                .redir = lib->settings->get_int(lib->settings, "%s.plugins.curl.redir",
                    271:                                                                                -1, lib->ns),
                    272:        );
                    273: 
                    274:        if (!this->curl)
                    275:        {
                    276:                free(this);
                    277:                return NULL;
                    278:        }
                    279:        return &this->public;
                    280: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>