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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
}; |