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 36struct 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 47svn_error_t * 48svn_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 77static apr_status_t 78sb_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 121static apr_status_t 122sb_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 132 133static apr_status_t 134sb_bucket_peek(serf_bucket_t *bucket, 135 const char **data, apr_size_t *len) 136{ 137 struct sbb_baton *sbb = bucket->data; 138 svn_error_t *err; 139 140 /* If we're not holding any data, then fill it. */ 141 if (sbb->holding == NULL) 142 { 143 err = svn_spillbuf__read(&sbb->holding, &sbb->hold_len, sbb->spillbuf, 144 sbb->scratch_pool); 145 svn_pool_clear(sbb->scratch_pool); 146 147 /* ### do something with this */ 148 svn_error_clear(err); 149 } 150 151 /* Return the data we are (now) holding. */ 152 *data = sbb->holding; 153 *len = sbb->hold_len; 154 155 return *data == NULL ? APR_EOF : APR_SUCCESS; 156} 157 158 159static const serf_bucket_type_t sb_bucket_vtable = { 160 "SPILLBUF", 161 sb_bucket_read, 162 sb_bucket_readline, 163 serf_default_read_iovec, 164 serf_default_read_for_sendfile, 165 serf_default_read_bucket, 166 sb_bucket_peek, 167 serf_default_destroy_and_data, 168}; 169 170 171serf_bucket_t * 172svn_ra_serf__create_sb_bucket(svn_spillbuf_t *spillbuf, 173 serf_bucket_alloc_t *allocator, 174 apr_pool_t *result_pool, 175 apr_pool_t *scratch_pool) 176{ 177 struct sbb_baton *sbb; 178 179 sbb = serf_bucket_mem_alloc(allocator, sizeof(*sbb)); 180 sbb->spillbuf = spillbuf; 181 sbb->holding = NULL; 182 sbb->scratch_pool = svn_pool_create(result_pool); 183 184 return serf_bucket_create(&sb_bucket_vtable, allocator, sbb); 185} 186