|
Packit Service |
d6b4c9 |
/*
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* mod_auth_mellon.c: an authentication apache module
|
|
Packit Service |
d6b4c9 |
* Copyright © 2003-2007 UNINETT (http://www.uninett.no/)
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
d6b4c9 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
d6b4c9 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
d6b4c9 |
* (at your option) any later version.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d6b4c9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d6b4c9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d6b4c9 |
* GNU General Public License for more details.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d6b4c9 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d6b4c9 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
#include "auth_mellon.h"
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
#include <curl/curl.h>
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The size of the blocks we will allocate. */
|
|
Packit Service |
d6b4c9 |
#define AM_HC_BLOCK_SIZE 1000
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
#ifdef APLOG_USE_MODULE
|
|
Packit Service |
d6b4c9 |
APLOG_USE_MODULE(auth_mellon);
|
|
Packit Service |
d6b4c9 |
#endif
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This structure describes a single-linked list of downloaded blocks. */
|
|
Packit Service |
d6b4c9 |
typedef struct am_hc_block_s {
|
|
Packit Service |
d6b4c9 |
/* The next block we have allocated. */
|
|
Packit Service |
d6b4c9 |
struct am_hc_block_s *next;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The number of bytes written to this block. */
|
|
Packit Service |
d6b4c9 |
apr_size_t used;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The data stored in this block. */
|
|
Packit Service |
d6b4c9 |
uint8_t data[AM_HC_BLOCK_SIZE];
|
|
Packit Service |
d6b4c9 |
} am_hc_block_t;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This structure describes a header for the block list. */
|
|
Packit Service |
d6b4c9 |
typedef struct {
|
|
Packit Service |
d6b4c9 |
/* The pool we will allocate memory for new blocks from. */
|
|
Packit Service |
d6b4c9 |
apr_pool_t *pool;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The first block in the linked list of blocks. */
|
|
Packit Service |
d6b4c9 |
am_hc_block_t *first;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The last block in the linked list of blocks. */
|
|
Packit Service |
d6b4c9 |
am_hc_block_t *last;
|
|
Packit Service |
d6b4c9 |
} am_hc_block_header_t;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function allocates and initializes a block for data copying.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* apr_pool_t *pool The pool we should allocate the block from.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* The new block we allocated.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static am_hc_block_t *am_hc_block_alloc(apr_pool_t *pool)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_hc_block_t *blk;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
blk = (am_hc_block_t *)apr_palloc(pool, sizeof(am_hc_block_t));
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
blk->next = NULL;
|
|
Packit Service |
d6b4c9 |
blk->used = 0;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
return blk;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function adds data to the end of a block, and allocates new blocks
|
|
Packit Service |
d6b4c9 |
* if the data doesn't fit in one block.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* am_hc_block_t *block The block we should begin by appending data to.
|
|
Packit Service |
d6b4c9 |
* apr_pool_t *pool The pool we should allocate memory for new blocks
|
|
Packit Service |
d6b4c9 |
* from.
|
|
Packit Service |
d6b4c9 |
* const uint8_t *data The data we should append to the blocks.
|
|
Packit Service |
d6b4c9 |
* apr_size_t size The length of the data we should append.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* The last block written to (i.e. the next block we should write to).
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static am_hc_block_t *am_hc_block_write(
|
|
Packit Service |
d6b4c9 |
am_hc_block_t *block,
|
|
Packit Service |
d6b4c9 |
apr_pool_t *pool,
|
|
Packit Service |
d6b4c9 |
const uint8_t *data, apr_size_t size
|
|
Packit Service |
d6b4c9 |
)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
apr_size_t num_cpy;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
while(size > 0) {
|
|
Packit Service |
d6b4c9 |
/* Find the number of bytes we should write to this block. */
|
|
Packit Service |
d6b4c9 |
num_cpy = AM_HC_BLOCK_SIZE - block->used;
|
|
Packit Service |
d6b4c9 |
if(num_cpy == 0) {
|
|
Packit Service |
d6b4c9 |
/* This block is full -- allocate a new block. */
|
|
Packit Service |
d6b4c9 |
block->next = am_hc_block_alloc(pool);
|
|
Packit Service |
d6b4c9 |
block = block->next;
|
|
Packit Service |
d6b4c9 |
num_cpy = AM_HC_BLOCK_SIZE;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
if(num_cpy > size) {
|
|
Packit Service |
d6b4c9 |
num_cpy = size;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Copy data to this block. */
|
|
Packit Service |
d6b4c9 |
memcpy(&block->data[block->used], data, num_cpy);
|
|
Packit Service |
d6b4c9 |
block->used += num_cpy;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
size -= num_cpy;
|
|
Packit Service |
d6b4c9 |
data += num_cpy;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* The next write should be to this block. */
|
|
Packit Service |
d6b4c9 |
return block;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function initializes a am_hc_block_header_t structure, which
|
|
Packit Service |
d6b4c9 |
* contains information about the linked list of data blocks.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* am_hc_block_header_t *bh Pointer to the data header whcih we
|
|
Packit Service |
d6b4c9 |
* should initialize.
|
|
Packit Service |
d6b4c9 |
* apr_pool_t *pool The pool we should allocate data from.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* Nothing.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static void am_hc_block_header_init(am_hc_block_header_t *bh,
|
|
Packit Service |
d6b4c9 |
apr_pool_t *pool)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
bh->pool = pool;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
bh->first = am_hc_block_alloc(pool);
|
|
Packit Service |
d6b4c9 |
bh->last = bh->first;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function writes data to the linked list of blocks identified by
|
|
Packit Service |
d6b4c9 |
* the stream-parameter. It matches the prototype required by curl.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* void *data The data that should be written. It is size*nmemb
|
|
Packit Service |
d6b4c9 |
* bytes long.
|
|
Packit Service |
d6b4c9 |
* size_t size The size of each block of data that should
|
|
Packit Service |
d6b4c9 |
* be written.
|
|
Packit Service |
d6b4c9 |
* size_t nmemb The number of blocks of data that should be written.
|
|
Packit Service |
d6b4c9 |
* void *block_header A pointer to a am_hc_block_header_t structure which
|
|
Packit Service |
d6b4c9 |
* identifies the linked list we should store data in.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* The number of bytes that have been written.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static size_t am_hc_data_write(void *data, size_t size, size_t nmemb,
|
|
Packit Service |
d6b4c9 |
void *data_header)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_t *bh;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
bh = (am_hc_block_header_t *)data_header;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
bh->last = am_hc_block_write(bh->last, bh->pool, (const uint8_t *)data,
|
|
Packit Service |
d6b4c9 |
size * nmemb);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
return size * nmemb;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function fetches the data which was written to the databuffers
|
|
Packit Service |
d6b4c9 |
* in the linked list which the am_hc_data_t structure keeps track of.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* am_hc_block_header_t *bh The header telling us which data buffers
|
|
Packit Service |
d6b4c9 |
* we should extract data from.
|
|
Packit Service |
d6b4c9 |
* apr_pool_t *pool The pool we should allocate the data
|
|
Packit Service |
d6b4c9 |
* buffer from.
|
|
Packit Service |
d6b4c9 |
* void **buffer A pointer to where we should store a pointer
|
|
Packit Service |
d6b4c9 |
* to the data buffer we allocate. We will
|
|
Packit Service |
d6b4c9 |
* always add a null-terminator to the end of
|
|
Packit Service |
d6b4c9 |
* data buffer. This parameter can't be NULL.
|
|
Packit Service |
d6b4c9 |
* apr_size_t *size This is a pointer to where we will store the
|
|
Packit Service |
d6b4c9 |
* length of the data, not including the
|
|
Packit Service |
d6b4c9 |
* null-terminator we add. This parameter can
|
|
Packit Service |
d6b4c9 |
* be NULL.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* Nothing.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static void am_hc_data_extract(am_hc_block_header_t *bh, apr_pool_t *pool,
|
|
Packit Service |
d6b4c9 |
void **buffer, apr_size_t *size)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_hc_block_t *blk;
|
|
Packit Service |
d6b4c9 |
apr_size_t length;
|
|
Packit Service |
d6b4c9 |
uint8_t *buf;
|
|
Packit Service |
d6b4c9 |
apr_size_t pos;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* First we find the length of the data. */
|
|
Packit Service |
d6b4c9 |
length = 0;
|
|
Packit Service |
d6b4c9 |
for(blk = bh->first; blk != NULL; blk = blk->next) {
|
|
Packit Service |
d6b4c9 |
length += blk->used;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Allocate memory for the data. Add one to the size in order to
|
|
Packit Service |
d6b4c9 |
* have space for the null-terminator.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
buf = (uint8_t *)apr_palloc(pool, length + 1);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Copy the data into the buffer. */
|
|
Packit Service |
d6b4c9 |
pos = 0;
|
|
Packit Service |
d6b4c9 |
for(blk = bh->first; blk != NULL; blk = blk->next) {
|
|
Packit Service |
d6b4c9 |
memcpy(&buf[pos], blk->data, blk->used);
|
|
Packit Service |
d6b4c9 |
pos += blk->used;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Add the null-terminator. */
|
|
Packit Service |
d6b4c9 |
buf[length] = 0;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set up the return values. */
|
|
Packit Service |
d6b4c9 |
*buffer = (void *)buf;
|
|
Packit Service |
d6b4c9 |
if(size != NULL) {
|
|
Packit Service |
d6b4c9 |
*size = length;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function creates a curl object and performs generic initialization
|
|
Packit Service |
d6b4c9 |
* of it.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* request_rec *r The request we should log errors against.
|
|
Packit Service |
d6b4c9 |
* const char *uri The URI we should request.
|
|
Packit Service |
d6b4c9 |
* am_hc_block_header_t *bh The buffer curl will write response data to.
|
|
Packit Service |
d6b4c9 |
* char *curl_error A buffer of size CURL_ERROR_SIZE where curl
|
|
Packit Service |
d6b4c9 |
* will store error messages.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* A initialized curl object on succcess, or NULL on error.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
static CURL *am_httpclient_init_curl(request_rec *r, const char *uri,
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_t *bh,
|
|
Packit Service |
d6b4c9 |
char *curl_error)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
|
Packit Service |
d6b4c9 |
CURL *curl;
|
|
Packit Service |
d6b4c9 |
CURLcode res;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Initialize the curl object. */
|
|
Packit Service |
d6b4c9 |
curl = curl_easy_init();
|
|
Packit Service |
d6b4c9 |
if(curl == NULL) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to initialize a curl object.");
|
|
Packit Service |
d6b4c9 |
return NULL;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set up error reporting. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set curl error buffer: [%u]\n", res);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Disable progress reporting. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to disable curl progress reporting: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Disable use of signals. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to disable signals in curl: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set the timeout of the transfer. It is currently set to two minutes. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120L);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set the timeout of the curl download:"
|
|
Packit Service |
d6b4c9 |
" [%u] %s", res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* If we have a CA configured, try to use it */
|
|
Packit Service |
d6b4c9 |
if (cfg->idp_ca_file != NULL) {
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_CAINFO, cfg->idp_ca_file->path);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set SSL CA info %s:"
|
|
Packit Service |
d6b4c9 |
" [%u] %s", cfg->idp_ca_file->path, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Enable fail on http error. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to enable failure on http error: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Select which uri we should download. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_URL, uri);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set curl download uri to \"%s\": [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set up data writing. */
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set curl write function. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, am_hc_data_write);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set the curl write function: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set the curl write function parameter. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, bh);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set the curl write function data: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
return curl;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
cleanup_fail:
|
|
Packit Service |
d6b4c9 |
curl_easy_cleanup(curl);
|
|
Packit Service |
d6b4c9 |
return NULL;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function downloads data from a specified URI, with specified timeout
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* request_rec *r The apache request this download is associated
|
|
Packit Service |
d6b4c9 |
* with. It is used for memory allocation and logging.
|
|
Packit Service |
d6b4c9 |
* const char *uri The URI we should download.
|
|
Packit Service |
d6b4c9 |
* void **buffer A pointer to where we should store a pointer to the
|
|
Packit Service |
d6b4c9 |
* downloaded data. We will always add a null-terminator
|
|
Packit Service |
d6b4c9 |
* to the data. This parameter can't be NULL.
|
|
Packit Service |
d6b4c9 |
* apr_size_t *size This is a pointer to where we will store the length
|
|
Packit Service |
d6b4c9 |
* of the downloaded data, not including the
|
|
Packit Service |
d6b4c9 |
* null-terminator we add. This parameter can be NULL.
|
|
Packit Service |
d6b4c9 |
* int timeout Timeout in seconds, 0 for no timeout.
|
|
Packit Service |
d6b4c9 |
* long *status Pointer to HTTP status code.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* OK on success, or HTTP_INTERNAL_SERVER_ERROR on failure. On failure we
|
|
Packit Service |
d6b4c9 |
* will write a log message describing the error.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
int am_httpclient_get(request_rec *r, const char *uri,
|
|
Packit Service |
d6b4c9 |
void **buffer, apr_size_t *size,
|
|
Packit Service |
d6b4c9 |
int timeout, long *status)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_t bh;
|
|
Packit Service |
d6b4c9 |
CURL *curl;
|
|
Packit Service |
d6b4c9 |
char curl_error[CURL_ERROR_SIZE];
|
|
Packit Service |
d6b4c9 |
CURLcode res;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Initialize the data storage. */
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_init(&bh, r->pool);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Initialize the curl object. */
|
|
Packit Service |
d6b4c9 |
curl = am_httpclient_init_curl(r, uri, &bh, curl_error);
|
|
Packit Service |
d6b4c9 |
if(curl == NULL) {
|
|
Packit Service |
d6b4c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)timeout);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to download data from the uri \"%s\", "
|
|
Packit Service |
d6b4c9 |
"cannot set timeout to %ld: [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, (long)timeout, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, (long)timeout);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to download data from the uri \"%s\", "
|
|
Packit Service |
d6b4c9 |
"cannot set connect timeout to %ld: [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, (long)timeout, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Do the download. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_perform(curl);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to download data from the uri \"%s\", "
|
|
Packit Service |
d6b4c9 |
"transaction aborted: [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
if (status != NULL) {
|
|
Packit Service |
d6b4c9 |
res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to download data from the uri \"%s\", "
|
|
Packit Service |
d6b4c9 |
"no status report: [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Free the curl object. */
|
|
Packit Service |
d6b4c9 |
curl_easy_cleanup(curl);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Copy the data. */
|
|
Packit Service |
d6b4c9 |
am_hc_data_extract(&bh, r->pool, buffer, size);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
return OK;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
cleanup_fail:
|
|
Packit Service |
d6b4c9 |
curl_easy_cleanup(curl);
|
|
Packit Service |
d6b4c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function downloads data from a specified URI by issuing a POST
|
|
Packit Service |
d6b4c9 |
* request.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* request_rec *r The apache request this download is
|
|
Packit Service |
d6b4c9 |
* associated with. It is used for memory
|
|
Packit Service |
d6b4c9 |
* allocation and logging.
|
|
Packit Service |
d6b4c9 |
* const char *uri The URI we should post data to.
|
|
Packit Service |
d6b4c9 |
* const void *post_data The POST data we should send.
|
|
Packit Service |
d6b4c9 |
* apr_size_t post_length The length of the POST data.
|
|
Packit Service |
d6b4c9 |
* const char *content_type The content type of the POST data. This
|
|
Packit Service |
d6b4c9 |
* parameter can be NULL, in which case the
|
|
Packit Service |
d6b4c9 |
* content type will be
|
|
Packit Service |
d6b4c9 |
* "application/x-www-form-urlencoded".
|
|
Packit Service |
d6b4c9 |
* void **buffer A pointer to where we should store a pointer
|
|
Packit Service |
d6b4c9 |
* to the downloaded data. We will always add a
|
|
Packit Service |
d6b4c9 |
* null-terminator to the data. This parameter
|
|
Packit Service |
d6b4c9 |
* can't be NULL.
|
|
Packit Service |
d6b4c9 |
* apr_size_t *size This is a pointer to where we will store the
|
|
Packit Service |
d6b4c9 |
* length of the downloaded data, not including
|
|
Packit Service |
d6b4c9 |
* the null-terminator we add. This parameter
|
|
Packit Service |
d6b4c9 |
* can be NULL.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* OK on success. On failure we will write a log message describing the
|
|
Packit Service |
d6b4c9 |
* error, and return HTTP_INTERNAL_SERVER_ERROR.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
int am_httpclient_post(request_rec *r, const char *uri,
|
|
Packit Service |
d6b4c9 |
const void *post_data, apr_size_t post_length,
|
|
Packit Service |
d6b4c9 |
const char *content_type,
|
|
Packit Service |
d6b4c9 |
void **buffer, apr_size_t *size)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_t bh;
|
|
Packit Service |
d6b4c9 |
CURL *curl;
|
|
Packit Service |
d6b4c9 |
char curl_error[CURL_ERROR_SIZE];
|
|
Packit Service |
d6b4c9 |
CURLcode res;
|
|
Packit Service |
d6b4c9 |
struct curl_slist *ctheader;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Initialize the data storage. */
|
|
Packit Service |
d6b4c9 |
am_hc_block_header_init(&bh, r->pool);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Initialize the curl object. */
|
|
Packit Service |
d6b4c9 |
curl = am_httpclient_init_curl(r, uri, &bh, curl_error);
|
|
Packit Service |
d6b4c9 |
if(curl == NULL) {
|
|
Packit Service |
d6b4c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Enable POST request. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to enable POST request: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set POST data size. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_length);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set the POST data length: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set POST data. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set the POST data: [%u] %s",
|
|
Packit Service |
d6b4c9 |
res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set the content-type header. */
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set default content type if content_type is NULL. */
|
|
Packit Service |
d6b4c9 |
if(content_type == NULL) {
|
|
Packit Service |
d6b4c9 |
content_type = "application/x-www-form-urlencoded";
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Create header list. */
|
|
Packit Service |
d6b4c9 |
ctheader = NULL;
|
|
Packit Service |
d6b4c9 |
ctheader = curl_slist_append(ctheader, apr_pstrcat(
|
|
Packit Service |
d6b4c9 |
r->pool,
|
|
Packit Service |
d6b4c9 |
"Content-Type: ",
|
|
Packit Service |
d6b4c9 |
content_type,
|
|
Packit Service |
d6b4c9 |
NULL
|
|
Packit Service |
d6b4c9 |
));
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Set headers. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, ctheader);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to set content-type header to \"%s\": [%u] %s",
|
|
Packit Service |
d6b4c9 |
content_type, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Do the download. */
|
|
Packit Service |
d6b4c9 |
res = curl_easy_perform(curl);
|
|
Packit Service |
d6b4c9 |
if(res != CURLE_OK) {
|
|
Packit Service |
d6b4c9 |
AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r,
|
|
Packit Service |
d6b4c9 |
"Failed to download data from the uri \"%s\": [%u] %s",
|
|
Packit Service |
d6b4c9 |
uri, res, curl_error);
|
|
Packit Service |
d6b4c9 |
goto cleanup_fail;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Free the curl object. */
|
|
Packit Service |
d6b4c9 |
curl_easy_cleanup(curl);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Free the content-type header. */
|
|
Packit Service |
d6b4c9 |
curl_slist_free_all(ctheader);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* Copy the data. */
|
|
Packit Service |
d6b4c9 |
am_hc_data_extract(&bh, r->pool, buffer, size);
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
return OK;
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
cleanup_fail:
|
|
Packit Service |
d6b4c9 |
curl_easy_cleanup(curl);
|
|
Packit Service |
d6b4c9 |
return HTTP_INTERNAL_SERVER_ERROR;
|
|
Packit Service |
d6b4c9 |
}
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
|
|
Packit Service |
d6b4c9 |
/* This function downloads data from a specified URI by issuing a POST
|
|
Packit Service |
d6b4c9 |
* request.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Parameters:
|
|
Packit Service |
d6b4c9 |
* request_rec *r The apache request this download is
|
|
Packit Service |
d6b4c9 |
* associated with. It is used for memory
|
|
Packit Service |
d6b4c9 |
* allocation and logging.
|
|
Packit Service |
d6b4c9 |
* const char *uri The URI we should post data to.
|
|
Packit Service |
d6b4c9 |
* const char *post_data The POST data we should send.
|
|
Packit Service |
d6b4c9 |
* const char *content_type The content type of the POST data. This
|
|
Packit Service |
d6b4c9 |
* parameter can be NULL, in which case the
|
|
Packit Service |
d6b4c9 |
* content type will be
|
|
Packit Service |
d6b4c9 |
* "application/x-www-form-urlencoded".
|
|
Packit Service |
d6b4c9 |
* void **buffer A pointer to where we should store a pointer
|
|
Packit Service |
d6b4c9 |
* to the downloaded data. We will always add a
|
|
Packit Service |
d6b4c9 |
* null-terminator to the data. This parameter
|
|
Packit Service |
d6b4c9 |
* can't be NULL.
|
|
Packit Service |
d6b4c9 |
* apr_size_t *size This is a pointer to where we will store the
|
|
Packit Service |
d6b4c9 |
* length of the downloaded data, not including
|
|
Packit Service |
d6b4c9 |
* the null-terminator we add. This parameter
|
|
Packit Service |
d6b4c9 |
* can be NULL.
|
|
Packit Service |
d6b4c9 |
*
|
|
Packit Service |
d6b4c9 |
* Returns:
|
|
Packit Service |
d6b4c9 |
* OK on success. On failure we will write a log message describing the
|
|
Packit Service |
d6b4c9 |
* error, and return HTTP_INTERNAL_SERVER_ERROR.
|
|
Packit Service |
d6b4c9 |
*/
|
|
Packit Service |
d6b4c9 |
int am_httpclient_post_str(request_rec *r, const char *uri,
|
|
Packit Service |
d6b4c9 |
const char *post_data,
|
|
Packit Service |
d6b4c9 |
const char *content_type,
|
|
Packit Service |
d6b4c9 |
void **buffer, apr_size_t *size)
|
|
Packit Service |
d6b4c9 |
{
|
|
Packit Service |
d6b4c9 |
return am_httpclient_post(r, uri, post_data, strlen(post_data),
|
|
Packit Service |
d6b4c9 |
content_type, buffer, size);
|
|
Packit Service |
d6b4c9 |
}
|