limit_buckets.c revision 251886
1234285Sdim/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein 2234285Sdim * 3234285Sdim * Licensed under the Apache License, Version 2.0 (the "License"); 4234285Sdim * you may not use this file except in compliance with the License. 5234285Sdim * You may obtain a copy of the License at 6234285Sdim * 7234285Sdim * http://www.apache.org/licenses/LICENSE-2.0 8234285Sdim * 9234285Sdim * Unless required by applicable law or agreed to in writing, software 10234285Sdim * distributed under the License is distributed on an "AS IS" BASIS, 11234285Sdim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12234285Sdim * See the License for the specific language governing permissions and 13234285Sdim * limitations under the License. 14234285Sdim */ 15234285Sdim 16234285Sdim#include <apr_pools.h> 17234285Sdim 18234285Sdim#include "serf.h" 19251662Sdim#include "serf_bucket_util.h" 20249423Sdim 21251662Sdim/* Older versions of APR do not have this macro. */ 22234285Sdim#ifdef APR_SIZE_MAX 23234285Sdim#define REQUESTED_MAX APR_SIZE_MAX 24234285Sdim#else 25234285Sdim#define REQUESTED_MAX (~((apr_size_t)0)) 26234285Sdim#endif 27234285Sdim 28234285Sdim 29263508Sdimtypedef struct { 30234285Sdim serf_bucket_t *stream; 31263508Sdim apr_uint64_t remaining; 32251662Sdim} limit_context_t; 33251662Sdim 34234285Sdim 35234285Sdimserf_bucket_t *serf_bucket_limit_create( 36234285Sdim serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator) 37234285Sdim{ 38234285Sdim limit_context_t *ctx; 39234285Sdim 40234285Sdim ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx)); 41234285Sdim ctx->stream = stream; 42234285Sdim ctx->remaining = len; 43234285Sdim 44234285Sdim return serf_bucket_create(&serf_bucket_type_limit, allocator, ctx); 45234285Sdim} 46234285Sdim 47234285Sdimstatic apr_status_t serf_limit_read(serf_bucket_t *bucket, 48234285Sdim apr_size_t requested, 49234285Sdim const char **data, apr_size_t *len) 50234285Sdim{ 51234285Sdim limit_context_t *ctx = bucket->data; 52234285Sdim apr_status_t status; 53234285Sdim 54234285Sdim if (!ctx->remaining) { 55234285Sdim *len = 0; 56234285Sdim return APR_EOF; 57234285Sdim } 58234285Sdim 59234285Sdim if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) { 60234285Sdim if (ctx->remaining <= REQUESTED_MAX) { 61234285Sdim requested = (apr_size_t) ctx->remaining; 62234285Sdim } else { 63234285Sdim requested = REQUESTED_MAX; 64234285Sdim } 65234285Sdim } 66234285Sdim 67234285Sdim status = serf_bucket_read(ctx->stream, requested, data, len); 68234285Sdim 69234285Sdim if (!SERF_BUCKET_READ_ERROR(status)) { 70234285Sdim ctx->remaining -= *len; 71234285Sdim } 72249423Sdim 73249423Sdim /* If we have met our limit and don't have a status, return EOF. */ 74249423Sdim if (!ctx->remaining && !status) { 75249423Sdim status = APR_EOF; 76234285Sdim } 77234285Sdim 78234285Sdim return status; 79234285Sdim} 80234285Sdim 81234285Sdimstatic apr_status_t serf_limit_readline(serf_bucket_t *bucket, 82234285Sdim int acceptable, int *found, 83234285Sdim const char **data, apr_size_t *len) 84234285Sdim{ 85234285Sdim limit_context_t *ctx = bucket->data; 86234285Sdim apr_status_t status; 87234285Sdim 88234285Sdim if (!ctx->remaining) { 89234285Sdim *len = 0; 90234285Sdim return APR_EOF; 91234285Sdim } 92234285Sdim 93234285Sdim status = serf_bucket_readline(ctx->stream, acceptable, found, data, len); 94234285Sdim 95234285Sdim if (!SERF_BUCKET_READ_ERROR(status)) { 96234285Sdim ctx->remaining -= *len; 97234285Sdim } 98234285Sdim 99234285Sdim /* If we have met our limit and don't have a status, return EOF. */ 100234285Sdim if (!ctx->remaining && !status) { 101234285Sdim status = APR_EOF; 102234285Sdim } 103234285Sdim 104234285Sdim return status; 105234285Sdim} 106234285Sdim 107234285Sdimstatic apr_status_t serf_limit_peek(serf_bucket_t *bucket, 108234285Sdim const char **data, 109234285Sdim apr_size_t *len) 110234285Sdim{ 111234285Sdim limit_context_t *ctx = bucket->data; 112234285Sdim 113234285Sdim return serf_bucket_peek(ctx->stream, data, len); 114234285Sdim} 115234285Sdim 116234285Sdimstatic void serf_limit_destroy(serf_bucket_t *bucket) 117251662Sdim{ 118234285Sdim limit_context_t *ctx = bucket->data; 119234285Sdim 120234285Sdim serf_bucket_destroy(ctx->stream); 121234285Sdim 122234285Sdim serf_default_destroy_and_data(bucket); 123239462Sdim} 124234285Sdim 125234285Sdimconst serf_bucket_type_t serf_bucket_type_limit = { 126234285Sdim "LIMIT", 127234285Sdim serf_limit_read, 128234285Sdim serf_limit_readline, 129234285Sdim serf_default_read_iovec, 130234285Sdim serf_default_read_for_sendfile, 131234285Sdim serf_default_read_bucket, 132234285Sdim serf_limit_peek, 133234285Sdim serf_limit_destroy, 134251662Sdim}; 135251662Sdim