Return to curl_fetcher.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / curl |
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: }