blob: 74193ad00cf64c06b16016e6bdc7bd189119347c [file] [log] [blame]
/* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#include "serf.h"
#include "serf_private.h"
#include "serf_bucket_util.h"
/* TODO: don't use SOCK[_MSG]_VERBOSE directly, but get a log category in
from the config object. */
typedef struct log_wrapped_context_t {
const serf_bucket_type_t *old_type;
const char *prefix;
serf_config_t *config;
} log_wrapped_context_t;
/* Extended serf_bucket_t. */
typedef struct serf_log_wrapped_bucket_t {
/* This must be the first member to ensure that this bucket can be cast
to a serf_bucket_t */
serf_bucket_t wrapped_bkt;
/* stored data for the log wrapper */
log_wrapped_context_t *more_data;
} serf_log_wrapped_bucket_t;
static apr_status_t
serf_log_wrapped_readline(serf_bucket_t *bucket,
int acceptable, int *found,
const char **data, apr_size_t *len)
{
serf_log_wrapped_bucket_t *lwbkt = (serf_log_wrapped_bucket_t *)bucket;
log_wrapped_context_t *ctx = lwbkt->more_data;
apr_status_t status = ctx->old_type->readline(bucket, acceptable, found,
data, len);
if (SERF_BUCKET_READ_ERROR(status))
serf__log(LOGLVL_ERROR, LOGCOMP_CONN, ctx->prefix, ctx->config,
"Error %d while reading.\n", status);
if (*len) {
serf__log(LOGLVL_DEBUG, LOGCOMP_CONN, ctx->prefix, ctx->config,
"--- %"APR_SIZE_T_FMT" bytes. --\n", *len);
serf__log(LOGLVL_DEBUG, LOGCOMP_RAWMSG, ctx->prefix, ctx->config,
"%.*s\n", *len, *data);
}
return status;
}
static apr_status_t
serf_log_wrapped_read_iovec(serf_bucket_t *bucket,
apr_size_t requested,
int vecs_size,
struct iovec *vecs,
int *vecs_used)
{
serf_log_wrapped_bucket_t *lwbkt = (serf_log_wrapped_bucket_t *)bucket;
log_wrapped_context_t *ctx = lwbkt->more_data;
apr_size_t len;
int i;
apr_status_t status = ctx->old_type->read_iovec(bucket, requested, vecs_size,
vecs, vecs_used);
if (SERF_BUCKET_READ_ERROR(status))
serf__log(LOGLVL_ERROR, LOGCOMP_CONN, ctx->prefix, ctx->config,
"Error %d while reading.\n", status);
for (i = 0, len = 0; i < *vecs_used; i++)
len += vecs[i].iov_len;
serf__log(LOGLVL_DEBUG, LOGCOMP_CONN, ctx->prefix, ctx->config,
"--- %"APR_SIZE_T_FMT" bytes. --\n", len);
for (i = 0; i < *vecs_used; i++) {
serf__log_nopref(LOGLVL_DEBUG, LOGCOMP_RAWMSG, ctx->config,
"%.*s", vecs[i].iov_len, vecs[i].iov_base);
}
serf__log_nopref(LOGLVL_DEBUG, LOGCOMP_RAWMSG, ctx->config, "\n");
return status;
}
static apr_status_t
serf_log_wrapped_read(serf_bucket_t *bucket, apr_size_t requested,
const char **data, apr_size_t *len)
{
serf_log_wrapped_bucket_t *lwbkt = (serf_log_wrapped_bucket_t *)bucket;
log_wrapped_context_t *ctx = lwbkt->more_data;
apr_status_t status = ctx->old_type->read(bucket, requested, data, len);
if (SERF_BUCKET_READ_ERROR(status))
serf__log(LOGLVL_ERROR, LOGCOMP_CONN, ctx->prefix, ctx->config,
"Error %d while reading.\n", status);
else if (*len) {
serf__log(LOGLVL_DEBUG, LOGCOMP_CONN, ctx->prefix, ctx->config,
"--- %"APR_SIZE_T_FMT" bytes. --\n", *len);
serf__log(LOGLVL_DEBUG, LOGCOMP_RAWMSG, ctx->prefix, ctx->config,
"%.*s\n", *len, *data);
}
return status;
}
static void serf_log_wrapped_destroy(serf_bucket_t *bucket)
{
serf_log_wrapped_bucket_t *lwbkt = (serf_log_wrapped_bucket_t *)bucket;
const serf_bucket_type_t *bkt_type = lwbkt->more_data->old_type;
serf_bucket_mem_free(bucket->allocator, (void*)bucket->type);
serf_bucket_mem_free(bucket->allocator, lwbkt->more_data);
bkt_type->destroy(bucket);
}
static apr_status_t serf_log_wrapped_set_config(serf_bucket_t *bucket,
serf_config_t *config)
{
serf_log_wrapped_bucket_t *lwbkt = (serf_log_wrapped_bucket_t *)bucket;
log_wrapped_context_t *ctx = lwbkt->more_data;
ctx->config = config;
return ctx->old_type->set_config(bucket, config);
}
serf_bucket_t *serf__bucket_log_wrapper_create(serf_bucket_t *wrapped,
const char *prefix,
serf_bucket_alloc_t *alloc)
{
/* ### This code currently breaks SERF_BUCKET_IS_XXXX() on the bucket.
So to avoid many false warnings we disable it when using
SERF_DEBUG_BUCKET_USE
*/
#if defined(SERF_LOGGING_ENABLED) && !defined(SERF_DEBUG_BUCKET_USE)
serf_log_wrapped_bucket_t *bkt = serf_bucket_mem_alloc(alloc, sizeof(*bkt));
log_wrapped_context_t *ctx = serf_bucket_mem_alloc(alloc, sizeof(*ctx));
serf_bucket_type_t *bkt_type = serf_bucket_mem_alloc(alloc, sizeof(*bkt_type));
/* Construct the new bucket type based on the wrapped bucket type, but
replace all read functions with the logging wrappers. */
bkt_type->name = wrapped->type->name;
bkt_type->peek = wrapped->type->peek;
/* These read functions are not used by serf, so no need to add logging. */
bkt_type->read_for_sendfile = wrapped->type->read_for_sendfile;
if (serf_get_type(wrapped, 2) != NULL) {
bkt_type->read_bucket = serf_buckets_are_v2;
bkt_type->read_bucket_v2 = wrapped->type->read_bucket_v2;
bkt_type->get_remaining = wrapped->type->get_remaining;
} else {
bkt_type->read_bucket = wrapped->type->read_bucket;
}
/* Wrap these functions */
bkt_type->destroy = serf_log_wrapped_destroy;
bkt_type->read = serf_log_wrapped_read;
bkt_type->readline = serf_log_wrapped_readline;
bkt_type->read_iovec = serf_log_wrapped_read_iovec;
bkt_type->set_config = serf_log_wrapped_set_config;
ctx->old_type = wrapped->type;
ctx->prefix = prefix;
ctx->config = NULL;
/* Construct the new extended bucket. */
bkt->wrapped_bkt.type = bkt_type;
bkt->wrapped_bkt.data = wrapped->data;
bkt->wrapped_bkt.allocator = wrapped->allocator;
bkt->more_data = ctx;
/* We have created a new extended bucket and copied over the data from the
wrapped bucket, so we can delete the wrapped bucket now. */
serf_default_destroy(wrapped);
return (serf_bucket_t *)bkt;
#else
return wrapped;
#endif
}