| /* 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_PRIVATE_H_ |
| #define _SERF_PRIVATE_H_ |
| |
| /* ### what the hell? why does the APR interface have a "size" ?? |
| ### the implication is that, if we bust this limit, we'd need to |
| ### stop, rebuild a pollset, and repopulate it. what suckage. */ |
| #define MAX_CONN 16 |
| |
| /* Windows does not define IOV_MAX, so we need to ensure it is defined. */ |
| #ifndef IOV_MAX |
| #define IOV_MAX 16 |
| #endif |
| |
| /* Older versions of APR do not have this macro. */ |
| #ifdef APR_SIZE_MAX |
| #define REQUESTED_MAX APR_SIZE_MAX |
| #else |
| #define REQUESTED_MAX (~((apr_size_t)0)) |
| #endif |
| |
| #ifndef APR_VERSION_AT_LEAST /* Introduced in APR 1.3.0 */ |
| #define APR_VERSION_AT_LEAST(major,minor,patch) \ |
| (((major) < APR_MAJOR_VERSION) \ |
| || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION) \ |
| || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && \ |
| (patch) <= APR_PATCH_VERSION)) |
| #endif /* APR_VERSION_AT_LEAST */ |
| |
| #define SERF_IO_CLIENT (1) |
| #define SERF_IO_CONN (2) |
| #define SERF_IO_LISTENER (3) |
| |
| /* Internal logging facilities, set flag to 1 to enable console logging for |
| the selected component. */ |
| #define SSL_VERBOSE 0 |
| #define SSL_MSG_VERBOSE 0 /* logs decrypted requests and responses. */ |
| #define SOCK_VERBOSE 0 |
| #define SOCK_MSG_VERBOSE 0 /* logs bytes received from or written to a socket. */ |
| #define CONN_VERBOSE 0 |
| #define AUTH_VERBOSE 0 |
| |
| |
| typedef struct serf__authn_scheme_t serf__authn_scheme_t; |
| |
| typedef struct serf_io_baton_t { |
| int type; |
| union { |
| serf_incoming_t *client; |
| serf_connection_t *conn; |
| serf_listener_t *listener; |
| } u; |
| } serf_io_baton_t; |
| |
| /* Holds all the information corresponding to a request/response pair. */ |
| struct serf_request_t { |
| serf_connection_t *conn; |
| |
| apr_pool_t *respool; |
| serf_bucket_alloc_t *allocator; |
| |
| /* The bucket corresponding to the request. Will be NULL once the |
| * bucket has been emptied (for delivery into the socket). |
| */ |
| serf_bucket_t *req_bkt; |
| |
| serf_request_setup_t setup; |
| void *setup_baton; |
| |
| serf_response_acceptor_t acceptor; |
| void *acceptor_baton; |
| |
| serf_response_handler_t handler; |
| void *handler_baton; |
| |
| serf_bucket_t *resp_bkt; |
| |
| int written; |
| int priority; |
| /* 1 if this is a request to setup a SSL tunnel, 0 for normal requests. */ |
| int ssltunnel; |
| |
| /* This baton is currently only used for digest authentication, which |
| needs access to the uri of the request in the response handler. |
| If serf_request_t is replaced by a serf_http_request_t in the future, |
| which knows about uri and method and such, this baton won't be needed |
| anymore. */ |
| void *auth_baton; |
| |
| struct serf_request_t *next; |
| }; |
| |
| typedef struct serf_pollset_t { |
| /* the set of connections to poll */ |
| apr_pollset_t *pollset; |
| } serf_pollset_t; |
| |
| typedef struct serf__authn_info_t { |
| const serf__authn_scheme_t *scheme; |
| |
| void *baton; |
| } serf__authn_info_t; |
| |
| struct serf_context_t { |
| /* the pool used for self and for other allocations */ |
| apr_pool_t *pool; |
| |
| void *pollset_baton; |
| serf_socket_add_t pollset_add; |
| serf_socket_remove_t pollset_rm; |
| |
| /* one of our connections has a dirty pollset state. */ |
| int dirty_pollset; |
| |
| /* the list of active connections */ |
| apr_array_header_t *conns; |
| #define GET_CONN(ctx, i) (((serf_connection_t **)(ctx)->conns->elts)[i]) |
| |
| /* Proxy server address */ |
| apr_sockaddr_t *proxy_address; |
| |
| /* Progress callback */ |
| serf_progress_t progress_func; |
| void *progress_baton; |
| apr_off_t progress_read; |
| apr_off_t progress_written; |
| |
| /* authentication info for the servers used in this context. Shared by all |
| connections to the same server. |
| Structure of the hashtable: key: host url, e.g. https://localhost:80 |
| value: serf__authn_info_t * |
| */ |
| apr_hash_t *server_authn_info; |
| |
| /* authentication info for the proxy configured in this context, shared by |
| all connections. */ |
| serf__authn_info_t proxy_authn_info; |
| |
| /* List of authn types supported by the client.*/ |
| int authn_types; |
| /* Callback function used to get credentials for a realm. */ |
| serf_credentials_callback_t cred_cb; |
| }; |
| |
| struct serf_listener_t { |
| serf_context_t *ctx; |
| serf_io_baton_t baton; |
| apr_socket_t *skt; |
| apr_pool_t *pool; |
| apr_pollfd_t desc; |
| void *accept_baton; |
| serf_accept_client_t accept_func; |
| }; |
| |
| struct serf_incoming_t { |
| serf_context_t *ctx; |
| serf_io_baton_t baton; |
| void *request_baton; |
| serf_incoming_request_cb_t request; |
| apr_socket_t *skt; |
| apr_pollfd_t desc; |
| }; |
| |
| /* States for the different stages in the lifecyle of a connection. */ |
| typedef enum { |
| SERF_CONN_INIT, /* no socket created yet */ |
| SERF_CONN_SETUP_SSLTUNNEL, /* ssl tunnel being setup, no requests sent */ |
| SERF_CONN_CONNECTED, /* conn is ready to send requests */ |
| SERF_CONN_CLOSING /* conn is closing, no more requests, |
| start a new socket */ |
| } serf__connection_state_t; |
| |
| struct serf_connection_t { |
| serf_context_t *ctx; |
| |
| apr_status_t status; |
| serf_io_baton_t baton; |
| |
| apr_pool_t *pool; |
| serf_bucket_alloc_t *allocator; |
| |
| apr_sockaddr_t *address; |
| |
| apr_socket_t *skt; |
| apr_pool_t *skt_pool; |
| |
| /* the last reqevents we gave to pollset_add */ |
| apr_int16_t reqevents; |
| |
| /* the events we've seen for this connection in our returned pollset */ |
| apr_int16_t seen_in_pollset; |
| |
| /* are we a dirty connection that needs its poll status updated? */ |
| int dirty_conn; |
| |
| /* number of completed requests we've sent */ |
| unsigned int completed_requests; |
| |
| /* number of completed responses we've got */ |
| unsigned int completed_responses; |
| |
| /* keepalive */ |
| unsigned int probable_keepalive_limit; |
| |
| /* Current state of the connection (whether or not it is connected). */ |
| serf__connection_state_t state; |
| |
| /* This connection may have responses without a request! */ |
| int async_responses; |
| serf_bucket_t *current_async_response; |
| serf_response_acceptor_t async_acceptor; |
| void *async_acceptor_baton; |
| serf_response_handler_t async_handler; |
| void *async_handler_baton; |
| |
| /* A bucket wrapped around our socket (for reading responses). */ |
| serf_bucket_t *stream; |
| /* A reference to the aggregate bucket that provides the boundary between |
| * request level buckets and connection level buckets. |
| */ |
| serf_bucket_t *ostream_head; |
| serf_bucket_t *ostream_tail; |
| |
| /* Aggregate bucket used to send the CONNECT request. */ |
| serf_bucket_t *ssltunnel_ostream; |
| |
| /* The list of active requests. */ |
| serf_request_t *requests; |
| serf_request_t *requests_tail; |
| |
| struct iovec vec[IOV_MAX]; |
| int vec_len; |
| |
| serf_connection_setup_t setup; |
| void *setup_baton; |
| serf_connection_closed_t closed; |
| void *closed_baton; |
| |
| /* Max. number of outstanding requests. */ |
| unsigned int max_outstanding_requests; |
| |
| int hit_eof; |
| |
| /* Host url, path ommitted, syntax: https://svn.apache.org . */ |
| const char *host_url; |
| |
| /* Exploded host url, path ommitted. Only scheme, hostinfo, hostname & |
| port values are filled in. */ |
| apr_uri_t host_info; |
| |
| /* connection and authentication scheme specific information */ |
| void *authn_baton; |
| void *proxy_authn_baton; |
| |
| /* Time marker when connection begins. */ |
| apr_time_t connect_time; |
| |
| /* Calculated connection latency. Negative value if latency is unknown. */ |
| apr_interval_time_t latency; |
| |
| /* Needs to read first before we can write again. */ |
| int stop_writing; |
| }; |
| |
| /*** Internal bucket functions ***/ |
| |
| /** Transform a response_bucket in-place into an aggregate bucket. Restore the |
| status line and all headers, not just the body. |
| |
| This can only be used when we haven't started reading the body of the |
| response yet. |
| |
| Keep internal for now, probably only useful within serf. |
| */ |
| apr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket); |
| |
| /*** Authentication handler declarations ***/ |
| |
| typedef enum { PROXY, HOST } peer_t; |
| |
| /** |
| * For each authentication scheme we need a handler function of type |
| * serf__auth_handler_func_t. This function will be called when an |
| * authentication challenge is received in a session. |
| */ |
| typedef apr_status_t |
| (*serf__auth_handler_func_t)(int code, |
| serf_request_t *request, |
| serf_bucket_t *response, |
| const char *auth_hdr, |
| const char *auth_attr, |
| void *baton, |
| apr_pool_t *pool); |
| |
| /** |
| * For each authentication scheme we need an initialization function of type |
| * serf__init_context_func_t. This function will be called the first time |
| * serf tries a specific authentication scheme handler. |
| */ |
| typedef apr_status_t |
| (*serf__init_context_func_t)(int code, |
| serf_context_t *conn, |
| apr_pool_t *pool); |
| |
| /** |
| * For each authentication scheme we need an initialization function of type |
| * serf__init_conn_func_t. This function will be called when a new |
| * connection is opened. |
| */ |
| typedef apr_status_t |
| (*serf__init_conn_func_t)(const serf__authn_scheme_t *scheme, |
| int code, |
| serf_connection_t *conn, |
| apr_pool_t *pool); |
| |
| /** |
| * For each authentication scheme we need a setup_request function of type |
| * serf__setup_request_func_t. This function will be called when a |
| * new serf_request_t object is created and should fill in the correct |
| * authentication headers (if needed). |
| */ |
| typedef apr_status_t |
| (*serf__setup_request_func_t)(peer_t peer, |
| int code, |
| serf_connection_t *conn, |
| serf_request_t *request, |
| const char *method, |
| const char *uri, |
| serf_bucket_t *hdrs_bkt); |
| |
| /** |
| * This function will be called when a response is received, so that the |
| * scheme handler can validate the Authentication related response headers |
| * (if needed). |
| */ |
| typedef apr_status_t |
| (*serf__validate_response_func_t)(peer_t peer, |
| int code, |
| serf_connection_t *conn, |
| serf_request_t *request, |
| serf_bucket_t *response, |
| apr_pool_t *pool); |
| |
| /** |
| * serf__authn_scheme_t: vtable for an authn scheme provider. |
| */ |
| struct serf__authn_scheme_t { |
| /* The name of this authentication scheme. Used in headers of requests and |
| for logging. */ |
| const char *name; |
| |
| /* Key is the name of the authentication scheme in lower case, to |
| facilitate case insensitive matching of the response headers. */ |
| const char *key; |
| |
| /* Internal code used for this authn type. */ |
| int type; |
| |
| /* The context initialization function if any; otherwise, NULL */ |
| serf__init_context_func_t init_ctx_func; |
| |
| /* The connection initialization function if any; otherwise, NULL */ |
| serf__init_conn_func_t init_conn_func; |
| |
| /* The authentication handler function */ |
| serf__auth_handler_func_t handle_func; |
| |
| /* Function to set up the authentication header of a request */ |
| serf__setup_request_func_t setup_request_func; |
| |
| /* Function to validate the authentication header of a response */ |
| serf__validate_response_func_t validate_response_func; |
| }; |
| |
| /** |
| * Handles a 401 or 407 response, tries the different available authentication |
| * handlers. |
| */ |
| apr_status_t serf__handle_auth_response(int *consumed_response, |
| serf_request_t *request, |
| serf_bucket_t *response, |
| void *baton, |
| apr_pool_t *pool); |
| |
| /* Get the cached serf__authn_info_t object for the target server, or create one |
| when this is the first connection to the server. |
| TODO: The serf__authn_info_t objects are allocated in the context pool, so |
| a context that's used to connect to many different servers using Basic or |
| Digest authencation will hold on to many objects indefinitely. We should be |
| able to cleanup stale objects from time to time. */ |
| serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn); |
| |
| /* fromt context.c */ |
| void serf__context_progress_delta(void *progress_baton, apr_off_t read, |
| apr_off_t written); |
| |
| /* from incoming.c */ |
| apr_status_t serf__process_client(serf_incoming_t *l, apr_int16_t events); |
| apr_status_t serf__process_listener(serf_listener_t *l); |
| |
| /* from outgoing.c */ |
| apr_status_t serf__open_connections(serf_context_t *ctx); |
| apr_status_t serf__process_connection(serf_connection_t *conn, |
| apr_int16_t events); |
| apr_status_t serf__conn_update_pollset(serf_connection_t *conn); |
| serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn, |
| serf_request_setup_t setup, |
| void *setup_baton); |
| apr_status_t serf__provide_credentials(serf_context_t *ctx, |
| char **username, |
| char **password, |
| serf_request_t *request, |
| void *baton, |
| int code, const char *authn_type, |
| const char *realm, |
| apr_pool_t *pool); |
| |
| /* from ssltunnel.c */ |
| apr_status_t serf__ssltunnel_connect(serf_connection_t *conn); |
| |
| |
| /** Logging functions. Use one of the [COMP]_VERBOSE flags to enable specific |
| logging. |
| **/ |
| |
| /* Logs a standard event, with filename & timestamp header */ |
| void serf__log(int verbose_flag, const char *filename, const char *fmt, ...); |
| |
| /* Logs a standard event, but without prefix. This is useful to build up |
| log lines in parts. */ |
| void serf__log_nopref(int verbose_flag, const char *fmt, ...); |
| |
| /* Logs a socket event, add local and remote ip address:port */ |
| void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt, |
| const char *fmt, ...); |
| |
| #endif |