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 #ifndef SERF_BUCKET_TYPES_H
22 #define SERF_BUCKET_TYPES_H
23 
24 #include <apr_mmap.h>
25 #include <apr_hash.h>
26 
27 /* this header and serf.h refer to each other, so take a little extra care */
28 #ifndef SERF_H
29 #include "serf.h"
30 #endif
31 
32 
33 /**
34  * @file serf_bucket_types.h
35  * @brief serf-supported bucket types
36  */
37 /* ### this whole file needs docco ... */
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /* ==================================================================== */
44 
45 
46 extern const serf_bucket_type_t serf_bucket_type_request;
47 #define SERF_BUCKET_IS_REQUEST(b) SERF_BUCKET_CHECK((b), request)
48 
49 serf_bucket_t *serf_bucket_request_create(
50     const char *method,
51     const char *URI,
52     serf_bucket_t *body,
53     serf_bucket_alloc_t *allocator);
54 
55 /* Send a Content-Length header with @a len. The @a body bucket should
56    contain precisely that much data.  */
57 void serf_bucket_request_set_CL(
58     serf_bucket_t *bucket,
59     apr_int64_t len);
60 
61 serf_bucket_t *serf_bucket_request_get_headers(
62     serf_bucket_t *request);
63 
64 void serf_bucket_request_become(
65     serf_bucket_t *bucket,
66     const char *method,
67     const char *uri,
68     serf_bucket_t *body);
69 
70 /**
71  * Sets the root url of the remote host. If this request contains a relative
72  * url, it will be prefixed with the root url to form an absolute url.
73  * @a bucket is the request bucket. @a root_url is the absolute url of the
74  * root of the remote host, without the closing '/'.
75  */
76 void serf_bucket_request_set_root(
77     serf_bucket_t *bucket,
78     const char *root_url);
79 
80 /* ==================================================================== */
81 
82 
83 extern const serf_bucket_type_t serf_bucket_type_response;
84 #define SERF_BUCKET_IS_RESPONSE(b) SERF_BUCKET_CHECK((b), response)
85 
86 serf_bucket_t *serf_bucket_response_create(
87     serf_bucket_t *stream,
88     serf_bucket_alloc_t *allocator);
89 
90 #define SERF_HTTP_VERSION(major, minor)  ((major) * 1000 + (minor))
91 #define SERF_HTTP_11 SERF_HTTP_VERSION(1, 1)
92 #define SERF_HTTP_10 SERF_HTTP_VERSION(1, 0)
93 #define SERF_HTTP_VERSION_MAJOR(shv) ((int)shv / 1000)
94 #define SERF_HTTP_VERSION_MINOR(shv) ((int)shv % 1000)
95 
96 typedef struct {
97     int version;
98     int code;
99     const char *reason;
100 } serf_status_line;
101 
102 /**
103  * Return the Status-Line information, if available. This function
104  * works like other bucket read functions: it may return APR_EAGAIN or
105  * APR_EOF to signal the state of the bucket for reading. A return
106  * value of APR_SUCCESS will always indicate that status line
107  * information was returned; for other return values the caller must
108  * check the version field in @a sline. A value of 0 means that the
109  * data is not (yet) present.
110  */
111 apr_status_t serf_bucket_response_status(
112     serf_bucket_t *bkt,
113     serf_status_line *sline);
114 
115 /**
116  * Wait for the HTTP headers to be processed for a @a response.
117  *
118  * If the headers are available, APR_SUCCESS is returned.
119  * If the headers aren't available, APR_EAGAIN is returned.
120  */
121 apr_status_t serf_bucket_response_wait_for_headers(
122     serf_bucket_t *response);
123 
124 /**
125  * Get the headers bucket for @a response.
126  */
127 serf_bucket_t *serf_bucket_response_get_headers(
128     serf_bucket_t *response);
129 
130 /**
131  * Advise the response @a bucket that this was from a HEAD request and
132  * that it should not expect to see a response body.
133  */
134 void serf_bucket_response_set_head(
135     serf_bucket_t *bucket);
136 
137 /* ==================================================================== */
138 
139 extern const serf_bucket_type_t serf_bucket_type_response_body;
140 #define SERF_BUCKET_IS_RESPONSE_BODY(b) SERF_BUCKET_CHECK((b), response_body)
141 
142 serf_bucket_t *serf_bucket_response_body_create(
143     serf_bucket_t *stream,
144     apr_uint64_t limit,
145     serf_bucket_alloc_t *allocator);
146 
147 /* ==================================================================== */
148 
149 extern const serf_bucket_type_t serf_bucket_type_bwtp_frame;
150 #define SERF_BUCKET_IS_BWTP_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_frame)
151 
152 extern const serf_bucket_type_t serf_bucket_type_bwtp_incoming_frame;
153 #define SERF_BUCKET_IS_BWTP_INCOMING_FRAME(b) SERF_BUCKET_CHECK((b), bwtp_incoming_frame)
154 
155 int serf_bucket_bwtp_frame_get_channel(
156     serf_bucket_t *hdr);
157 
158 int serf_bucket_bwtp_frame_get_type(
159     serf_bucket_t *hdr);
160 
161 const char *serf_bucket_bwtp_frame_get_phrase(
162     serf_bucket_t *hdr);
163 
164 serf_bucket_t *serf_bucket_bwtp_frame_get_headers(
165     serf_bucket_t *hdr);
166 
167 serf_bucket_t *serf_bucket_bwtp_channel_open(
168     int channel,
169     const char *URI,
170     serf_bucket_alloc_t *allocator);
171 
172 serf_bucket_t *serf_bucket_bwtp_channel_close(
173     int channel,
174     serf_bucket_alloc_t *allocator);
175 
176 serf_bucket_t *serf_bucket_bwtp_header_create(
177     int channel,
178     const char *phrase,
179     serf_bucket_alloc_t *allocator);
180 
181 serf_bucket_t *serf_bucket_bwtp_message_create(
182     int channel,
183     serf_bucket_t *body,
184     serf_bucket_alloc_t *allocator);
185 
186 serf_bucket_t *serf_bucket_bwtp_incoming_frame_create(
187     serf_bucket_t *bkt,
188     serf_bucket_alloc_t *allocator);
189 
190 apr_status_t serf_bucket_bwtp_incoming_frame_wait_for_headers(
191     serf_bucket_t *bkt);
192 
193 /* ==================================================================== */
194 
195 
196 extern const serf_bucket_type_t serf_bucket_type_aggregate;
197 #define SERF_BUCKET_IS_AGGREGATE(b) SERF_BUCKET_CHECK((b), aggregate)
198 
199 typedef apr_status_t (*serf_bucket_aggregate_eof_t)(
200     void *baton,
201     serf_bucket_t *aggregate_bucket);
202 
203 /** serf_bucket_aggregate_cleanup will instantly destroy all buckets in
204     the aggregate bucket that have been read completely. Whereas normally,
205     these buckets are destroyed on every read operation. */
206 void serf_bucket_aggregate_cleanup(
207     serf_bucket_t *bucket,
208     serf_bucket_alloc_t *allocator);
209 
210 serf_bucket_t *serf_bucket_aggregate_create(
211     serf_bucket_alloc_t *allocator);
212 
213 /* Creates a stream bucket.
214    A stream bucket is like an aggregate bucket, but:
215    - it doesn't destroy its child buckets on cleanup
216    - one can always keep adding child buckets, the handler FN should return
217      APR_EOF when no more buckets will be added.
218 
219   Note: keep this factory function internal for now. If it turns out this
220   bucket type is useful outside serf, we should make it an actual separate
221   type.
222   */
223 serf_bucket_t *serf__bucket_stream_create(
224     serf_bucket_alloc_t *allocator,
225     serf_bucket_aggregate_eof_t fn,
226     void *baton);
227 
228 /** Transform @a bucket in-place into an aggregate bucket. */
229 void serf_bucket_aggregate_become(
230     serf_bucket_t *bucket);
231 
232 void serf_bucket_aggregate_prepend(
233     serf_bucket_t *aggregate_bucket,
234     serf_bucket_t *prepend_bucket);
235 
236 void serf_bucket_aggregate_append(
237     serf_bucket_t *aggregate_bucket,
238     serf_bucket_t *append_bucket);
239 
240 void serf_bucket_aggregate_hold_open(
241     serf_bucket_t *aggregate_bucket,
242     serf_bucket_aggregate_eof_t fn,
243     void *baton);
244 
245 void serf_bucket_aggregate_prepend_iovec(
246     serf_bucket_t *aggregate_bucket,
247     struct iovec *vecs,
248     int vecs_count);
249 
250 void serf_bucket_aggregate_append_iovec(
251     serf_bucket_t *aggregate_bucket,
252     struct iovec *vecs,
253     int vecs_count);
254 
255 /* ==================================================================== */
256 
257 
258 extern const serf_bucket_type_t serf_bucket_type_file;
259 #define SERF_BUCKET_IS_FILE(b) SERF_BUCKET_CHECK((b), file)
260 
261 serf_bucket_t *serf_bucket_file_create(
262     apr_file_t *file,
263     serf_bucket_alloc_t *allocator);
264 
265 
266 /* ==================================================================== */
267 
268 
269 extern const serf_bucket_type_t serf_bucket_type_socket;
270 #define SERF_BUCKET_IS_SOCKET(b) SERF_BUCKET_CHECK((b), socket)
271 
272 serf_bucket_t *serf_bucket_socket_create(
273     apr_socket_t *skt,
274     serf_bucket_alloc_t *allocator);
275 
276 /**
277  * Call @a progress_func every time bytes are read from the socket, pass
278  * the number of bytes read.
279  *
280  * When using serf's bytes read & written progress indicator, pass
281  * @a serf_context_progress_delta for progress_func and the serf_context for
282  * progress_baton.
283  */
284 void serf_bucket_socket_set_read_progress_cb(
285     serf_bucket_t *bucket,
286     const serf_progress_t progress_func,
287     void *progress_baton);
288 
289 /* ==================================================================== */
290 
291 
292 extern const serf_bucket_type_t serf_bucket_type_simple;
293 #define SERF_BUCKET_IS_SIMPLE(b) SERF_BUCKET_CHECK((b), simple)
294 
295 typedef void (*serf_simple_freefunc_t)(
296     void *baton,
297     const char *data);
298 
299 serf_bucket_t *serf_bucket_simple_create(
300     const char *data,
301     apr_size_t len,
302     serf_simple_freefunc_t freefunc,
303     void *freefunc_baton,
304     serf_bucket_alloc_t *allocator);
305 
306 /**
307  * Equivalent to serf_bucket_simple_create, except that the bucket takes
308  * ownership of a private copy of the data.
309  */
310 serf_bucket_t *serf_bucket_simple_copy_create(
311     const char *data,
312     apr_size_t len,
313     serf_bucket_alloc_t *allocator);
314 
315 /**
316  * Equivalent to serf_bucket_simple_create, except that the bucket assumes
317  * responsibility for freeing the data on this allocator without making
318  * a copy.  It is assumed that data was created by a call from allocator.
319  */
320 serf_bucket_t *serf_bucket_simple_own_create(
321     const char *data,
322     apr_size_t len,
323     serf_bucket_alloc_t *allocator);
324 
325 #define SERF_BUCKET_SIMPLE_STRING(s,a) \
326     serf_bucket_simple_create(s, strlen(s), NULL, NULL, a);
327 
328 #define SERF_BUCKET_SIMPLE_STRING_LEN(s,l,a) \
329     serf_bucket_simple_create(s, l, NULL, NULL, a);
330 
331 /* ==================================================================== */
332 
333 
334 /* Note: apr_mmap_t is always defined, but if APR doesn't have mmaps, then
335    the caller can never create an apr_mmap_t to pass to this function. */
336 
337 extern const serf_bucket_type_t serf_bucket_type_mmap;
338 #define SERF_BUCKET_IS_MMAP(b) SERF_BUCKET_CHECK((b), mmap)
339 
340 serf_bucket_t *serf_bucket_mmap_create(
341     apr_mmap_t *mmap,
342     serf_bucket_alloc_t *allocator);
343 
344 
345 /* ==================================================================== */
346 
347 
348 extern const serf_bucket_type_t serf_bucket_type_headers;
349 #define SERF_BUCKET_IS_HEADERS(b) SERF_BUCKET_CHECK((b), headers)
350 
351 serf_bucket_t *serf_bucket_headers_create(
352     serf_bucket_alloc_t *allocator);
353 
354 /**
355  * Set, default: value copied.
356  *
357  * Set the specified @a header within the bucket, copying the @a value
358  * into space from this bucket's allocator. The header is NOT copied,
359  * so it should remain in scope at least as long as the bucket.
360  */
361 void serf_bucket_headers_set(
362     serf_bucket_t *headers_bucket,
363     const char *header,
364     const char *value);
365 
366 /**
367  * Set, copies: header and value copied.
368  *
369  * Copy the specified @a header and @a value into the bucket, using space
370  * from this bucket's allocator.
371  */
372 void serf_bucket_headers_setc(
373     serf_bucket_t *headers_bucket,
374     const char *header,
375     const char *value);
376 
377 /**
378  * Set, no copies.
379  *
380  * Set the specified @a header and @a value into the bucket, without
381  * copying either attribute. Both attributes should remain in scope at
382  * least as long as the bucket.
383  *
384  * @note In the case where a header already exists this will result
385  *       in a reallocation and copy, @see serf_bucket_headers_setn.
386  */
387 void serf_bucket_headers_setn(
388     serf_bucket_t *headers_bucket,
389     const char *header,
390     const char *value);
391 
392 /**
393  * Set, extended: fine grained copy control of header and value.
394  *
395  * Set the specified @a header, with length @a header_size with the
396  * @a value, and length @a value_size, into the bucket. The header will
397  * be copied if @a header_copy is set, and the value is copied if
398  * @a value_copy is set. If the values are not copied, then they should
399  * remain in scope at least as long as the bucket.
400  *
401  * If @a headers_bucket already contains a header with the same name
402  * as @a header, then append @a value to the existing value,
403  * separating with a comma (as per RFC 2616, section 4.2).  In this
404  * case, the new value must be allocated and the header re-used, so
405  * behave as if @a value_copy were true and @a header_copy false.
406  */
407 void serf_bucket_headers_setx(
408     serf_bucket_t *headers_bucket,
409     const char *header,
410     apr_size_t header_size,
411     int header_copy,
412     const char *value,
413     apr_size_t value_size,
414     int value_copy);
415 
416 const char *serf_bucket_headers_get(
417     serf_bucket_t *headers_bucket,
418     const char *header);
419 
420 /**
421  * @param baton opaque baton as passed to @see serf_bucket_headers_do
422  * @param key The header key from this iteration through the table
423  * @param value The header value from this iteration through the table
424  */
425 typedef int (serf_bucket_headers_do_callback_fn_t)(
426     void *baton,
427     const char *key,
428     const char *value);
429 
430 /**
431  * Iterates over all headers of the message and invokes the callback
432  * function with header key and value. Stop iterating when no more
433  * headers are available or when the callback function returned a
434  * non-0 value.
435  *
436  * @param headers_bucket headers to iterate over
437  * @param func callback routine to invoke for every header in the bucket
438  * @param baton baton to pass on each invocation to func
439  */
440 void serf_bucket_headers_do(
441     serf_bucket_t *headers_bucket,
442     serf_bucket_headers_do_callback_fn_t func,
443     void *baton);
444 
445 
446 /* ==================================================================== */
447 
448 
449 extern const serf_bucket_type_t serf_bucket_type_chunk;
450 #define SERF_BUCKET_IS_CHUNK(b) SERF_BUCKET_CHECK((b), chunk)
451 
452 serf_bucket_t *serf_bucket_chunk_create(
453     serf_bucket_t *stream,
454     serf_bucket_alloc_t *allocator);
455 
456 
457 /* ==================================================================== */
458 
459 
460 extern const serf_bucket_type_t serf_bucket_type_dechunk;
461 #define SERF_BUCKET_IS_DECHUNK(b) SERF_BUCKET_CHECK((b), dechunk)
462 
463 serf_bucket_t *serf_bucket_dechunk_create(
464     serf_bucket_t *stream,
465     serf_bucket_alloc_t *allocator);
466 
467 
468 /* ==================================================================== */
469 
470 
471 extern const serf_bucket_type_t serf_bucket_type_deflate;
472 #define SERF_BUCKET_IS_DEFLATE(b) SERF_BUCKET_CHECK((b), deflate)
473 
474 #define SERF_DEFLATE_GZIP 0
475 #define SERF_DEFLATE_DEFLATE 1
476 
477 serf_bucket_t *serf_bucket_deflate_create(
478     serf_bucket_t *stream,
479     serf_bucket_alloc_t *allocator,
480     int format);
481 
482 
483 /* ==================================================================== */
484 
485 
486 extern const serf_bucket_type_t serf_bucket_type_limit;
487 #define SERF_BUCKET_IS_LIMIT(b) SERF_BUCKET_CHECK((b), limit)
488 
489 serf_bucket_t *serf_bucket_limit_create(
490     serf_bucket_t *stream,
491     apr_uint64_t limit,
492     serf_bucket_alloc_t *allocator);
493 
494 
495 /* ==================================================================== */
496 #define SERF_SSL_CERT_NOTYETVALID       1
497 #define SERF_SSL_CERT_EXPIRED           2
498 #define SERF_SSL_CERT_UNKNOWNCA         4
499 #define SERF_SSL_CERT_SELF_SIGNED       8
500 #define SERF_SSL_CERT_UNKNOWN_FAILURE  16
501 #define SERF_SSL_CERT_REVOKED          32
502 
503 extern const serf_bucket_type_t serf_bucket_type_ssl_encrypt;
504 #define SERF_BUCKET_IS_SSL_ENCRYPT(b) SERF_BUCKET_CHECK((b), ssl_encrypt)
505 
506 typedef struct serf_ssl_context_t serf_ssl_context_t;
507 typedef struct serf_ssl_certificate_t serf_ssl_certificate_t;
508 
509 typedef apr_status_t (*serf_ssl_need_client_cert_t)(
510     void *data,
511     const char **cert_path);
512 
513 typedef apr_status_t (*serf_ssl_need_cert_password_t)(
514     void *data,
515     const char *cert_path,
516     const char **password);
517 
518 typedef apr_status_t (*serf_ssl_need_server_cert_t)(
519     void *data,
520     int failures,
521     const serf_ssl_certificate_t *cert);
522 
523 typedef apr_status_t (*serf_ssl_server_cert_chain_cb_t)(
524     void *data,
525     int failures,
526     int error_depth,
527     const serf_ssl_certificate_t * const * certs,
528     apr_size_t certs_len);
529 
530 void serf_ssl_client_cert_provider_set(
531     serf_ssl_context_t *context,
532     serf_ssl_need_client_cert_t callback,
533     void *data,
534     void *cache_pool);
535 
536 void serf_ssl_client_cert_password_set(
537     serf_ssl_context_t *context,
538     serf_ssl_need_cert_password_t callback,
539     void *data,
540     void *cache_pool);
541 
542 /**
543  * Set a callback to override the default SSL server certificate validation
544  * algorithm.
545  */
546 void serf_ssl_server_cert_callback_set(
547     serf_ssl_context_t *context,
548     serf_ssl_need_server_cert_t callback,
549     void *data);
550 
551 /**
552  * Set callbacks to override the default SSL server certificate validation
553  * algorithm for the current certificate or the entire certificate chain.
554  */
555 void serf_ssl_server_cert_chain_callback_set(
556     serf_ssl_context_t *context,
557     serf_ssl_need_server_cert_t cert_callback,
558     serf_ssl_server_cert_chain_cb_t cert_chain_callback,
559     void *data);
560 
561 /**
562  * Use the default root CA certificates as included with the OpenSSL library.
563  */
564 apr_status_t serf_ssl_use_default_certificates(
565     serf_ssl_context_t *context);
566 
567 /**
568  * Allow SNI indicators to be sent to the server.
569  */
570 apr_status_t serf_ssl_set_hostname(
571     serf_ssl_context_t *context, const char *hostname);
572 
573 /**
574  * Return the depth of the certificate.
575  */
576 int serf_ssl_cert_depth(
577     const serf_ssl_certificate_t *cert);
578 
579 /**
580  * Extract the fields of the issuer in a table with keys (E, CN, OU, O, L,
581  * ST and C). The returned table will be allocated in @a pool.
582  */
583 apr_hash_t *serf_ssl_cert_issuer(
584     const serf_ssl_certificate_t *cert,
585     apr_pool_t *pool);
586 
587 /**
588  * Extract the fields of the subject in a table with keys (E, CN, OU, O, L,
589  * ST and C). The returned table will be allocated in @a pool.
590  */
591 apr_hash_t *serf_ssl_cert_subject(
592     const serf_ssl_certificate_t *cert,
593     apr_pool_t *pool);
594 
595 /**
596  * Extract the fields of the certificate in a table with keys (sha1, notBefore,
597  * notAfter, subjectAltName). The returned table will be allocated in @a pool.
598  */
599 apr_hash_t *serf_ssl_cert_certificate(
600     const serf_ssl_certificate_t *cert,
601     apr_pool_t *pool);
602 
603 /**
604  * Export a certificate to base64-encoded, zero-terminated string.
605  * The returned string is allocated in @a pool. Returns NULL on failure.
606  */
607 const char *serf_ssl_cert_export(
608     const serf_ssl_certificate_t *cert,
609     apr_pool_t *pool);
610 
611 /**
612  * Load a CA certificate file from a path @a file_path. If the file was loaded
613  * and parsed correctly, a certificate @a cert will be created and returned.
614  * This certificate object will be alloced in @a pool.
615  */
616 apr_status_t serf_ssl_load_cert_file(
617     serf_ssl_certificate_t **cert,
618     const char *file_path,
619     apr_pool_t *pool);
620 
621 /**
622  * Adds the certificate @a cert to the list of trusted certificates in
623  * @a ssl_ctx that will be used for verification.
624  * See also @a serf_ssl_load_cert_file.
625  */
626 apr_status_t serf_ssl_trust_cert(
627     serf_ssl_context_t *ssl_ctx,
628     serf_ssl_certificate_t *cert);
629 
630 /**
631  * Enable or disable SSL compression on a SSL session.
632  * @a enabled = 1 to enable compression, 0 to disable compression.
633  * Default = disabled.
634  */
635 apr_status_t serf_ssl_use_compression(
636     serf_ssl_context_t *ssl_ctx,
637     int enabled);
638 
639 serf_bucket_t *serf_bucket_ssl_encrypt_create(
640     serf_bucket_t *stream,
641     serf_ssl_context_t *ssl_context,
642     serf_bucket_alloc_t *allocator);
643 
644 serf_ssl_context_t *serf_bucket_ssl_encrypt_context_get(
645     serf_bucket_t *bucket);
646 
647 /* ==================================================================== */
648 
649 
650 extern const serf_bucket_type_t serf_bucket_type_ssl_decrypt;
651 #define SERF_BUCKET_IS_SSL_DECRYPT(b) SERF_BUCKET_CHECK((b), ssl_decrypt)
652 
653 serf_bucket_t *serf_bucket_ssl_decrypt_create(
654     serf_bucket_t *stream,
655     serf_ssl_context_t *ssl_context,
656     serf_bucket_alloc_t *allocator);
657 
658 serf_ssl_context_t *serf_bucket_ssl_decrypt_context_get(
659     serf_bucket_t *bucket);
660 
661 
662 /* ==================================================================== */
663 
664 
665 extern const serf_bucket_type_t serf_bucket_type_barrier;
666 #define SERF_BUCKET_IS_BARRIER(b) SERF_BUCKET_CHECK((b), barrier)
667 
668 serf_bucket_t *serf_bucket_barrier_create(
669     serf_bucket_t *stream,
670     serf_bucket_alloc_t *allocator);
671 
672 
673 /* ==================================================================== */
674 
675 extern const serf_bucket_type_t serf_bucket_type_iovec;
676 #define SERF_BUCKET_IS_IOVEC(b) SERF_BUCKET_CHECK((b), iovec)
677 
678 serf_bucket_t *serf_bucket_iovec_create(
679     struct iovec vecs[],
680     int len,
681     serf_bucket_alloc_t *allocator);
682 
683 
684 /* ==================================================================== */
685 
686 /* ### do we need a PIPE bucket type? they are simple apr_file_t objects */
687 
688 
689 #ifdef __cplusplus
690 }
691 #endif
692 
693 #endif	/* !SERF_BUCKET_TYPES_H */
694