1 /* ====================================================================
2  *    Licensed to the Apache Software Foundation (ASF) under one
3  *    or more contributor license agreements.  See the NOTICE file
4  *    distributed with this work for additional information
5  *    regarding copyright ownership.  The ASF licenses this file
6  *    to you under the Apache License, Version 2.0 (the
7  *    "License"); you may not use this file except in compliance
8  *    with the License.  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing,
13  *    software distributed under the License is distributed on an
14  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  *    KIND, either express or implied.  See the License for the
16  *    specific language governing permissions and limitations
17  *    under the License.
18  * ====================================================================
19  */
20 
21 #include <apr_pools.h>
22 
23 #include "serf.h"
24 #include "serf_bucket_util.h"
25 
26 
27 typedef struct {
28     struct iovec *vecs;
29 
30     /* Total number of buffer stored in the vecs var. */
31     int vecs_len;
32     /* Points to the first unread buffer. */
33     int current_vec;
34     /* First buffer offset. */
35     int offset;
36 } iovec_context_t;
37 
serf_bucket_iovec_create(struct iovec vecs[],int len,serf_bucket_alloc_t * allocator)38 serf_bucket_t *serf_bucket_iovec_create(
39     struct iovec vecs[],
40     int len,
41     serf_bucket_alloc_t *allocator)
42 {
43     iovec_context_t *ctx;
44     int i;
45 
46     ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
47     ctx->vecs = serf_bucket_mem_alloc(allocator, len * sizeof(struct iovec));
48     ctx->vecs_len = len;
49     ctx->current_vec = 0;
50     ctx->offset = 0;
51 
52     /* copy all buffers to our iovec. */
53     for (i = 0; i < len; i++) {
54         ctx->vecs[i].iov_base = vecs[i].iov_base;
55         ctx->vecs[i].iov_len = vecs[i].iov_len;
56     }
57 
58     return serf_bucket_create(&serf_bucket_type_iovec, allocator, ctx);
59 }
60 
serf_iovec_readline(serf_bucket_t * bucket,int acceptable,int * found,const char ** data,apr_size_t * len)61 static apr_status_t serf_iovec_readline(serf_bucket_t *bucket,
62                                          int acceptable, int *found,
63                                          const char **data, apr_size_t *len)
64 {
65     return APR_ENOTIMPL;
66 }
67 
serf_iovec_read_iovec(serf_bucket_t * bucket,apr_size_t requested,int vecs_size,struct iovec * vecs,int * vecs_used)68 static apr_status_t serf_iovec_read_iovec(serf_bucket_t *bucket,
69                                           apr_size_t requested,
70                                           int vecs_size,
71                                           struct iovec *vecs,
72                                           int *vecs_used)
73 {
74     iovec_context_t *ctx = bucket->data;
75 
76     *vecs_used = 0;
77 
78     /* copy the requested amount of buffers to the provided iovec. */
79     for (; ctx->current_vec < ctx->vecs_len; ctx->current_vec++) {
80         struct iovec vec = ctx->vecs[ctx->current_vec];
81         apr_size_t remaining;
82 
83         if (requested != SERF_READ_ALL_AVAIL && requested <= 0)
84             break;
85         if (*vecs_used >= vecs_size)
86             break;
87 
88         vecs[*vecs_used].iov_base = (char*)vec.iov_base + ctx->offset;
89         remaining = vec.iov_len - ctx->offset;
90 
91         /* Less bytes requested than remaining in the current buffer. */
92         if (requested != SERF_READ_ALL_AVAIL && requested < remaining) {
93             vecs[*vecs_used].iov_len = requested;
94             ctx->offset += requested;
95             requested = 0;
96             (*vecs_used)++;
97             break;
98         } else {
99             /* Copy the complete buffer. */
100             vecs[*vecs_used].iov_len = remaining;
101             ctx->offset = 0;
102             if (requested != SERF_READ_ALL_AVAIL)
103                 requested -= remaining;
104             (*vecs_used)++;
105         }
106     }
107 
108     if (ctx->current_vec == ctx->vecs_len && !ctx->offset)
109         return APR_EOF;
110 
111     return APR_SUCCESS;
112 }
113 
serf_iovec_read(serf_bucket_t * bucket,apr_size_t requested,const char ** data,apr_size_t * len)114 static apr_status_t serf_iovec_read(serf_bucket_t *bucket,
115                                     apr_size_t requested,
116                                     const char **data, apr_size_t *len)
117 {
118     struct iovec vec[1];
119     apr_status_t status;
120     int vecs_used;
121 
122     status = serf_iovec_read_iovec(bucket, requested, 1, vec, &vecs_used);
123 
124     if (vecs_used) {
125         *data = vec[0].iov_base;
126         *len = vec[0].iov_len;
127     } else {
128         *len = 0;
129     }
130 
131     return status;
132 }
133 
serf_iovec_peek(serf_bucket_t * bucket,const char ** data,apr_size_t * len)134 static apr_status_t serf_iovec_peek(serf_bucket_t *bucket,
135                                     const char **data,
136                                     apr_size_t *len)
137 {
138     iovec_context_t *ctx = bucket->data;
139 
140     if (ctx->current_vec >= ctx->vecs_len) {
141         *len = 0;
142         return APR_EOF;
143     }
144 
145     /* Return the first unread buffer, don't bother combining all
146        remaining data. */
147     *data = ctx->vecs[ctx->current_vec].iov_base;
148     *len = ctx->vecs[ctx->current_vec].iov_len;
149 
150     if (ctx->current_vec + 1 == ctx->vecs_len)
151         return APR_EOF;
152 
153     return APR_SUCCESS;
154 }
155 
serf_iovec_destroy(serf_bucket_t * bucket)156 static void serf_iovec_destroy(serf_bucket_t *bucket)
157 {
158     iovec_context_t *ctx = bucket->data;
159 
160     serf_bucket_mem_free(bucket->allocator, ctx->vecs);
161     serf_default_destroy_and_data(bucket);
162 }
163 
164 
165 const serf_bucket_type_t serf_bucket_type_iovec = {
166     "IOVEC",
167     serf_iovec_read,
168     serf_iovec_readline,
169     serf_iovec_read_iovec,
170     serf_default_read_for_sendfile,
171     serf_default_read_bucket,
172     serf_iovec_peek,
173     serf_iovec_destroy,
174 };
175