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