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