1 /*
2 * sb_bucket.c : a serf bucket that wraps a spillbuf
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24 #include <serf.h>
25 #include <serf_bucket_util.h>
26
27 #include "svn_private_config.h"
28 #include "private/svn_subr_private.h"
29
30 #include "ra_serf.h"
31
32 #define SB_BLOCKSIZE 1024
33 #define SB_MAXSIZE 32768
34
35
36 struct sbb_baton
37 {
38 svn_spillbuf_t *spillbuf;
39
40 const char *holding;
41 apr_size_t hold_len;
42
43 apr_pool_t *scratch_pool;
44 };
45
46
47 svn_error_t *
svn_ra_serf__copy_into_spillbuf(svn_spillbuf_t ** spillbuf,serf_bucket_t * bkt,apr_pool_t * result_pool,apr_pool_t * scratch_pool)48 svn_ra_serf__copy_into_spillbuf(svn_spillbuf_t **spillbuf,
49 serf_bucket_t *bkt,
50 apr_pool_t *result_pool,
51 apr_pool_t *scratch_pool)
52 {
53 *spillbuf = svn_spillbuf__create(SB_BLOCKSIZE, SB_MAXSIZE, result_pool);
54
55 /* Copy all data from the bucket into the spillbuf. */
56 while (TRUE)
57 {
58 apr_status_t status;
59 const char *data;
60 apr_size_t len;
61
62 status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
63
64 if (status != APR_SUCCESS && status != APR_EOF)
65 return svn_ra_serf__wrap_err(status, _("Failed to read the request"));
66
67 SVN_ERR(svn_spillbuf__write(*spillbuf, data, len, scratch_pool));
68
69 if (status == APR_EOF)
70 break;
71 }
72
73 return SVN_NO_ERROR;
74 }
75
76
77 static apr_status_t
sb_bucket_read(serf_bucket_t * bucket,apr_size_t requested,const char ** data,apr_size_t * len)78 sb_bucket_read(serf_bucket_t *bucket, apr_size_t requested,
79 const char **data, apr_size_t *len)
80 {
81 struct sbb_baton *sbb = bucket->data;
82 svn_error_t *err;
83
84 if (sbb->holding)
85 {
86 *data = sbb->holding;
87
88 if (requested < sbb->hold_len)
89 {
90 *len = requested;
91 sbb->holding += requested;
92 sbb->hold_len -= requested;
93 return APR_SUCCESS;
94 }
95
96 /* Return whatever we're holding, and then forget (consume) it. */
97 *len = sbb->hold_len;
98 sbb->holding = NULL;
99 return APR_SUCCESS;
100 }
101
102 err = svn_spillbuf__read(data, len, sbb->spillbuf, sbb->scratch_pool);
103 svn_pool_clear(sbb->scratch_pool);
104
105 /* ### do something with this */
106 svn_error_clear(err);
107
108 /* The spillbuf may have returned more than requested. Stash any extra
109 into our holding area. */
110 if (requested < *len)
111 {
112 sbb->holding = *data + requested;
113 sbb->hold_len = *len - requested;
114 *len = requested;
115 }
116
117 return *data == NULL ? APR_EOF : APR_SUCCESS;
118 }
119
120 #if !SERF_VERSION_AT_LEAST(1, 4, 0)
121 static apr_status_t
sb_bucket_readline(serf_bucket_t * bucket,int acceptable,int * found,const char ** data,apr_size_t * len)122 sb_bucket_readline(serf_bucket_t *bucket, int acceptable,
123 int *found,
124 const char **data, apr_size_t *len)
125 {
126 /* ### for now, we know callers won't use this function. */
127 svn_error_clear(svn_error__malfunction(TRUE, __FILE__, __LINE__,
128 "Not implemented."));
129 return APR_ENOTIMPL;
130 }
131 #endif
132
133
134 static apr_status_t
sb_bucket_peek(serf_bucket_t * bucket,const char ** data,apr_size_t * len)135 sb_bucket_peek(serf_bucket_t *bucket,
136 const char **data, apr_size_t *len)
137 {
138 struct sbb_baton *sbb = bucket->data;
139 svn_error_t *err;
140
141 /* If we're not holding any data, then fill it. */
142 if (sbb->holding == NULL)
143 {
144 err = svn_spillbuf__read(&sbb->holding, &sbb->hold_len, sbb->spillbuf,
145 sbb->scratch_pool);
146 svn_pool_clear(sbb->scratch_pool);
147
148 /* ### do something with this */
149 svn_error_clear(err);
150 }
151
152 /* Return the data we are (now) holding. */
153 *data = sbb->holding;
154 *len = sbb->hold_len;
155
156 return *data == NULL ? APR_EOF : APR_SUCCESS;
157 }
158
159
160 static const serf_bucket_type_t sb_bucket_vtable = {
161 "SPILLBUF",
162 sb_bucket_read,
163 #if SERF_VERSION_AT_LEAST(1, 4, 0)
164 serf_default_readline,
165 #else
166 sb_bucket_readline,
167 #endif
168 serf_default_read_iovec,
169 serf_default_read_for_sendfile,
170 serf_default_read_bucket,
171 sb_bucket_peek,
172 serf_default_destroy_and_data,
173 };
174
175
176 serf_bucket_t *
svn_ra_serf__create_sb_bucket(svn_spillbuf_t * spillbuf,serf_bucket_alloc_t * allocator,apr_pool_t * result_pool,apr_pool_t * scratch_pool)177 svn_ra_serf__create_sb_bucket(svn_spillbuf_t *spillbuf,
178 serf_bucket_alloc_t *allocator,
179 apr_pool_t *result_pool,
180 apr_pool_t *scratch_pool)
181 {
182 struct sbb_baton *sbb;
183
184 sbb = serf_bucket_mem_alloc(allocator, sizeof(*sbb));
185 sbb->spillbuf = spillbuf;
186 sbb->holding = NULL;
187 sbb->scratch_pool = svn_pool_create(result_pool);
188
189 return serf_bucket_create(&sb_bucket_vtable, allocator, sbb);
190 }
191