1251881Speter/*
2251881Speter * sb_bucket.c :  a serf bucket that wraps a spillbuf
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter#include <serf.h>
25251881Speter#include <serf_bucket_util.h>
26251881Speter
27251881Speter#include "svn_private_config.h"
28251881Speter#include "private/svn_subr_private.h"
29251881Speter
30251881Speter#include "ra_serf.h"
31251881Speter
32251881Speter#define SB_BLOCKSIZE 1024
33251881Speter#define SB_MAXSIZE 32768
34251881Speter
35251881Speter
36251881Speterstruct sbb_baton
37251881Speter{
38251881Speter  svn_spillbuf_t *spillbuf;
39251881Speter
40251881Speter  const char *holding;
41251881Speter  apr_size_t hold_len;
42251881Speter
43251881Speter  apr_pool_t *scratch_pool;
44251881Speter};
45251881Speter
46251881Speter
47251881Spetersvn_error_t *
48251881Spetersvn_ra_serf__copy_into_spillbuf(svn_spillbuf_t **spillbuf,
49251881Speter                                serf_bucket_t *bkt,
50251881Speter                                apr_pool_t *result_pool,
51251881Speter                                apr_pool_t *scratch_pool)
52251881Speter{
53251881Speter  *spillbuf = svn_spillbuf__create(SB_BLOCKSIZE, SB_MAXSIZE, result_pool);
54251881Speter
55251881Speter  /* Copy all data from the bucket into the spillbuf.  */
56251881Speter  while (TRUE)
57251881Speter    {
58251881Speter      apr_status_t status;
59251881Speter      const char *data;
60251881Speter      apr_size_t len;
61251881Speter
62251881Speter      status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
63251881Speter
64251881Speter      if (status != APR_SUCCESS && status != APR_EOF)
65251881Speter        return svn_ra_serf__wrap_err(status, _("Failed to read the request"));
66251881Speter
67251881Speter      SVN_ERR(svn_spillbuf__write(*spillbuf, data, len, scratch_pool));
68251881Speter
69251881Speter      if (status == APR_EOF)
70251881Speter        break;
71251881Speter    }
72251881Speter
73251881Speter  return SVN_NO_ERROR;
74251881Speter}
75251881Speter
76251881Speter
77251881Speterstatic apr_status_t
78251881Spetersb_bucket_read(serf_bucket_t *bucket, apr_size_t requested,
79251881Speter               const char **data, apr_size_t *len)
80251881Speter{
81251881Speter  struct sbb_baton *sbb = bucket->data;
82251881Speter  svn_error_t *err;
83251881Speter
84251881Speter  if (sbb->holding)
85251881Speter    {
86251881Speter      *data = sbb->holding;
87251881Speter
88251881Speter      if (requested < sbb->hold_len)
89251881Speter        {
90251881Speter          *len = requested;
91251881Speter          sbb->holding += requested;
92251881Speter          sbb->hold_len -= requested;
93251881Speter          return APR_SUCCESS;
94251881Speter        }
95251881Speter
96251881Speter      /* Return whatever we're holding, and then forget (consume) it.  */
97251881Speter      *len = sbb->hold_len;
98251881Speter      sbb->holding = NULL;
99251881Speter      return APR_SUCCESS;
100251881Speter    }
101251881Speter
102251881Speter  err = svn_spillbuf__read(data, len, sbb->spillbuf, sbb->scratch_pool);
103251881Speter  svn_pool_clear(sbb->scratch_pool);
104251881Speter
105251881Speter  /* ### do something with this  */
106251881Speter  svn_error_clear(err);
107251881Speter
108251881Speter  /* The spillbuf may have returned more than requested. Stash any extra
109251881Speter     into our holding area.  */
110251881Speter  if (requested < *len)
111251881Speter    {
112251881Speter      sbb->holding = *data + requested;
113251881Speter      sbb->hold_len = *len - requested;
114251881Speter      *len = requested;
115251881Speter    }
116251881Speter
117251881Speter  return *data == NULL ? APR_EOF : APR_SUCCESS;
118251881Speter}
119251881Speter
120251881Speter
121251881Speterstatic apr_status_t
122251881Spetersb_bucket_readline(serf_bucket_t *bucket, int acceptable,
123251881Speter                   int *found,
124251881Speter                   const char **data, apr_size_t *len)
125251881Speter{
126251881Speter  /* ### for now, we know callers won't use this function.  */
127251881Speter  svn_error_clear(svn_error__malfunction(TRUE, __FILE__, __LINE__,
128251881Speter                                         "Not implemented."));
129251881Speter  return APR_ENOTIMPL;
130251881Speter}
131251881Speter
132251881Speter
133251881Speterstatic apr_status_t
134251881Spetersb_bucket_peek(serf_bucket_t *bucket,
135251881Speter               const char **data, apr_size_t *len)
136251881Speter{
137251881Speter  struct sbb_baton *sbb = bucket->data;
138251881Speter  svn_error_t *err;
139251881Speter
140251881Speter  /* If we're not holding any data, then fill it.  */
141251881Speter  if (sbb->holding == NULL)
142251881Speter    {
143251881Speter      err = svn_spillbuf__read(&sbb->holding, &sbb->hold_len, sbb->spillbuf,
144251881Speter                               sbb->scratch_pool);
145251881Speter      svn_pool_clear(sbb->scratch_pool);
146251881Speter
147251881Speter      /* ### do something with this  */
148251881Speter      svn_error_clear(err);
149251881Speter    }
150251881Speter
151251881Speter  /* Return the data we are (now) holding.  */
152251881Speter  *data = sbb->holding;
153251881Speter  *len = sbb->hold_len;
154251881Speter
155251881Speter  return *data == NULL ? APR_EOF : APR_SUCCESS;
156251881Speter}
157251881Speter
158251881Speter
159251881Speterstatic const serf_bucket_type_t sb_bucket_vtable = {
160251881Speter    "SPILLBUF",
161251881Speter    sb_bucket_read,
162251881Speter    sb_bucket_readline,
163251881Speter    serf_default_read_iovec,
164251881Speter    serf_default_read_for_sendfile,
165251881Speter    serf_default_read_bucket,
166251881Speter    sb_bucket_peek,
167251881Speter    serf_default_destroy_and_data,
168251881Speter};
169251881Speter
170251881Speter
171251881Speterserf_bucket_t *
172251881Spetersvn_ra_serf__create_sb_bucket(svn_spillbuf_t *spillbuf,
173251881Speter                              serf_bucket_alloc_t *allocator,
174251881Speter                              apr_pool_t *result_pool,
175251881Speter                              apr_pool_t *scratch_pool)
176251881Speter{
177251881Speter  struct sbb_baton *sbb;
178251881Speter
179251881Speter  sbb = serf_bucket_mem_alloc(allocator, sizeof(*sbb));
180251881Speter  sbb->spillbuf = spillbuf;
181251881Speter  sbb->holding = NULL;
182251881Speter  sbb->scratch_pool = svn_pool_create(result_pool);
183251881Speter
184251881Speter  return serf_bucket_create(&sb_bucket_vtable, allocator, sbb);
185251881Speter}
186