1/*
2 * eagain_bucket.c :  a serf bucket that handles slowing down data
3 *                   for specific readers that would have unwanted
4 *                   behavior if they read everything too fast
5 * ====================================================================
6 *    Licensed to the Apache Software Foundation (ASF) under one
7 *    or more contributor license agreements.  See the NOTICE file
8 *    distributed with this work for additional information
9 *    regarding copyright ownership.  The ASF licenses this file
10 *    to you under the Apache License, Version 2.0 (the
11 *    "License"); you may not use this file except in compliance
12 *    with the License.  You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 *    Unless required by applicable law or agreed to in writing,
17 *    software distributed under the License is distributed on an
18 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 *    KIND, either express or implied.  See the License for the
20 *    specific language governing permissions and limitations
21 *    under the License.
22 * ====================================================================
23 */
24
25#include <serf.h>
26#include <serf_bucket_util.h>
27
28#include "svn_private_config.h"
29
30#include "ra_serf.h"
31
32typedef struct eagain_baton_t
33{
34  const char *data;
35  apr_size_t remaining;
36} eagain_baton_t;
37
38static apr_status_t
39eagain_bucket_read(serf_bucket_t *bucket,
40                   apr_size_t requested,
41                   const char **data,
42                   apr_size_t *len)
43{
44  eagain_baton_t *eab = bucket->data;
45
46  if (eab->remaining > 0)
47    {
48      *data = eab->data;
49      if (requested > eab->remaining || requested == SERF_READ_ALL_AVAIL)
50        {
51          *len = eab->remaining;
52          eab->data = NULL;
53          eab->remaining = 0;
54        }
55      else
56        {
57          *len = requested;
58          eab->data += requested;
59          eab->remaining -= requested;
60        }
61
62      if (eab->remaining)
63        return APR_SUCCESS;
64    }
65
66  return APR_EAGAIN;
67}
68
69#if !SERF_VERSION_AT_LEAST(1, 4, 0)
70static apr_status_t
71eagain_bucket_readline(serf_bucket_t *bucket,
72                       int acceptable,
73                       int *found,
74                       const char **data,
75                       apr_size_t *len)
76{
77  /* ### for now, we know callers won't use this function.  */
78  svn_error_clear(svn_error__malfunction(TRUE, __FILE__, __LINE__,
79                                         "Not implemented."));
80  return APR_ENOTIMPL;
81}
82#endif
83
84
85static apr_status_t
86eagain_bucket_peek(serf_bucket_t *bucket,
87                   const char **data,
88                   apr_size_t *len)
89{
90  const eagain_baton_t *eab = bucket->data;
91
92  *data = eab->data ? eab->data : "";
93  *len = eab->remaining;
94
95  return APR_SUCCESS;
96}
97
98
99static const serf_bucket_type_t delay_bucket_vtable = {
100    "BUF-EAGAIN",
101    eagain_bucket_read,
102#if SERF_VERSION_AT_LEAST(1, 4, 0)
103    serf_default_readline,
104#else
105    eagain_bucket_readline,
106#endif
107    serf_default_read_iovec,
108    serf_default_read_for_sendfile,
109    serf_default_read_bucket,
110    eagain_bucket_peek,
111    serf_default_destroy_and_data,
112};
113
114
115serf_bucket_t *
116svn_ra_serf__create_bucket_with_eagain(const char *data,
117                                       apr_size_t len,
118                                       serf_bucket_alloc_t *allocator)
119{
120  eagain_baton_t *eab;
121
122  eab = serf_bucket_mem_alloc(allocator, sizeof(*eab));
123  eab->data = data;
124  eab->remaining = len;
125
126  return serf_bucket_create(&delay_bucket_vtable, allocator, eab);
127}
128