Annotation of embedaddon/strongswan/src/libstrongswan/plugins/curl/curl_fetcher.c, revision 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>