summaryrefslogtreecommitdiff
path: root/serf.h
diff options
context:
space:
mode:
Diffstat (limited to 'serf.h')
-rw-r--r--serf.h1086
1 files changed, 1086 insertions, 0 deletions
diff --git a/serf.h b/serf.h
new file mode 100644
index 0000000..6428e08
--- /dev/null
+++ b/serf.h
@@ -0,0 +1,1086 @@
+/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SERF_H
+#define SERF_H
+
+/**
+ * @file serf.h
+ * @brief Main serf header file
+ */
+
+#include <apr.h>
+#include <apr_errno.h>
+#include <apr_allocator.h>
+#include <apr_pools.h>
+#include <apr_network_io.h>
+#include <apr_time.h>
+#include <apr_poll.h>
+#include <apr_uri.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declare some structures */
+typedef struct serf_context_t serf_context_t;
+
+typedef struct serf_bucket_t serf_bucket_t;
+typedef struct serf_bucket_type_t serf_bucket_type_t;
+typedef struct serf_bucket_alloc_t serf_bucket_alloc_t;
+
+typedef struct serf_connection_t serf_connection_t;
+typedef struct serf_listener_t serf_listener_t;
+typedef struct serf_incoming_t serf_incoming_t;
+typedef struct serf_incoming_request_t serf_incoming_request_t;
+
+typedef struct serf_request_t serf_request_t;
+
+
+/**
+ * @defgroup serf high-level constructs
+ * @ingroup serf
+ * @{
+ */
+
+/**
+ * Serf-specific error codes
+ */
+#define SERF_ERROR_RANGE 100
+
+/* This code is for when this is the last response on this connection:
+ * i.e. do not send any more requests on this connection or expect
+ * any more responses.
+ */
+#define SERF_ERROR_CLOSING (APR_OS_START_USERERR + SERF_ERROR_RANGE + 1)
+/* This code is for when the connection terminated before the request
+ * could be processed on the other side.
+ */
+#define SERF_ERROR_REQUEST_LOST (APR_OS_START_USERERR + SERF_ERROR_RANGE + 2)
+/* This code is for when the connection is blocked - we can not proceed
+ * until something happens - generally due to SSL negotiation-like behavior
+ * where a write() is blocked until a read() is processed.
+ */
+#define SERF_ERROR_WAIT_CONN (APR_OS_START_USERERR + SERF_ERROR_RANGE + 3)
+/* This code is for when something went wrong during deflating compressed
+ * data e.g. a CRC error. */
+#define SERF_ERROR_DECOMPRESSION_FAILED (APR_OS_START_USERERR + \
+ SERF_ERROR_RANGE + 4)
+/* This code is for when a response received from a http server is not in
+ * http-compliant syntax. */
+#define SERF_ERROR_BAD_HTTP_RESPONSE (APR_OS_START_USERERR + \
+ SERF_ERROR_RANGE + 5)
+
+/* General authentication related errors */
+#define SERF_ERROR_AUTHN_FAILED (APR_OS_START_USERERR + SERF_ERROR_RANGE + 90)
+
+/* None of the available authn mechanisms for the request are supported */
+#define SERF_ERROR_AUTHN_NOT_SUPPORTED (APR_OS_START_USERERR + SERF_ERROR_RANGE + 91)
+
+/* Authn was requested by the server but the header lacked some attribute */
+#define SERF_ERROR_AUTHN_MISSING_ATTRIBUTE (APR_OS_START_USERERR + SERF_ERROR_RANGE + 92)
+
+/* Authentication handler initialization related errors */
+#define SERF_ERROR_AUTHN_INITALIZATION_FAILED (APR_OS_START_USERERR +\
+ SERF_ERROR_RANGE + 93)
+
+/* This macro groups errors potentially raised when reading a http response. */
+#define SERF_BAD_RESPONSE_ERROR(status) ((status) \
+ && ((SERF_ERROR_DECOMPRESSION_FAILED == (status)) \
+ ||(SERF_ERROR_BAD_HTTP_RESPONSE == (status))))
+
+/**
+ * Return a string that describes the specified error code.
+ *
+ * If the error code is not one of the above Serf error codes, then
+ * NULL will be returned.
+ *
+ * Note regarding lifetime: the string is a statically-allocated constant
+ */
+const char *serf_error_string(apr_status_t errcode);
+
+
+/**
+ * Create a new context for serf operations.
+ *
+ * A serf context defines a control loop which processes multiple
+ * connections simultaneously.
+ *
+ * The context will be allocated within @a pool.
+ */
+serf_context_t *serf_context_create(
+ apr_pool_t *pool);
+
+/**
+ * Callback function. Add a socket to the externally managed poll set.
+ *
+ * Both @a pfd and @a serf_baton should be used when calling serf_event_trigger
+ * later.
+ */
+typedef apr_status_t (*serf_socket_add_t)(
+ void *user_baton,
+ apr_pollfd_t *pfd,
+ void *serf_baton);
+
+/**
+ * Callback function. Remove the socket, identified by both @a pfd and
+ * @a serf_baton from the externally managed poll set.
+ */
+typedef apr_status_t (*serf_socket_remove_t)(
+ void *user_baton,
+ apr_pollfd_t *pfd,
+ void *serf_baton);
+
+/* Create a new context for serf operations.
+ *
+ * Use this function to make serf not use its internal control loop, but
+ * instead rely on an external event loop. Serf will use the @a addf and @a rmf
+ * callbacks to notify of any event on a connection. The @a user_baton will be
+ * passed through the addf and rmf callbacks.
+ *
+ * The context will be allocated within @a pool.
+ */
+serf_context_t *serf_context_create_ex(
+ void *user_baton,
+ serf_socket_add_t addf,
+ serf_socket_remove_t rmf,
+ apr_pool_t *pool);
+
+/**
+ * Make serf process events on a connection, identified by both @a pfd and
+ * @a serf_baton.
+ *
+ * Any outbound data is delivered, and incoming data is made available to
+ * the associated response handlers and their buckets.
+ *
+ * If any data is processed (incoming or outgoing), then this function will
+ * return with APR_SUCCESS.
+ */
+apr_status_t serf_event_trigger(
+ serf_context_t *s,
+ void *serf_baton,
+ const apr_pollfd_t *pfd);
+
+/** @see serf_context_run should not block at all. */
+#define SERF_DURATION_NOBLOCK 0
+/** @see serf_context_run should run for (nearly) "forever". */
+#define SERF_DURATION_FOREVER 2000000000 /* approx 1^31 */
+
+/**
+ * Run the main networking control loop.
+ *
+ * The set of connections defined by the serf context @a ctx are processed.
+ * Any outbound data is delivered, and incoming data is made available to
+ * the associated response handlers and their buckets. This function will
+ * block on the network for no longer than @a duration microseconds.
+ *
+ * If any data is processed (incoming or outgoing), then this function will
+ * return with APR_SUCCESS. Typically, the caller will just want to call it
+ * again to continue processing data.
+ *
+ * If no activity occurs within the specified timeout duration, then
+ * APR_TIMEUP is returned.
+ *
+ * All temporary allocations will be made in @a pool.
+ */
+apr_status_t serf_context_run(
+ serf_context_t *ctx,
+ apr_short_interval_time_t duration,
+ apr_pool_t *pool);
+
+
+apr_status_t serf_context_prerun(
+ serf_context_t *ctx);
+
+/**
+ * Callback function for progress information. @a progress indicates cumulative
+ * number of bytes read or written, for the whole context.
+ */
+typedef void (*serf_progress_t)(
+ void *progress_baton,
+ apr_off_t read,
+ apr_off_t write);
+
+/**
+ * Sets the progress callback function. @a progress_func will be called every
+ * time bytes are read of or written on a socket.
+ */
+void serf_context_set_progress_cb(
+ serf_context_t *ctx,
+ const serf_progress_t progress_func,
+ void *progress_baton);
+
+/** @} */
+
+/**
+ * @defgroup serf connections and requests
+ * @ingroup serf
+ * @{
+ */
+
+/**
+ * When a connection is established, the application needs to wrap some
+ * buckets around @a skt to enable serf to process incoming responses. This
+ * is the control point for assembling connection-level processing logic
+ * around the given socket.
+ *
+ * The @a setup_baton is the baton established at connection creation time.
+ *
+ * This callback corresponds to reading from the server. Since this is an
+ * on-demand activity, we use a callback. The corresponding write operation
+ * is based on the @see serf_request_deliver function, where the application
+ * can assemble the appropriate bucket(s) before delivery.
+ *
+ * The returned bucket should live at least as long as the connection itself.
+ * It is assumed that an appropriate allocator is passed in @a setup_baton.
+ * ### we may want to create a connection-level allocator and pass that
+ * ### along. however, that allocator would *only* be used for this
+ * ### callback. it may be wasteful to create a per-conn allocator, so this
+ * ### baton-based, app-responsible form might be best.
+ *
+ * Responsibility for the buckets is passed to the serf library. They will be
+ * destroyed when the connection is closed.
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef apr_status_t (*serf_connection_setup_t)(
+ apr_socket_t *skt,
+ serf_bucket_t **read_bkt,
+ serf_bucket_t **write_bkt,
+ void *setup_baton,
+ apr_pool_t *pool);
+
+/**
+ * ### need to update docco w.r.t socket. became "stream" recently.
+ * ### the stream does not have a barrier, this callback should generally
+ * ### add a barrier around the stream before incorporating it into a
+ * ### response bucket stack.
+ * ### should serf add the barrier automatically to protect its data
+ * ### structure? i.e. the passed bucket becomes owned rather than
+ * ### borrowed. that might suit overall semantics better.
+ * Accept an incoming response for @a request, and its @a socket. A bucket
+ * for the response should be constructed and returned. This is the control
+ * point for assembling the appropriate wrapper buckets around the socket to
+ * enable processing of the incoming response.
+ *
+ * The @a acceptor_baton is the baton provided when the specified request
+ * was created.
+ *
+ * The request's pool and bucket allocator should be used for any allocations
+ * that need to live for the duration of the response. Care should be taken
+ * to bound the amount of memory stored in this pool -- to ensure that
+ * allocations are not proportional to the amount of data in the response.
+ *
+ * Responsibility for the bucket is passed to the serf library. It will be
+ * destroyed when the response has been fully read (the bucket returns an
+ * APR_EOF status from its read functions).
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+/* ### do we need to return an error? */
+typedef serf_bucket_t * (*serf_response_acceptor_t)(
+ serf_request_t *request,
+ serf_bucket_t *stream,
+ void *acceptor_baton,
+ apr_pool_t *pool);
+
+/**
+ * Notification callback for when a connection closes.
+ *
+ * This callback is used to inform an application that the @a conn
+ * connection has been (abnormally) closed. The @a closed_baton is the
+ * baton provided when the connection was first opened. The reason for
+ * closure is given in @a why, and will be APR_SUCCESS if the application
+ * requested closure (by clearing the pool used to allocate this
+ * connection or calling serf_connection_close).
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef void (*serf_connection_closed_t)(
+ serf_connection_t *conn,
+ void *closed_baton,
+ apr_status_t why,
+ apr_pool_t *pool);
+
+/**
+ * Response data has arrived and should be processed.
+ *
+ * Whenever response data for @a request arrives (initially, or continued data
+ * arrival), this handler is invoked. The response data is available in the
+ * @a response bucket. The @a handler_baton is passed along from the baton
+ * provided by the request setup callback (@see serf_request_setup_t).
+ *
+ * The handler MUST process data from the @a response bucket until the
+ * bucket's read function states it would block (see APR_STATUS_IS_EAGAIN).
+ * The handler is invoked only when new data arrives. If no further data
+ * arrives, and the handler does not process all available data, then the
+ * system can result in a deadlock around the unprocessed, but read, data.
+ *
+ * The handler should return APR_EOF when the response has been fully read.
+ * If calling the handler again would block, APR_EAGAIN should be returned.
+ * If the handler should be invoked again, simply return APR_SUCCESS.
+ *
+ * Note: if the connection closed (at the request of the application, or
+ * because of an (abnormal) termination) while a request is being delivered,
+ * or before a response arrives, then @a response will be NULL. This is the
+ * signal that the request was not delivered properly, and no further
+ * response should be expected (this callback will not be invoked again).
+ * If a request is injected into the connection (during this callback's
+ * execution, or otherwise), then the connection will be reopened.
+ *
+ * All temporary allocations should be made in @a pool.
+ */
+typedef apr_status_t (*serf_response_handler_t)(
+ serf_request_t *request,
+ serf_bucket_t *response,
+ void *handler_baton,
+ apr_pool_t *pool);
+
+/**
+ * Callback function to be implemented by the application, so that serf
+ * can handle server and proxy authentication.
+ * code = 401 (server) or 407 (proxy).
+ * baton = the baton passed to serf_context_run.
+ * authn_type = one of "Basic", "Digest".
+ */
+typedef apr_status_t (*serf_credentials_callback_t)(
+ char **username,
+ char **password,
+ serf_request_t *request, void *baton,
+ int code, const char *authn_type,
+ const char *realm,
+ apr_pool_t *pool);
+
+/**
+ * Create a new connection associated with the @a ctx serf context.
+ *
+ * A connection will be created to (eventually) connect to the address
+ * specified by @a address. The address must live at least as long as
+ * @a pool (thus, as long as the connection object).
+ *
+ * The connection object will be allocated within @a pool. Clearing or
+ * destroying this pool will close the connection, and terminate any
+ * outstanding requests or responses.
+ *
+ * When the connection is closed (upon request or because of an error),
+ * then the @a closed callback is invoked, and @a closed_baton is passed.
+ *
+ * ### doc on setup(_baton). tweak below comment re: acceptor.
+ * NULL may be passed for @a acceptor and @a closed; default implementations
+ * will be used.
+ *
+ * Note: the connection is not made immediately. It will be opened on
+ * the next call to @see serf_context_run.
+ */
+serf_connection_t *serf_connection_create(
+ serf_context_t *ctx,
+ apr_sockaddr_t *address,
+ serf_connection_setup_t setup,
+ void *setup_baton,
+ serf_connection_closed_t closed,
+ void *closed_baton,
+ apr_pool_t *pool);
+
+/**
+ * Create a new connection associated with the @a ctx serf context.
+ *
+ * A connection will be created to (eventually) connect to the address
+ * specified by @a address. The address must live at least as long as
+ * @a pool (thus, as long as the connection object).
+ *
+ * The host address will be looked up based on the hostname in @a host_info.
+ *
+ * The connection object will be allocated within @a pool. Clearing or
+ * destroying this pool will close the connection, and terminate any
+ * outstanding requests or responses.
+ *
+ * When the connection is closed (upon request or because of an error),
+ * then the @a closed callback is invoked, and @a closed_baton is passed.
+ *
+ * ### doc on setup(_baton). tweak below comment re: acceptor.
+ * NULL may be passed for @a acceptor and @a closed; default implementations
+ * will be used.
+ *
+ * Note: the connection is not made immediately. It will be opened on
+ * the next call to @see serf_context_run.
+ */
+apr_status_t serf_connection_create2(
+ serf_connection_t **conn,
+ serf_context_t *ctx,
+ apr_uri_t host_info,
+ serf_connection_setup_t setup,
+ void *setup_baton,
+ serf_connection_closed_t closed,
+ void *closed_baton,
+ apr_pool_t *pool);
+
+
+typedef apr_status_t (*serf_accept_client_t)(
+ serf_context_t *ctx,
+ serf_listener_t *l,
+ void *accept_baton,
+ apr_socket_t *insock,
+ apr_pool_t *pool);
+
+apr_status_t serf_listener_create(
+ serf_listener_t **listener,
+ serf_context_t *ctx,
+ const char *host,
+ apr_uint16_t port,
+ void *accept_baton,
+ serf_accept_client_t accept_func,
+ apr_pool_t *pool);
+
+typedef apr_status_t (*serf_incoming_request_cb_t)(
+ serf_context_t *ctx,
+ serf_incoming_request_t *req,
+ void *request_baton,
+ apr_pool_t *pool);
+
+apr_status_t serf_incoming_create(
+ serf_incoming_t **client,
+ serf_context_t *ctx,
+ apr_socket_t *insock,
+ void *request_baton,
+ serf_incoming_request_cb_t request,
+ apr_pool_t *pool);
+
+
+
+
+/**
+ * Reset the connection, but re-open the socket again.
+ */
+apr_status_t serf_connection_reset(
+ serf_connection_t *conn);
+
+/**
+ * Close the connection associated with @a conn and cancel all pending requests.
+ *
+ * The closed callback passed to serf_connection_create() will be invoked
+ * with APR_SUCCESS.
+ */
+apr_status_t serf_connection_close(
+ serf_connection_t *conn);
+
+/**
+ * Sets the maximum number of outstanding requests @a max_requests on the
+ * connection @a conn. Setting max_requests to 0 means unlimited (the default).
+ * Ex.: setting max_requests to 1 means a request is sent when a response on the
+ * previous request was received and handled.
+ */
+void serf_connection_set_max_outstanding_requests(
+ serf_connection_t *conn,
+ unsigned int max_requests);
+
+void serf_connection_set_async_responses(
+ serf_connection_t *conn,
+ serf_response_acceptor_t acceptor,
+ void *acceptor_baton,
+ serf_response_handler_t handler,
+ void *handler_baton);
+
+/**
+ * Setup the @a request for delivery on its connection.
+ *
+ * Right before this is invoked, @a pool will be built within the
+ * connection's pool for the request to use. The associated response will
+ * be allocated within that subpool. An associated bucket allocator will
+ * be built. These items may be fetched from the request object through
+ * @see serf_request_get_pool or @see serf_request_get_alloc.
+ *
+ * The content of the request is specified by the @a req_bkt bucket. When
+ * a response arrives, the @a acceptor callback will be invoked (along with
+ * the @a acceptor_baton) to produce a response bucket. That bucket will then
+ * be passed to @a handler, along with the @a handler_baton.
+ *
+ * The responsibility for the request bucket is passed to the request
+ * object. When the request is done with the bucket, it will be destroyed.
+ */
+typedef apr_status_t (*serf_request_setup_t)(
+ serf_request_t *request,
+ void *setup_baton,
+ serf_bucket_t **req_bkt,
+ serf_response_acceptor_t *acceptor,
+ void **acceptor_baton,
+ serf_response_handler_t *handler,
+ void **handler_baton,
+ apr_pool_t *pool);
+
+/**
+ * Construct a request object for the @a conn connection.
+ *
+ * When it is time to deliver the request, the @a setup callback will
+ * be invoked with the @a setup_baton passed into it to complete the
+ * construction of the request object.
+ *
+ * If the request has not (yet) been delivered, then it may be canceled
+ * with @see serf_request_cancel.
+ *
+ * Invoking any calls other than @see serf_request_cancel before the setup
+ * callback executes is not supported.
+ */
+serf_request_t *serf_connection_request_create(
+ serf_connection_t *conn,
+ serf_request_setup_t setup,
+ void *setup_baton);
+
+/**
+ * Construct a request object for the @a conn connection, add it in the
+ * list as the next to-be-written request before all unwritten requests.
+ *
+ * When it is time to deliver the request, the @a setup callback will
+ * be invoked with the @a setup_baton passed into it to complete the
+ * construction of the request object.
+ *
+ * If the request has not (yet) been delivered, then it may be canceled
+ * with @see serf_request_cancel.
+ *
+ * Invoking any calls other than @see serf_request_cancel before the setup
+ * callback executes is not supported.
+ */
+serf_request_t *serf_connection_priority_request_create(
+ serf_connection_t *conn,
+ serf_request_setup_t setup,
+ void *setup_baton);
+
+/**
+ * Cancel the request specified by the @a request object.
+ *
+ * If the request has been scheduled for delivery, then its response
+ * handler will be run, passing NULL for the response bucket.
+ *
+ * If the request has already been (partially or fully) delivered, then
+ * APR_EBUSY is returned and the request is *NOT* canceled. To properly
+ * cancel the request, the connection must be closed (by clearing or
+ * destroying its associated pool).
+ */
+apr_status_t serf_request_cancel(
+ serf_request_t *request);
+
+/**
+ * Return the pool associated with @a request.
+ *
+ * WARNING: be very careful about the kinds of things placed into this
+ * pool. In particular, all allocation should be bounded in size, rather
+ * than proportional to any data stream.
+ */
+apr_pool_t *serf_request_get_pool(
+ const serf_request_t *request);
+
+/**
+ * Return the bucket allocator associated with @a request.
+ */
+serf_bucket_alloc_t *serf_request_get_alloc(
+ const serf_request_t *request);
+
+/**
+ * Return the connection associated with @a request.
+ */
+serf_connection_t *serf_request_get_conn(
+ const serf_request_t *request);
+
+/**
+ * Update the @a handler and @a handler_baton for this @a request.
+ *
+ * This can be called after the request has started processing -
+ * subsequent data will be delivered to this new handler.
+ */
+void serf_request_set_handler(
+ serf_request_t *request,
+ const serf_response_handler_t handler,
+ const void **handler_baton);
+
+/**
+ * Configure proxy server settings, to be used by all connections associated
+ * with the @a ctx serf context.
+ *
+ * The next connection will be created to connect to the proxy server
+ * specified by @a address. The address must live at least as long as the
+ * serf context.
+ */
+void serf_config_proxy(
+ serf_context_t *ctx,
+ apr_sockaddr_t *address);
+
+/* Supported authentication types. */
+#define SERF_AUTHN_NONE 0x00
+#define SERF_AUTHN_BASIC 0x01
+#define SERF_AUTHN_DIGEST 0x02
+#define SERF_AUTHN_NTLM 0x04
+#define SERF_AUTHN_NEGOTIATE 0x08
+#define SERF_AUTHN_ALL 0xFF
+
+/**
+ * Define the authentication handlers that serf will try on incoming requests.
+ */
+void serf_config_authn_types(
+ serf_context_t *ctx,
+ int authn_types);
+
+/**
+ * Set the credentials callback handler.
+ */
+void serf_config_credentials_callback(
+ serf_context_t *ctx,
+ serf_credentials_callback_t cred_cb);
+
+/* ### maybe some connection control functions for flood? */
+
+/*** Special bucket creation functions ***/
+
+/**
+ * Create a bucket of type 'socket bucket'.
+ * This is basically a wrapper around @a serf_bucket_socket_create, which
+ * initializes the bucket using connection and/or context specific settings.
+ */
+serf_bucket_t *serf_context_bucket_socket_create(
+ serf_context_t *ctx,
+ apr_socket_t *skt,
+ serf_bucket_alloc_t *allocator);
+
+/**
+ * Create a bucket of type 'request bucket'.
+ * This is basically a wrapper around @a serf_bucket_request_create, which
+ * initializes the bucket using request, connection and/or context specific
+ * settings.
+ *
+ * This function will set following header(s):
+ * - Host: if the connection was created with @a serf_connection_create2.
+ */
+serf_bucket_t *serf_request_bucket_request_create(
+ serf_request_t *request,
+ const char *method,
+ const char *uri,
+ serf_bucket_t *body,
+ serf_bucket_alloc_t *allocator);
+
+/** @} */
+
+
+/**
+ * @defgroup serf buckets
+ * @ingroup serf
+ * @{
+ */
+
+/** Pass as REQUESTED to the read function of a bucket to read, consume,
+ * and return all available data.
+ */
+#define SERF_READ_ALL_AVAIL ((apr_size_t)-1)
+
+/** Acceptable newline types for bucket->readline(). */
+#define SERF_NEWLINE_CR 0x0001
+#define SERF_NEWLINE_CRLF 0x0002
+#define SERF_NEWLINE_LF 0x0004
+#define SERF_NEWLINE_ANY 0x0007
+
+/** Used to indicate that a newline is not present in the data buffer. */
+/* ### should we make this zero? */
+#define SERF_NEWLINE_NONE 0x0008
+
+/** Used to indicate that a CR was found at the end of a buffer, and CRLF
+ * was acceptable. It may be that the LF is present, but it needs to be
+ * read first.
+ *
+ * Note: an alternative to using this symbol would be for callers to see
+ * the SERF_NEWLINE_CR return value, and know that some "end of buffer" was
+ * reached. While this works well for @see serf_util_readline, it does not
+ * necessary work as well for buckets (there is no obvious "end of buffer",
+ * although there is an "end of bucket"). The other problem with that
+ * alternative is that developers might miss the condition. This symbol
+ * calls out the possibility and ensures that callers will watch for it.
+ */
+#define SERF_NEWLINE_CRLF_SPLIT 0x0010
+
+
+struct serf_bucket_type_t {
+
+ /** name of this bucket type */
+ const char *name;
+
+ /**
+ * Read (and consume) up to @a requested bytes from @a bucket.
+ *
+ * A pointer to the data will be returned in @a data, and its length
+ * is specified by @a len.
+ *
+ * The data will exist until one of two conditions occur:
+ *
+ * 1) this bucket is destroyed
+ * 2) another call to any read function or to peek()
+ *
+ * If an application needs the data to exist for a longer duration,
+ * then it must make a copy.
+ */
+ apr_status_t (*read)(serf_bucket_t *bucket, apr_size_t requested,
+ const char **data, apr_size_t *len);
+
+ /**
+ * Read (and consume) a line of data from @a bucket.
+ *
+ * The acceptable forms of a newline are given by @a acceptable, and
+ * the type found is returned in @a found. If a newline is not present
+ * in the returned data, then SERF_NEWLINE_NONE is stored into @a found.
+ *
+ * A pointer to the data is returned in @a data, and its length is
+ * specified by @a len. The data will include the newline, if present.
+ *
+ * Note that there is no way to limit the amount of data returned
+ * by this function.
+ *
+ * The lifetime of the data is the same as that of the @see read
+ * function above.
+ */
+ apr_status_t (*readline)(serf_bucket_t *bucket, int acceptable,
+ int *found,
+ const char **data, apr_size_t *len);
+
+ /**
+ * Read a set of pointer/length pairs from the bucket.
+ *
+ * The size of the @a vecs array is specified by @a vecs_size. The
+ * bucket should fill in elements of the array, and return the number
+ * used in @a vecs_used.
+ *
+ * Each element of @a vecs should specify a pointer to a block of
+ * data and a length of that data.
+ *
+ * The total length of all data elements should not exceed the
+ * amount specified in @a requested.
+ *
+ * The lifetime of the data is the same as that of the @see read
+ * function above.
+ */
+ apr_status_t (*read_iovec)(serf_bucket_t *bucket, apr_size_t requested,
+ int vecs_size, struct iovec *vecs,
+ int *vecs_used);
+
+ /**
+ * Read data from the bucket in a form suitable for apr_socket_sendfile()
+ *
+ * On input, hdtr->numheaders and hdtr->numtrailers specify the size
+ * of the hdtr->headers and hdtr->trailers arrays, respectively. The
+ * bucket should fill in the headers and trailers, up to the specified
+ * limits, and set numheaders and numtrailers to the number of iovecs
+ * filled in for each item.
+ *
+ * @a file should be filled in with a file that can be read. If a file
+ * is not available or appropriate, then NULL should be stored. The
+ * file offset for the data should be stored in @a offset, and the
+ * length of that data should be stored in @a len. If a file is not
+ * returned, then @a offset and @a len should be ignored.
+ *
+ * The file position is not required to correspond to @a offset, and
+ * the caller may manipulate it at will.
+ *
+ * The total length of all data elements, and the portion of the
+ * file should not exceed the amount specified in @a requested.
+ *
+ * The lifetime of the data is the same as that of the @see read
+ * function above.
+ */
+ apr_status_t (*read_for_sendfile)(serf_bucket_t *bucket,
+ apr_size_t requested, apr_hdtr_t *hdtr,
+ apr_file_t **file, apr_off_t *offset,
+ apr_size_t *len);
+
+ /**
+ * Look within @a bucket for a bucket of the given @a type. The bucket
+ * must be the "initial" data because it will be consumed by this
+ * function. If the given bucket type is available, then read and consume
+ * it, and return it to the caller.
+ *
+ * This function is usually used by readers that have custom handling
+ * for specific bucket types (e.g. looking for a file bucket to pass
+ * to apr_socket_sendfile).
+ *
+ * If a bucket of the given type is not found, then NULL is returned.
+ *
+ * The returned bucket becomes the responsibility of the caller. When
+ * the caller is done with the bucket, it should be destroyed.
+ */
+ serf_bucket_t * (*read_bucket)(serf_bucket_t *bucket,
+ const serf_bucket_type_t *type);
+
+ /**
+ * Peek, but don't consume, the data in @a bucket.
+ *
+ * Since this function is non-destructive, the implicit read size is
+ * SERF_READ_ALL_AVAIL. The caller can then use whatever amount is
+ * appropriate.
+ *
+ * The @a data parameter will point to the data, and @a len will
+ * specify how much data is available. The lifetime of the data follows
+ * the same rules as the @see read function above.
+ *
+ * Note: if the peek does not return enough data for your particular
+ * use, then you must read/consume some first, then peek again.
+ *
+ * If the returned data represents all available data, then APR_EOF
+ * will be returned. Since this function does not consume data, it
+ * can return the same data repeatedly rather than blocking; thus,
+ * APR_EAGAIN will never be returned.
+ */
+ apr_status_t (*peek)(serf_bucket_t *bucket,
+ const char **data, apr_size_t *len);
+
+ /**
+ * Destroy @a bucket, along with any associated resources.
+ */
+ void (*destroy)(serf_bucket_t *bucket);
+
+ /* ### apr buckets have 'copy', 'split', and 'setaside' functions.
+ ### not sure whether those will be needed in this bucket model.
+ */
+};
+
+/**
+ * Should the use and lifecycle of buckets be tracked?
+ *
+ * When tracking, the system will ensure several semantic requirements
+ * of bucket use:
+ *
+ * - if a bucket returns APR_EAGAIN, one of its read functions should
+ * not be called immediately. the context's run loop should be called.
+ * ### and for APR_EOF, too?
+ * - all buckets must be drained of input before returning to the
+ * context's run loop.
+ * - buckets should not be destroyed before they return APR_EOF unless
+ * the connection is closed for some reason.
+ *
+ * Undefine this symbol to avoid the tracking (and a performance gain).
+ *
+ * ### we may want to examine when/how we provide this. should it always
+ * ### be compiled in? and apps select it before including this header?
+ */
+/* #define SERF_DEBUG_BUCKET_USE */
+
+
+/* Internal macros for tracking bucket use. */
+#ifdef SERF_DEBUG_BUCKET_USE
+#define SERF__RECREAD(b,s) serf_debug__record_read(b,s)
+#else
+#define SERF__RECREAD(b,s) (s)
+#endif
+
+#define serf_bucket_read(b,r,d,l) SERF__RECREAD(b, (b)->type->read(b,r,d,l))
+#define serf_bucket_readline(b,a,f,d,l) \
+ SERF__RECREAD(b, (b)->type->readline(b,a,f,d,l))
+#define serf_bucket_read_iovec(b,r,s,v,u) \
+ SERF__RECREAD(b, (b)->type->read_iovec(b,r,s,v,u))
+#define serf_bucket_read_for_sendfile(b,r,h,f,o,l) \
+ SERF__RECREAD(b, (b)->type->read_for_sendfile(b,r,h,f,o,l))
+#define serf_bucket_read_bucket(b,t) ((b)->type->read_bucket(b,t))
+#define serf_bucket_peek(b,d,l) ((b)->type->peek(b,d,l))
+#define serf_bucket_destroy(b) ((b)->type->destroy(b))
+
+/**
+ * Check whether a real error occurred. Note that bucket read functions
+ * can return EOF and EAGAIN as part of their "normal" operation, so they
+ * should not be considered an error.
+ */
+#define SERF_BUCKET_READ_ERROR(status) ((status) \
+ && !APR_STATUS_IS_EOF(status) \
+ && !APR_STATUS_IS_EAGAIN(status) \
+ && (SERF_ERROR_WAIT_CONN != status))
+
+
+struct serf_bucket_t {
+
+ /** the type of this bucket */
+ const serf_bucket_type_t *type;
+
+ /** bucket-private data */
+ void *data;
+
+ /** the allocator used for this bucket (needed at destroy time) */
+ serf_bucket_alloc_t *allocator;
+};
+
+
+/**
+ * Generic macro to construct "is TYPE" macros.
+ */
+#define SERF_BUCKET_CHECK(b, btype) ((b)->type == &serf_bucket_type_ ## btype)
+
+
+/**
+ * Notification callback for a block that was not returned to the bucket
+ * allocator when its pool was destroyed.
+ *
+ * The block of memory is given by @a block. The baton provided when the
+ * allocator was constructed is passed as @a unfreed_baton.
+ */
+typedef void (*serf_unfreed_func_t)(
+ void *unfreed_baton,
+ void *block);
+
+/**
+ * Create a new allocator for buckets.
+ *
+ * All buckets are associated with a serf bucket allocator. This allocator
+ * will be created within @a pool and will be destroyed when that pool is
+ * cleared or destroyed.
+ *
+ * When the allocator is destroyed, if any allocations were not explicitly
+ * returned (by calling serf_bucket_mem_free), then the @a unfreed callback
+ * will be invoked for each block. @a unfreed_baton will be passed to the
+ * callback.
+ *
+ * If @a unfreed is NULL, then the library will invoke the abort() stdlib
+ * call. Any failure to return memory is a bug in the application, and an
+ * abort can assist with determining what kinds of memory were not freed.
+ */
+serf_bucket_alloc_t *serf_bucket_allocator_create(
+ apr_pool_t *pool,
+ serf_unfreed_func_t unfreed,
+ void *unfreed_baton);
+
+/**
+ * Return the pool that was used for this @a allocator.
+ *
+ * WARNING: the use of this pool for allocations requires a very
+ * detailed understanding of pool behaviors, the bucket system,
+ * and knowledge of the bucket's use within the overall pattern
+ * of request/response behavior.
+ *
+ * See design-guide.txt for more information about pool usage.
+ */
+apr_pool_t *serf_bucket_allocator_get_pool(
+ const serf_bucket_alloc_t *allocator);
+
+
+/**
+ * Utility structure for reading a complete line of input from a bucket.
+ *
+ * Since it is entirely possible for a line to be broken by APR_EAGAIN,
+ * this structure can be used to accumulate the data until a complete line
+ * has been read from a bucket.
+ */
+
+/* This limit applies to the line buffer functions. If an application needs
+ * longer lines, then they will need to manually handle line buffering.
+ */
+#define SERF_LINEBUF_LIMIT 8000
+
+typedef struct {
+
+ /* Current state of the buffer. */
+ enum {
+ SERF_LINEBUF_EMPTY,
+ SERF_LINEBUF_READY,
+ SERF_LINEBUF_PARTIAL,
+ SERF_LINEBUF_CRLF_SPLIT
+ } state;
+
+ /* How much of the buffer have we used? */
+ apr_size_t used;
+
+ /* The line is read into this buffer, minus CR/LF */
+ char line[SERF_LINEBUF_LIMIT];
+
+} serf_linebuf_t;
+
+/**
+ * Initialize the @a linebuf structure.
+ */
+void serf_linebuf_init(serf_linebuf_t *linebuf);
+
+/**
+ * Fetch a line of text from @a bucket, accumulating the line into
+ * @a linebuf. @a acceptable specifies the types of newlines which are
+ * acceptable for this fetch.
+ *
+ * ### we should return a data/len pair so that we can avoid a copy,
+ * ### rather than having callers look into our state and line buffer.
+ */
+apr_status_t serf_linebuf_fetch(
+ serf_linebuf_t *linebuf,
+ serf_bucket_t *bucket,
+ int acceptable);
+
+/** @} */
+
+
+/* Internal functions for bucket use and lifecycle tracking */
+apr_status_t serf_debug__record_read(
+ const serf_bucket_t *bucket,
+ apr_status_t status);
+void serf_debug__entered_loop(
+ serf_bucket_alloc_t *allocator);
+void serf_debug__closed_conn(
+ serf_bucket_alloc_t *allocator);
+void serf_debug__bucket_destroy(
+ const serf_bucket_t *bucket);
+void serf_debug__bucket_alloc_check(
+ serf_bucket_alloc_t *allocator);
+
+/* Version info */
+#define SERF_MAJOR_VERSION 1
+#define SERF_MINOR_VERSION 1
+#define SERF_PATCH_VERSION 0
+
+/* Version number string */
+#define SERF_VERSION_STRING APR_STRINGIFY(SERF_MAJOR_VERSION) "." \
+ APR_STRINGIFY(SERF_MINOR_VERSION) "." \
+ APR_STRINGIFY(SERF_PATCH_VERSION)
+
+/**
+ * Check at compile time if the Serf version is at least a certain
+ * level.
+ * @param major The major version component of the version checked
+ * for (e.g., the "1" of "1.3.0").
+ * @param minor The minor version component of the version checked
+ * for (e.g., the "3" of "1.3.0").
+ * @param patch The patch level component of the version checked
+ * for (e.g., the "0" of "1.3.0").
+ */
+#define SERF_VERSION_AT_LEAST(major,minor,patch) \
+(((major) < SERF_MAJOR_VERSION) \
+ || ((major) == SERF_MAJOR_VERSION && (minor) < SERF_MINOR_VERSION) \
+ || ((major) == SERF_MAJOR_VERSION && (minor) == SERF_MINOR_VERSION && \
+ (patch) <= SERF_PATCH_VERSION))
+
+
+/**
+ * Returns the version of the library the application has linked/loaded.
+ * Values are returned in @a major, @a minor, and @a patch.
+ *
+ * Applications will want to use this function to verify compatibility,
+ * expecially while serf has not reached a 1.0 milestone. APIs and
+ * semantics may change drastically until the library hits 1.0.
+ */
+void serf_lib_version(
+ int *major,
+ int *minor,
+ int *patch);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Every user of serf will want to deal with our various bucket types.
+ * Go ahead and include that header right now.
+ *
+ * Note: make sure this occurs outside of the C++ namespace block
+ */
+#include "serf_bucket_types.h"
+
+
+#endif /* !SERF_H */