blob: b88dba53d8a20e0aa92e74feae976df9d3d0e8b2 [file] [log] [blame]
/*
* sb_bucket.c : a serf bucket that wraps a spillbuf
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#include <serf.h>
#include <serf_bucket_util.h>
#include "svn_private_config.h"
#include "private/svn_subr_private.h"
#include "ra_serf.h"
#define SB_BLOCKSIZE 1024
#define SB_MAXSIZE 32768
struct sbb_baton
{
svn_spillbuf_t *spillbuf;
const char *holding;
apr_size_t hold_len;
apr_pool_t *scratch_pool;
};
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)
{
*spillbuf = svn_spillbuf__create(SB_BLOCKSIZE, SB_MAXSIZE, result_pool);
/* Copy all data from the bucket into the spillbuf. */
while (TRUE)
{
apr_status_t status;
const char *data;
apr_size_t len;
status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
if (status != APR_SUCCESS && status != APR_EOF)
return svn_ra_serf__wrap_err(status, _("Failed to read the request"));
SVN_ERR(svn_spillbuf__write(*spillbuf, data, len, scratch_pool));
if (status == APR_EOF)
break;
}
return SVN_NO_ERROR;
}
static apr_status_t
sb_bucket_read(serf_bucket_t *bucket, apr_size_t requested,
const char **data, apr_size_t *len)
{
struct sbb_baton *sbb = bucket->data;
svn_error_t *err;
if (sbb->holding)
{
*data = sbb->holding;
if (requested < sbb->hold_len)
{
*len = requested;
sbb->holding += requested;
sbb->hold_len -= requested;
return APR_SUCCESS;
}
/* Return whatever we're holding, and then forget (consume) it. */
*len = sbb->hold_len;
sbb->holding = NULL;
return APR_SUCCESS;
}
err = svn_spillbuf__read(data, len, sbb->spillbuf, sbb->scratch_pool);
svn_pool_clear(sbb->scratch_pool);
/* ### do something with this */
svn_error_clear(err);
/* The spillbuf may have returned more than requested. Stash any extra
into our holding area. */
if (requested < *len)
{
sbb->holding = *data + requested;
sbb->hold_len = *len - requested;
*len = requested;
}
return *data == NULL ? APR_EOF : APR_SUCCESS;
}
#if !SERF_VERSION_AT_LEAST(1, 4, 0)
static apr_status_t
sb_bucket_readline(serf_bucket_t *bucket, int acceptable,
int *found,
const char **data, apr_size_t *len)
{
/* ### for now, we know callers won't use this function. */
svn_error_clear(svn_error__malfunction(TRUE, __FILE__, __LINE__,
"Not implemented."));
return APR_ENOTIMPL;
}
#endif
static apr_status_t
sb_bucket_peek(serf_bucket_t *bucket,
const char **data, apr_size_t *len)
{
struct sbb_baton *sbb = bucket->data;
svn_error_t *err;
/* If we're not holding any data, then fill it. */
if (sbb->holding == NULL)
{
err = svn_spillbuf__read(&sbb->holding, &sbb->hold_len, sbb->spillbuf,
sbb->scratch_pool);
svn_pool_clear(sbb->scratch_pool);
/* ### do something with this */
svn_error_clear(err);
}
/* Return the data we are (now) holding. */
*data = sbb->holding;
*len = sbb->hold_len;
return *data == NULL ? APR_EOF : APR_SUCCESS;
}
static const serf_bucket_type_t sb_bucket_vtable = {
"SPILLBUF",
sb_bucket_read,
#if SERF_VERSION_AT_LEAST(1, 4, 0)
serf_default_readline,
#else
sb_bucket_readline,
#endif
serf_default_read_iovec,
serf_default_read_for_sendfile,
serf_default_read_bucket,
sb_bucket_peek,
serf_default_destroy_and_data,
};
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)
{
struct sbb_baton *sbb;
sbb = serf_bucket_mem_alloc(allocator, sizeof(*sbb));
sbb->spillbuf = spillbuf;
sbb->holding = NULL;
sbb->scratch_pool = svn_pool_create(result_pool);
return serf_bucket_create(&sb_bucket_vtable, allocator, sbb);
}