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>