1/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <apr_pools.h> 17 18#include "serf.h" 19#include "serf_bucket_util.h" 20#include "serf_private.h" 21 22typedef struct { 23 serf_bucket_t *stream; 24 apr_uint64_t remaining; 25} limit_context_t; 26 27 28serf_bucket_t *serf_bucket_limit_create( 29 serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator) 30{ 31 limit_context_t *ctx; 32 33 ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx)); 34 ctx->stream = stream; 35 ctx->remaining = len; 36 37 return serf_bucket_create(&serf_bucket_type_limit, allocator, ctx); 38} 39 40static apr_status_t serf_limit_read(serf_bucket_t *bucket, 41 apr_size_t requested, 42 const char **data, apr_size_t *len) 43{ 44 limit_context_t *ctx = bucket->data; 45 apr_status_t status; 46 47 if (!ctx->remaining) { 48 *len = 0; 49 return APR_EOF; 50 } 51 52 if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) { 53 if (ctx->remaining <= REQUESTED_MAX) { 54 requested = (apr_size_t) ctx->remaining; 55 } else { 56 requested = REQUESTED_MAX; 57 } 58 } 59 60 status = serf_bucket_read(ctx->stream, requested, data, len); 61 62 if (!SERF_BUCKET_READ_ERROR(status)) { 63 ctx->remaining -= *len; 64 } 65 66 /* If we have met our limit and don't have a status, return EOF. */ 67 if (!ctx->remaining && !status) { 68 status = APR_EOF; 69 } 70 71 return status; 72} 73 74static apr_status_t serf_limit_readline(serf_bucket_t *bucket, 75 int acceptable, int *found, 76 const char **data, apr_size_t *len) 77{ 78 limit_context_t *ctx = bucket->data; 79 apr_status_t status; 80 81 if (!ctx->remaining) { 82 *len = 0; 83 return APR_EOF; 84 } 85 86 status = serf_bucket_readline(ctx->stream, acceptable, found, data, len); 87 88 if (!SERF_BUCKET_READ_ERROR(status)) { 89 ctx->remaining -= *len; 90 } 91 92 /* If we have met our limit and don't have a status, return EOF. */ 93 if (!ctx->remaining && !status) { 94 status = APR_EOF; 95 } 96 97 return status; 98} 99 100static apr_status_t serf_limit_peek(serf_bucket_t *bucket, 101 const char **data, 102 apr_size_t *len) 103{ 104 limit_context_t *ctx = bucket->data; 105 106 return serf_bucket_peek(ctx->stream, data, len); 107} 108 109static void serf_limit_destroy(serf_bucket_t *bucket) 110{ 111 limit_context_t *ctx = bucket->data; 112 113 serf_bucket_destroy(ctx->stream); 114 115 serf_default_destroy_and_data(bucket); 116} 117 118const serf_bucket_type_t serf_bucket_type_limit = { 119 "LIMIT", 120 serf_limit_read, 121 serf_limit_readline, 122 serf_default_read_iovec, 123 serf_default_read_for_sendfile, 124 serf_default_read_bucket, 125 serf_limit_peek, 126 serf_limit_destroy, 127}; 128