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