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
21
22typedef struct {
23    const char *original;
24    const char *current;
25    apr_size_t remaining;
26
27    serf_simple_freefunc_t freefunc;
28    void *baton;
29
30} simple_context_t;
31
32
33static void free_copied_data(void *baton, const char *data)
34{
35    serf_bucket_mem_free(baton, (char*)data);
36}
37
38serf_bucket_t *serf_bucket_simple_create(
39    const char *data,
40    apr_size_t len,
41    serf_simple_freefunc_t freefunc,
42    void *freefunc_baton,
43    serf_bucket_alloc_t *allocator)
44{
45    simple_context_t *ctx;
46
47    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
48    ctx->original = ctx->current = data;
49    ctx->remaining = len;
50    ctx->freefunc = freefunc;
51    ctx->baton = freefunc_baton;
52
53    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
54}
55
56serf_bucket_t *serf_bucket_simple_copy_create(
57    const char *data, apr_size_t len,
58    serf_bucket_alloc_t *allocator)
59{
60    simple_context_t *ctx;
61
62    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
63
64    ctx->original = ctx->current = serf_bucket_mem_alloc(allocator, len);
65    memcpy((char*)ctx->original, data, len);
66
67    ctx->remaining = len;
68    ctx->freefunc = free_copied_data;
69    ctx->baton = allocator;
70
71    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
72}
73
74serf_bucket_t *serf_bucket_simple_own_create(
75    const char *data, apr_size_t len,
76    serf_bucket_alloc_t *allocator)
77{
78    simple_context_t *ctx;
79
80    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
81
82    ctx->original = ctx->current = data;
83
84    ctx->remaining = len;
85    ctx->freefunc = free_copied_data;
86    ctx->baton = allocator;
87
88    return serf_bucket_create(&serf_bucket_type_simple, allocator, ctx);
89}
90
91static apr_status_t serf_simple_read(serf_bucket_t *bucket,
92                                     apr_size_t requested,
93                                     const char **data, apr_size_t *len)
94{
95    simple_context_t *ctx = bucket->data;
96
97    if (requested == SERF_READ_ALL_AVAIL || requested > ctx->remaining)
98        requested = ctx->remaining;
99
100    *data = ctx->current;
101    *len = requested;
102
103    ctx->current += requested;
104    ctx->remaining -= requested;
105
106    return ctx->remaining ? APR_SUCCESS : APR_EOF;
107}
108
109static apr_status_t serf_simple_readline(serf_bucket_t *bucket,
110                                         int acceptable, int *found,
111                                         const char **data, apr_size_t *len)
112{
113    simple_context_t *ctx = bucket->data;
114
115    /* Returned data will be from current position. */
116    *data = ctx->current;
117    serf_util_readline(&ctx->current, &ctx->remaining, acceptable, found);
118
119    /* See how much ctx->current moved forward. */
120    *len = ctx->current - *data;
121
122    return ctx->remaining ? APR_SUCCESS : APR_EOF;
123}
124
125static apr_status_t serf_simple_peek(serf_bucket_t *bucket,
126                                     const char **data,
127                                     apr_size_t *len)
128{
129    simple_context_t *ctx = bucket->data;
130
131    /* return whatever we have left */
132    *data = ctx->current;
133    *len = ctx->remaining;
134
135    /* we returned everything this bucket will ever hold */
136    return APR_EOF;
137}
138
139static void serf_simple_destroy(serf_bucket_t *bucket)
140{
141    simple_context_t *ctx = bucket->data;
142
143    if (ctx->freefunc)
144        (*ctx->freefunc)(ctx->baton, ctx->original);
145
146    serf_default_destroy_and_data(bucket);
147}
148
149
150const serf_bucket_type_t serf_bucket_type_simple = {
151    "SIMPLE",
152    serf_simple_read,
153    serf_simple_readline,
154    serf_default_read_iovec,
155    serf_default_read_for_sendfile,
156    serf_default_read_bucket,
157    serf_simple_peek,
158    serf_simple_destroy,
159};
160