limit_buckets.c revision 251877
1193323Sed/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
2193323Sed *
3193323Sed * Licensed under the Apache License, Version 2.0 (the "License");
4193323Sed * you may not use this file except in compliance with the License.
5193323Sed * You may obtain a copy of the License at
6193323Sed *
7193323Sed *     http://www.apache.org/licenses/LICENSE-2.0
8193323Sed *
9193323Sed * Unless required by applicable law or agreed to in writing, software
10193323Sed * distributed under the License is distributed on an "AS IS" BASIS,
11193323Sed * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12193323Sed * See the License for the specific language governing permissions and
13193323Sed * limitations under the License.
14193323Sed */
15193323Sed
16193323Sed#include <apr_pools.h>
17193323Sed
18249423Sdim#include "serf.h"
19249423Sdim#include "serf_bucket_util.h"
20193323Sed
21198090Srdivacky/* Older versions of APR do not have this macro.  */
22198090Srdivacky#ifdef APR_SIZE_MAX
23193323Sed#define REQUESTED_MAX APR_SIZE_MAX
24193323Sed#else
25193323Sed#define REQUESTED_MAX (~((apr_size_t)0))
26193323Sed#endif
27193323Sed
28193323Sed
29193323Sedtypedef struct {
30193323Sed    serf_bucket_t *stream;
31193323Sed    apr_uint64_t remaining;
32193323Sed} limit_context_t;
33193323Sed
34193323Sed
35193323Sedserf_bucket_t *serf_bucket_limit_create(
36193323Sed    serf_bucket_t *stream, apr_uint64_t len, serf_bucket_alloc_t *allocator)
37193323Sed{
38193323Sed    limit_context_t *ctx;
39193323Sed
40193323Sed    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
41193323Sed    ctx->stream = stream;
42193323Sed    ctx->remaining = len;
43193323Sed
44193323Sed    return serf_bucket_create(&serf_bucket_type_limit, allocator, ctx);
45193323Sed}
46193323Sed
47193323Sedstatic apr_status_t serf_limit_read(serf_bucket_t *bucket,
48193323Sed                                    apr_size_t requested,
49193323Sed                                    const char **data, apr_size_t *len)
50193323Sed{
51193323Sed    limit_context_t *ctx = bucket->data;
52193323Sed    apr_status_t status;
53193323Sed
54193323Sed    if (!ctx->remaining) {
55193323Sed        *len = 0;
56193323Sed        return APR_EOF;
57193323Sed    }
58193323Sed
59193323Sed    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining) {
60193323Sed        if (ctx->remaining <= REQUESTED_MAX) {
61193323Sed            requested = (apr_size_t) ctx->remaining;
62193323Sed        } else {
63193323Sed            requested = REQUESTED_MAX;
64193323Sed        }
65193323Sed    }
66193323Sed
67199989Srdivacky    status = serf_bucket_read(ctx->stream, requested, data, len);
68199989Srdivacky
69199989Srdivacky    if (!SERF_BUCKET_READ_ERROR(status)) {
70199989Srdivacky        ctx->remaining -= *len;
71199989Srdivacky    }
72199989Srdivacky
73193323Sed    /* If we have met our limit and don't have a status, return EOF. */
74193323Sed    if (!ctx->remaining && !status) {
75193323Sed        status = APR_EOF;
76193323Sed    }
77193323Sed
78193323Sed    return status;
79193323Sed}
80193323Sed
81193323Sedstatic apr_status_t serf_limit_readline(serf_bucket_t *bucket,
82193323Sed                                         int acceptable, int *found,
83193323Sed                                         const char **data, apr_size_t *len)
84193323Sed{
85193323Sed    limit_context_t *ctx = bucket->data;
86193323Sed    apr_status_t status;
87193323Sed
88193323Sed    if (!ctx->remaining) {
89193323Sed        *len = 0;
90193323Sed        return APR_EOF;
91193323Sed    }
92193323Sed
93193323Sed    status = serf_bucket_readline(ctx->stream, acceptable, found, data, len);
94193323Sed
95193323Sed    if (!SERF_BUCKET_READ_ERROR(status)) {
96193323Sed        ctx->remaining -= *len;
97193323Sed    }
98193323Sed
99193323Sed    /* If we have met our limit and don't have a status, return EOF. */
100193323Sed    if (!ctx->remaining && !status) {
101193323Sed        status = APR_EOF;
102193323Sed    }
103193323Sed
104193323Sed    return status;
105193323Sed}
106193323Sed
107193323Sedstatic apr_status_t serf_limit_peek(serf_bucket_t *bucket,
108193323Sed                                     const char **data,
109193323Sed                                     apr_size_t *len)
110193323Sed{
111193323Sed    limit_context_t *ctx = bucket->data;
112193323Sed
113193323Sed    return serf_bucket_peek(ctx->stream, data, len);
114193323Sed}
115193323Sed
116193323Sedstatic void serf_limit_destroy(serf_bucket_t *bucket)
117193323Sed{
118193323Sed    limit_context_t *ctx = bucket->data;
119193323Sed
120193323Sed    serf_bucket_destroy(ctx->stream);
121199989Srdivacky
122199989Srdivacky    serf_default_destroy_and_data(bucket);
123199989Srdivacky}
124199989Srdivacky
125199989Srdivackyconst serf_bucket_type_t serf_bucket_type_limit = {
126202375Srdivacky    "LIMIT",
127193323Sed    serf_limit_read,
128193323Sed    serf_limit_readline,
129193323Sed    serf_default_read_iovec,
130193323Sed    serf_default_read_for_sendfile,
131202375Srdivacky    serf_default_read_bucket,
132193323Sed    serf_limit_peek,
133193323Sed    serf_limit_destroy,
134193323Sed};
135193323Sed