2 * ra_serf.h : Private declarations for the Serf-based DAV RA module.
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 #ifndef SVN_LIBSVN_RA_SERF_RA_SERF_H
25 #define SVN_LIBSVN_RA_SERF_RA_SERF_H
29 #include <expat.h> /* for XML_Parser */
32 #include "svn_types.h"
33 #include "svn_string.h"
34 #include "svn_pools.h"
36 #include "svn_delta.h"
37 #include "svn_version.h"
39 #include "svn_dirent_uri.h"
41 #include "private/svn_dav_protocol.h"
42 #include "private/svn_subr_private.h"
43 #include "private/svn_editor.h"
49 #endif /* __cplusplus */
52 /* Enforce the minimum version of serf. */
53 #if !SERF_VERSION_AT_LEAST(1, 2, 1)
54 #error Please update your version of serf to at least 1.2.1.
57 /** Wait duration (in microseconds) used in calls to serf_context_run() */
58 #define SVN_RA_SERF__CONTEXT_RUN_DURATION 500000
62 /* Forward declarations. */
63 typedef struct svn_ra_serf__session_t svn_ra_serf__session_t;
65 /* A serf connection and optionally associated SSL context. */
66 typedef struct svn_ra_serf__connection_t {
67 /* Our connection to a server. */
68 serf_connection_t *conn;
70 /* Bucket allocator for this connection. */
71 serf_bucket_alloc_t *bkt_alloc;
73 /* Collected cert failures in chain. */
74 int server_cert_failures;
76 /* What was the last HTTP status code we got on this connection? */
79 /* Optional SSL context for this connection. */
80 serf_ssl_context_t *ssl_context;
81 svn_auth_iterstate_t *ssl_client_auth_state;
82 svn_auth_iterstate_t *ssl_client_pw_auth_state;
84 svn_ra_serf__session_t *session;
86 } svn_ra_serf__connection_t;
88 /** Maximum value we'll allow for the http-max-connections config option.
90 * Note: minimum 2 connections are required for ra_serf to function
93 #define SVN_RA_SERF__MAX_CONNECTIONS_LIMIT 8
96 * The master serf RA session.
98 * This is stored in the ra session ->priv field.
100 * ### Check ra_serf_dup_session when adding fields.
102 struct svn_ra_serf__session_t {
103 /* Pool for allocations during this session */
105 apr_hash_t *config; /* For duplicating */
107 /* The current context */
108 serf_context_t *context;
110 /* The maximum number of connections we'll use for parallelized
111 fetch operations (updates, etc.) */
112 apr_int64_t max_connections;
114 /* Are we using ssl */
115 svn_boolean_t using_ssl;
117 /* Should we ask for compressed responses? */
118 svn_boolean_t using_compression;
120 /* The user agent string */
121 const char *useragent;
123 /* The current connection */
124 svn_ra_serf__connection_t *conns[SVN_RA_SERF__MAX_CONNECTIONS_LIMIT];
128 /* The URL that was passed into _open() */
129 apr_uri_t session_url;
130 const char *session_url_str;
132 /* The actual discovered root; may be NULL until we know it. */
133 apr_uri_t repos_root;
134 const char *repos_root_str;
136 /* The server is not Apache/mod_dav_svn (directly) and only supports
137 HTTP/1.0. Thus, we cannot send chunked requests. */
138 svn_boolean_t http10;
140 /* Should we use Transfer-Encoding: chunked for HTTP/1.1 servers. */
141 svn_boolean_t using_chunked_requests;
143 /* Do we need to detect whether the connection supports chunked requests?
144 i.e. is there a (reverse) proxy that does not support them? */
145 svn_boolean_t detect_chunking;
147 /* Our Version-Controlled-Configuration; may be NULL until we know it. */
150 /* Authentication related properties. */
151 svn_auth_iterstate_t *auth_state;
154 /* Callback functions to get info from WC */
155 const svn_ra_callbacks2_t *wc_callbacks;
156 void *wc_callback_baton;
157 svn_auth_baton_t *auth_baton;
159 /* Callback function to send progress info to the client */
160 svn_ra_progress_notify_func_t progress_func;
161 void *progress_baton;
163 /* Callback function to handle cancellation */
164 svn_cancel_func_t cancel_func;
167 /* Ev2 shim callbacks */
168 svn_delta_shim_callbacks_t *shim_callbacks;
170 /* Error that we've received but not yet returned upstream. */
171 svn_error_t *pending_error;
173 /* List of authn types supported by the client.*/
176 /* Maps SVN_RA_CAPABILITY_foo keys to "yes" or "no" values.
177 If a capability is not yet discovered, it is absent from the table.
178 The table itself is allocated in the svn_ra_serf__session_t's pool;
179 keys and values must have at least that lifetime. Most likely
180 the keys and values are constants anyway (and sufficiently
181 well-informed internal code may just compare against those
182 constants' addresses, therefore). */
183 apr_hash_t *capabilities;
185 /* Activity collection URL. (Cached from the initial OPTIONS
186 request when run against HTTPv1 servers.) */
187 const char *activity_collection_url;
189 /* Are we using a proxy? */
190 svn_boolean_t using_proxy;
192 const char *proxy_username;
193 const char *proxy_password;
194 int proxy_auth_attempts;
196 /* SSL server certificates */
197 svn_boolean_t trust_default_ca;
198 const char *ssl_authorities;
200 /* Repository UUID */
203 /* Connection timeout value */
204 apr_interval_time_t timeout;
207 svn_tristate_t supports_deadprop_count;
209 /*** HTTP v2 protocol stuff. ***
211 * We assume that if mod_dav_svn sends one of the special v2 OPTIONs
212 * response headers, it has sent all of them. Specifically, we'll
213 * be looking at the presence of the "me resource" as a flag that
214 * the server supports v2 of our HTTP protocol.
217 /* The "me resource". Typically used as a target for REPORTs that
218 are path-agnostic. If we have this, we can speak HTTP v2 to the
220 const char *me_resource;
222 /* Opaque URL "stubs". If the OPTIONS response returns these, then
223 we know we're using HTTP protocol v2. */
224 const char *rev_stub; /* for accessing revisions (i.e. revprops) */
225 const char *rev_root_stub; /* for accessing REV/PATH pairs */
226 const char *txn_stub; /* for accessing transactions (i.e. txnprops) */
227 const char *txn_root_stub; /* for accessing TXN/PATH pairs */
228 const char *vtxn_stub; /* for accessing transactions (i.e. txnprops) */
229 const char *vtxn_root_stub; /* for accessing TXN/PATH pairs */
231 /* Hash mapping const char * server-supported POST types to
232 disinteresting-but-non-null values. */
233 apr_hash_t *supported_posts;
235 /*** End HTTP v2 stuff ***/
237 svn_ra_serf__blncache_t *blncache;
239 /* Trisate flag that indicates user preference for using bulk updates
240 (svn_tristate_true) with all the properties and content in the
241 update-report response. If svn_tristate_false, request a skelta
242 update-report with inlined properties. If svn_tristate_unknown then use
243 server preference. */
244 svn_tristate_t bulk_updates;
246 /* Indicates if the server wants bulk update requests (Prefer) or only
247 accepts skelta requests (Off). If this value is On both options are
249 const char *server_allows_bulk;
251 /* Indicates if the server supports sending inlined props in update editor
252 * in skelta mode (send-all == 'false'). */
253 svn_boolean_t supports_inline_props;
255 /* Indicates whether the server supports issuing replay REPORTs
256 against rev resources (children of `rev_stub', elsestruct). */
257 svn_boolean_t supports_rev_rsrc_replay;
260 #define SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(sess) ((sess)->me_resource != NULL)
263 * Structure which represents a DAV element with a NAMESPACE and NAME.
265 typedef struct svn_ra_serf__dav_props_t {
266 /* Element namespace */
270 } svn_ra_serf__dav_props_t;
272 /** DAV property sets **/
274 static const svn_ra_serf__dav_props_t base_props[] =
276 { "DAV:", "version-controlled-configuration" },
277 { "DAV:", "resourcetype" },
278 { SVN_DAV_PROP_NS_DAV, "baseline-relative-path" },
279 { SVN_DAV_PROP_NS_DAV, "repository-uuid" },
283 static const svn_ra_serf__dav_props_t checked_in_props[] =
285 { "DAV:", "checked-in" },
289 static const svn_ra_serf__dav_props_t baseline_props[] =
291 { "DAV:", "baseline-collection" },
292 { "DAV:", SVN_DAV__VERSION_NAME },
296 static const svn_ra_serf__dav_props_t all_props[] =
298 { "DAV:", "allprop" },
302 static const svn_ra_serf__dav_props_t check_path_props[] =
304 { "DAV:", "resourcetype" },
308 static const svn_ra_serf__dav_props_t type_and_checksum_props[] =
310 { "DAV:", "resourcetype" },
311 { SVN_DAV_PROP_NS_DAV, "sha1-checksum" },
315 /* WC props compatibility with ra_neon. */
316 #define SVN_RA_SERF__WC_CHECKED_IN_URL SVN_PROP_WC_PREFIX "ra_dav:version-url"
318 /** Serf utility functions **/
321 svn_ra_serf__conn_setup(apr_socket_t *sock,
322 serf_bucket_t **read_bkt,
323 serf_bucket_t **write_bkt,
328 svn_ra_serf__conn_closed(serf_connection_t *conn,
334 /* Helper function to provide SSL client certificates.
336 * NOTE: This function sets the session's 'pending_error' member when
337 * returning an non-success status.
340 svn_ra_serf__handle_client_cert(void *data,
341 const char **cert_path);
343 /* Helper function to provide SSL client certificate passwords.
345 * NOTE: This function sets the session's 'pending_error' member when
346 * returning an non-success status.
349 svn_ra_serf__handle_client_cert_pw(void *data,
350 const char *cert_path,
351 const char **password);
355 * This function will run the serf context in SESS until *DONE is TRUE.
358 svn_ra_serf__context_run_wait(svn_boolean_t *done,
359 svn_ra_serf__session_t *sess,
360 apr_pool_t *scratch_pool);
362 /* Run the context once. Manage waittime_left to handle timing out when
363 nothing happens over the session->timout.
366 svn_ra_serf__context_run(svn_ra_serf__session_t *sess,
367 apr_interval_time_t *waittime_left,
368 apr_pool_t *scratch_pool);
372 /* Callback for response handlers */
373 typedef svn_error_t *
374 (*svn_ra_serf__response_handler_t)(serf_request_t *request,
375 serf_bucket_t *response,
377 apr_pool_t *scratch_pool);
379 /* Callback when the request is done */
380 typedef svn_error_t *
381 (*svn_ra_serf__response_done_delegate_t)(serf_request_t *request,
383 apr_pool_t *scratch_pool);
385 /* Callback for when a request body is needed. */
386 typedef svn_error_t *
387 (*svn_ra_serf__request_body_delegate_t)(serf_bucket_t **body_bkt,
389 serf_bucket_alloc_t *alloc,
390 apr_pool_t *request_pool,
391 apr_pool_t *scratch_pool);
393 /* Callback for when request headers are needed. */
394 typedef svn_error_t *
395 (*svn_ra_serf__request_header_delegate_t)(serf_bucket_t *headers,
397 apr_pool_t *request_pool,
398 apr_pool_t *scratch_pool);
400 /* Callback for when a response has an error. */
401 typedef svn_error_t *
402 (*svn_ra_serf__response_error_t)(serf_request_t *request,
403 serf_bucket_t *response,
407 /* ### we should reorder the types in this file. */
408 typedef struct svn_ra_serf__server_error_t svn_ra_serf__server_error_t;
411 * Structure that can be passed to our default handler to guide the
412 * execution of the request through its lifecycle.
414 * Use svn_ra_serf__create_handler() to create instances of this struct.
416 typedef struct svn_ra_serf__handler_t {
417 /* The HTTP method string of the request */
420 /* The resource to the execute the method on. */
423 /* The content-type of the request body. */
424 const char *body_type;
426 /* If TRUE then default Accept-Encoding request header is not configured for
427 request. If FALSE then 'gzip' accept encoding will be used if compression
429 svn_boolean_t custom_accept_encoding;
431 /* If TRUE then default DAV: capabilities request headers is not configured
433 svn_boolean_t no_dav_headers;
435 /* If TRUE doesn't fail requests on HTTP error statuses like 405, 408, 500
436 (see util.c response_done()) */
437 svn_boolean_t no_fail_on_http_failure_status;
439 /* If TRUE doesn't fail requests on HTTP redirect statuses like 301, 307 */
440 svn_boolean_t no_fail_on_http_redirect_status;
442 /* Has the request/response been completed? */
444 svn_boolean_t scheduled; /* Is the request scheduled in a context */
446 /* If we captured an error from the server, then this will be non-NULL.
447 It will be allocated from HANDLER_POOL. */
448 svn_ra_serf__server_error_t *server_error;
450 /* The handler and baton pair for our handler. */
451 svn_ra_serf__response_handler_t response_handler;
452 void *response_baton;
454 /* When REPONSE_HANDLER is invoked, the following fields will be set
455 based on the response header. HANDLER_POOL must be non-NULL for these
456 values to be filled in. SLINE.REASON and LOCATION will be allocated
457 within HANDLER_POOL. */
458 serf_status_line sline; /* The parsed Status-Line */
459 const char *location; /* The Location: header, if any */
461 /* This function and baton pair allows handling the completion of request.
463 * The default handler is responsible for the HTTP failure processing.
465 * If no_fail_on_http_failure_status is not TRUE, then the callback will
466 * return recorded server errors or if there is none and the http status
467 * specifies an error returns an error for that.
469 * The default baton is the handler itself.
471 svn_ra_serf__response_done_delegate_t done_delegate;
472 void *done_delegate_baton;
474 /* The handler and baton pair to be executed when a non-recoverable error
475 * is detected. If it is NULL in the presence of an error, an abort() may
478 svn_ra_serf__response_error_t response_error;
479 void *response_error_baton;
481 /* This function and baton pair allows for custom request headers to
484 * It will be executed after the request has been set up but before it is
487 svn_ra_serf__request_header_delegate_t header_delegate;
488 void *header_delegate_baton;
490 /* This function and baton pair allows a body to be created right before
493 * It will be executed after the request has been set up but before it is
496 * May be NULL if there is no body to send.
499 svn_ra_serf__request_body_delegate_t body_delegate;
500 void *body_delegate_baton;
502 /* The connection and session to be used for this request. */
503 svn_ra_serf__connection_t *conn;
504 svn_ra_serf__session_t *session;
506 /* Internal flag to indicate we've parsed the headers. */
507 svn_boolean_t reading_body;
509 /* When this flag will be set, the core handler will discard any unread
510 portion of the response body. The registered response handler will
511 no longer be called. */
512 svn_boolean_t discard_body;
514 /* Pool for allocating SLINE.REASON and LOCATION. If this pool is NULL,
515 then the requestor does not care about SLINE and LOCATION. */
516 apr_pool_t *handler_pool;
517 } svn_ra_serf__handler_t;
520 /* Run one request and process the response.
522 Similar to context_run_wait(), but this creates the request for HANDLER
523 and then waits for it to complete.
525 WARNING: context_run_wait() does NOT create a request, whereas this
526 function DOES. Avoid a double-create. */
528 svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler,
529 apr_pool_t *scratch_pool);
533 * Helper function to queue a request in the @a handler's connection.
535 void svn_ra_serf__request_create(svn_ra_serf__handler_t *handler);
537 /* v2 of the XML parsing functions */
539 /* The XML parsing context. */
540 typedef struct svn_ra_serf__xml_context_t svn_ra_serf__xml_context_t;
543 /* An opaque structure for the XML parse element/state. */
544 typedef struct svn_ra_serf__xml_estate_t svn_ra_serf__xml_estate_t;
546 /* Called just after the parser moves into ENTERED_STATE. The tag causing
547 the transition is passed in TAG.
549 This callback is applied to a parsing context by using the
550 svn_ra_serf__xml_context_customize() function.
552 NOTE: this callback, when set, will be invoked on *every* transition.
553 The callback must examine ENTERED_STATE to determine if any action
554 must be taken. The original state is not provided, but must be derived
555 from ENTERED_STATE and/or the TAG causing the transition (if needed). */
556 typedef svn_error_t *
557 (*svn_ra_serf__xml_opened_t)(svn_ra_serf__xml_estate_t *xes,
560 const svn_ra_serf__dav_props_t *tag,
561 apr_pool_t *scratch_pool);
564 /* Called just before the parser leaves LEAVING_STATE.
566 If cdata collection was enabled for this state, then CDATA will be
567 non-NULL and contain the collected cdata.
569 If attribute collection was enabled for this state, then ATTRS will
570 contain the attributes collected for this element only, along with
571 any values stored via svn_ra_serf__xml_note().
573 Use svn_ra_serf__xml_gather_since() to gather up data from outer states.
575 ATTRS is char* -> char*.
577 Temporary allocations may be made in SCRATCH_POOL. */
578 typedef svn_error_t *
579 (*svn_ra_serf__xml_closed_t)(svn_ra_serf__xml_estate_t *xes,
582 const svn_string_t *cdata,
584 apr_pool_t *scratch_pool);
587 /* Called for all states that are not using the builtin cdata collection.
588 This callback is (only) appropriate for unbounded-size cdata content.
590 CURRENT_STATE may be used to decide what to do with the data.
592 Temporary allocations may be made in SCRATCH_POOL. */
593 typedef svn_error_t *
594 (*svn_ra_serf__xml_cdata_t)(svn_ra_serf__xml_estate_t *xes,
599 apr_pool_t *scratch_pool);
602 /* Magic state value for the initial state in a svn_ra_serf__xml_transition_t
604 #define XML_STATE_INITIAL 0
606 /* State transition table.
608 When the XML Context is constructed, it is in state 0. User states are
611 In a list of transitions, use { 0 } to indicate the end. Specifically,
612 the code looks for NS == NULL.
614 The initial state for each transition table is XML_STATE_INITIAL.
618 typedef struct svn_ra_serf__xml_transition_t {
619 /* This transition applies when in this state */
622 /* And when this tag is observed */
626 /* Moving to this state */
629 /* Should the cdata of NAME be collected? Note that CUSTOM_CLOSE should
630 be TRUE in order to capture this cdata. */
631 svn_boolean_t collect_cdata;
633 /* Which attributes of NAME should be collected? Terminate with NULL.
634 Maximum of 10 attributes may be collected. Note that attribute
635 namespaces are ignored at this time.
637 Attribute names beginning with "?" are optional. Other names must
638 exist on the element, or SVN_ERR_XML_ATTRIB_NOT_FOUND will be raised. */
639 const char *collect_attrs[11];
641 /* When NAME is closed, should the callback be invoked? */
642 svn_boolean_t custom_close;
644 } svn_ra_serf__xml_transition_t;
646 /* Constructor for svn_ra_serf__handler_t. Initializes a new handler
647 with default settings for SESSION. */
648 svn_ra_serf__handler_t *
649 svn_ra_serf__create_handler(svn_ra_serf__session_t *session,
650 apr_pool_t *result_pool);
652 /* Construct an XML parsing context, based on the TTABLE transition table.
653 As content is parsed, the CLOSED_CB callback will be invoked according
654 to the definition in the table.
656 If OPENED_CB is not NULL, then it will be invoked for *every* tag-open
657 event. The callback will need to use the ENTERED_STATE and TAG parameters
658 to decide what it would like to do.
660 If CDATA_CB is not NULL, then it will be called for all cdata that is
661 not be automatically collected (based on the transition table record's
662 COLLECT_CDATA flag). It will be called in every state, so the callback
663 must examine the CURRENT_STATE parameter to decide what to do.
665 The same BATON value will be passed to all three callbacks.
667 The context will be created within RESULT_POOL. */
668 svn_ra_serf__xml_context_t *
669 svn_ra_serf__xml_context_create(
670 const svn_ra_serf__xml_transition_t *ttable,
671 svn_ra_serf__xml_opened_t opened_cb,
672 svn_ra_serf__xml_closed_t closed_cb,
673 svn_ra_serf__xml_cdata_t cdata_cb,
675 apr_pool_t *result_pool);
677 /* Verifies if the parsing completed successfully and destroys
680 svn_ra_serf__xml_context_done(svn_ra_serf__xml_context_t *xmlctx);
682 /* Construct a handler with the response function/baton set up to parse
683 a response body using the given XML context. The handler and its
684 internal structures are allocated in RESULT_POOL.
686 As part of the handling the http status value is compared to 200, or
687 if EXPECTED_STATUS is not NULL to all the values in EXPECTED_STATUS.
688 EXPECTED_STATUS is expected to be a list of integers ending with a 0
689 that lives at least as long as RESULT_POOL. If the status doesn't
690 match the request has failed and will be parsed as en error response.
692 This also initializes HANDLER_POOL to the given RESULT_POOL. */
693 svn_ra_serf__handler_t *
694 svn_ra_serf__create_expat_handler(svn_ra_serf__session_t *session,
695 svn_ra_serf__xml_context_t *xmlctx,
696 const int *expected_status,
697 apr_pool_t *result_pool);
700 /* Allocated within XES->STATE_POOL. Changes are not allowd (callers
701 should make a deep copy if they need to make changes).
703 The resulting hash maps char* names to char* values. */
705 svn_ra_serf__xml_gather_since(svn_ra_serf__xml_estate_t *xes,
709 /* Attach the NAME/VALUE pair onto this/parent state identified by STATE.
710 The name and value will be copied into the target state's pool.
712 These values will be available to the CLOSED_CB for the target state,
713 or part of the gathered state via xml_gather_since().
715 Typically, this function is used by a child state's close callback,
716 or within an opening callback to store additional data.
718 Note: if the state is not found, then a programmer error has occurred,
719 so the function will invoke SVN_ERR_MALFUNCTION(). */
721 svn_ra_serf__xml_note(svn_ra_serf__xml_estate_t *xes,
727 /* Returns XES->STATE_POOL for allocating structures that should live
728 as long as the state identified by XES.
730 Note: a state pool is created upon demand, so only use this function
731 when memory is required for a given state. */
733 svn_ra_serf__xml_state_pool(svn_ra_serf__xml_estate_t *xes);
736 * Parses a server-side error message into a local Subversion error.
738 struct svn_ra_serf__server_error_t {
741 /* XML parser and namespace used to parse the remote response */
742 svn_ra_serf__xml_context_t *xmlctx;
744 svn_ra_serf__response_handler_t response_handler;
745 void *response_baton;
747 /* The partial errors to construct the final error from */
748 apr_array_header_t *items;
750 /* The hooked handler */
751 svn_ra_serf__handler_t *handler;
755 * Handler that discards the entire @a response body associated with a
756 * @a request. Implements svn_ra_serf__response_handler_t.
758 * If @a baton is a svn_ra_serf__server_error_t (i.e. non-NULL) and an
759 * error is detected, it will be populated for later detection.
761 * All temporary allocations will be made in a @a pool.
764 svn_ra_serf__handle_discard_body(serf_request_t *request,
765 serf_bucket_t *response,
771 * Handler that retrieves the embedded XML multistatus response from the
772 * the @a RESPONSE body associated with a @a REQUEST.
774 * Implements svn_ra_serf__response_handler_t.
776 * The @a BATON should be of type svn_ra_serf__handler_t. When the request
777 * is complete, the handler's DONE flag will be set to TRUE.
779 * All temporary allocations will be made in a @a scratch_pool.
782 svn_ra_serf__handle_multistatus_only(serf_request_t *request,
783 serf_bucket_t *response,
785 apr_pool_t *scratch_pool);
788 /* Handler that expects an empty body.
790 If a body IS present, and it is text/xml, then it will be parsed for
793 BATON should be the svn_ra_serf__handler_t running REQUEST.
795 Status line information will be in HANDLER->SLINE.
797 Any parsed errors will be left in HANDLER->SERVER_ERROR. That member
798 may be NULL if no body was present, or a problem occurred trying to
801 All temporary allocations will be made in SCRATCH_POOL. */
803 svn_ra_serf__expect_empty_body(serf_request_t *request,
804 serf_bucket_t *response,
806 apr_pool_t *scratch_pool);
810 * This function sets up error parsing for an existing request
813 svn_ra_serf__setup_error_parsing(svn_ra_serf__server_error_t **server_err,
814 svn_ra_serf__handler_t *handler,
815 svn_boolean_t expect_207_only,
816 apr_pool_t *result_pool,
817 apr_pool_t *scratch_pool);
820 * Forwards response data to the server error parser
823 svn_ra_serf__handle_server_error(svn_ra_serf__server_error_t *server_error,
824 svn_ra_serf__handler_t *handler,
825 serf_request_t *request,
826 serf_bucket_t *response,
827 apr_status_t *serf_status,
828 apr_pool_t *scratch_pool);
831 * Creates the svn_error_t * instance from the error recorded in
832 * HANDLER->server_error
835 svn_ra_serf__server_error_create(svn_ra_serf__handler_t *handler,
836 apr_pool_t *scratch_pool);
838 /* serf_response_handler_t implementation that completely discards
841 * All temporary allocations will be made in @a pool.
844 svn_ra_serf__response_discard_handler(serf_request_t *request,
845 serf_bucket_t *response,
851 * Add the appropriate serf buckets to @a agg_bucket represented by
852 * the XML * @a tag and @a value.
854 * The bucket will be allocated from @a bkt_alloc.
857 svn_ra_serf__add_tag_buckets(serf_bucket_t *agg_bucket,
860 serf_bucket_alloc_t *bkt_alloc);
863 * Add the appropriate serf buckets to AGG_BUCKET with standard XML header:
864 * <?xml version="1.0" encoding="utf-8"?>
866 * The bucket will be allocated from BKT_ALLOC.
869 svn_ra_serf__add_xml_header_buckets(serf_bucket_t *agg_bucket,
870 serf_bucket_alloc_t *bkt_alloc);
873 * Add the appropriate serf buckets to AGG_BUCKET representing the XML
874 * open tag with name TAG.
876 * Take the tag's attributes from varargs, a NULL-terminated list of
877 * alternating <tt>char *</tt> key and <tt>char *</tt> val. Attribute
878 * will be ignored if it's value is NULL.
880 * NOTE: Callers are responsible for XML-escaping attribute values as
883 * The bucket will be allocated from BKT_ALLOC.
886 svn_ra_serf__add_open_tag_buckets(serf_bucket_t *agg_bucket,
887 serf_bucket_alloc_t *bkt_alloc,
889 ...) SVN_NEEDS_SENTINEL_NULL;
892 * Add the appropriate serf buckets to AGG_BUCKET representing xml tag close
895 * The bucket will be allocated from BKT_ALLOC.
898 svn_ra_serf__add_close_tag_buckets(serf_bucket_t *agg_bucket,
899 serf_bucket_alloc_t *bkt_alloc,
902 /* Add the appropriate serf buckets to AGG_BUCKET representing the XML
903 * open tag with name TAG, and then immediately closes the tag using the />
907 svn_ra_serf__add_empty_tag_buckets(serf_bucket_t *agg_bucket,
908 serf_bucket_alloc_t *bkt_alloc,
910 ...) SVN_NEEDS_SENTINEL_NULL;
913 * Add the appropriate serf buckets to AGG_BUCKET with xml-escaped
916 * The bucket will be allocated from BKT_ALLOC.
919 svn_ra_serf__add_cdata_len_buckets(serf_bucket_t *agg_bucket,
920 serf_bucket_alloc_t *bkt_alloc,
921 const char *data, apr_size_t len);
924 /** PROPFIND-related functions **/
926 /* Removes all non regular properties from PROPS */
928 svn_ra_serf__keep_only_regular_props(apr_hash_t *props,
929 apr_pool_t *scratch_pool);
932 /* Callback used via svn_ra_serf__deliver_props2 */
933 typedef svn_error_t *
934 (*svn_ra_serf__prop_func_t)(void *baton,
938 const svn_string_t *value,
939 apr_pool_t *scratch_pool);
942 * Implementation of svn_ra_serf__prop_func_t that just delivers svn compatible
943 * properties in the apr_hash_t * that is used as baton.
946 svn_ra_serf__deliver_svn_props(void *baton,
950 const svn_string_t *value,
951 apr_pool_t *scratch_pool);
954 * This function will create a handler for a PROPFIND request, which will deliver
955 * properties to PROP_FUNC() with PROP_BATON for the properties listed in LOOKUP_PROPS
956 * at URL for DEPTH ("0","1","infinity").
959 svn_ra_serf__create_propfind_handler(svn_ra_serf__handler_t **handler,
960 svn_ra_serf__session_t *session,
964 const svn_ra_serf__dav_props_t *find_props,
965 svn_ra_serf__prop_func_t prop_func,
966 void *prop_func_baton,
967 apr_pool_t *result_pool);
970 /* Using SESSION, fetch the properties specified by WHICH_PROPS using CONN
971 for URL at REVISION. The resulting properties are placed into a 2-level
972 hash in RESULTS, mapping NAMESPACE -> hash<PROPNAME, PROPVALUE>, which
973 is allocated in RESULT_POOL.
975 If REVISION is SVN_INVALID_REVNUM, then the properties are fetched
978 This function performs the request synchronously.
980 Temporary allocations are made in SCRATCH_POOL. */
982 svn_ra_serf__fetch_node_props(apr_hash_t **results,
983 svn_ra_serf__session_t *session,
985 svn_revnum_t revision,
986 const svn_ra_serf__dav_props_t *which_props,
987 apr_pool_t *result_pool,
988 apr_pool_t *scratch_pool);
991 /* Using SESSION, fetch a DAV: property from the resource identified by URL
992 within REVISION. The PROPNAME may be one of:
997 The resulting value will be allocated in RESULT_POOL, and may be NULL
998 if the property does not exist (note: "href" always exists).
1000 This function performs the request synchronously.
1002 Temporary allocations are made in SCRATCH_POOL. */
1004 svn_ra_serf__fetch_dav_prop(const char **value,
1005 svn_ra_serf__session_t *session,
1007 svn_revnum_t revision,
1008 const char *propname,
1009 apr_pool_t *result_pool,
1010 apr_pool_t *scratch_pool);
1012 /* Map a property name, as passed over the wire, into its corresponding
1013 Subversion-internal name. The returned name will be a static value,
1014 or allocated within RESULT_POOL.
1016 If the property should be ignored (eg. some DAV properties), then NULL
1017 will be returned. */
1019 svn_ra_serf__svnname_from_wirename(const char *ns,
1021 apr_pool_t *result_pool);
1023 /** MERGE-related functions **/
1026 svn_ra_serf__merge_lock_token_list(apr_hash_t *lock_tokens,
1028 serf_bucket_t *body,
1029 serf_bucket_alloc_t *alloc,
1032 /* Create an MERGE request aimed at the SESSION url, requesting the
1033 merge of the resource identified by MERGE_RESOURCE_URL.
1034 LOCK_TOKENS is a hash mapping paths to lock tokens owned by the
1035 client. If KEEP_LOCKS is set, instruct the server to not release
1036 locks set on the paths included in this commit. */
1038 svn_ra_serf__run_merge(const svn_commit_info_t **commit_info,
1039 svn_ra_serf__session_t *session,
1040 const char *merge_resource_url,
1041 apr_hash_t *lock_tokens,
1042 svn_boolean_t keep_locks,
1043 apr_pool_t *result_pool,
1044 apr_pool_t *scratch_pool);
1047 /** OPTIONS-related functions **/
1049 /* When running with a proxy, we may need to detect and correct for problems.
1050 This probing function will send a simple OPTIONS request to detect problems
1051 with the connection. */
1053 svn_ra_serf__probe_proxy(svn_ra_serf__session_t *serf_sess,
1054 apr_pool_t *scratch_pool);
1057 /* On HTTPv2 connections, run an OPTIONS request over CONN to fetch the
1058 current youngest revnum, returning it in *YOUNGEST.
1060 (the revnum is headers of the OPTIONS response)
1062 This function performs the request synchronously.
1064 All temporary allocations will be made in SCRATCH_POOL. */
1066 svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest,
1067 svn_ra_serf__session_t *session,
1068 apr_pool_t *scratch_pool);
1071 /* On HTTPv1 connections, run an OPTIONS request over CONN to fetch the
1072 activity collection set and return it in *ACTIVITY_URL, allocated
1075 (the activity-collection-set is in the body of the OPTIONS response)
1077 This function performs the request synchronously.
1079 All temporary allocations will be made in SCRATCH_POOL. */
1081 svn_ra_serf__v1_get_activity_collection(const char **activity_url,
1082 svn_ra_serf__session_t *session,
1083 apr_pool_t *result_pool,
1084 apr_pool_t *scratch_pool);
1087 /* Set @a VCC_URL to the default VCC for our repository based on @a
1088 * ORIG_PATH for the session @a SESSION, ensuring that the VCC URL and
1089 * repository root URLs are cached in @a SESSION.
1091 * All temporary allocations will be made in @a SCRATCH_POOL. */
1093 svn_ra_serf__discover_vcc(const char **vcc_url,
1094 svn_ra_serf__session_t *session,
1095 apr_pool_t *scratch_pool);
1097 /* Set @a REPORT_TARGET to the URI of the resource at which generic
1098 * (path-agnostic) REPORTs should be aimed for @a SESSION.
1100 * All temporary allocations will be made in @a POOL.
1103 svn_ra_serf__report_resource(const char **report_target,
1104 svn_ra_serf__session_t *session,
1107 /* Set @a REL_PATH to a path (not URI-encoded) relative to the root of
1108 * the repository pointed to by @a SESSION, based on original path
1109 * (URI-encoded) @a ORIG_PATH. Use @a CONN for any required network
1110 * communications if it is non-NULL; otherwise use the default
1111 * connection. Use POOL for allocations. */
1113 svn_ra_serf__get_relative_path(const char **rel_path,
1114 const char *orig_path,
1115 svn_ra_serf__session_t *session,
1119 /* Using the default connection in SESSION (conns[0]), get the youngest
1120 revnum from the server, returning it in *YOUNGEST.
1122 This function operates synchronously.
1124 All temporary allocations are performed in SCRATCH_POOL. */
1126 svn_ra_serf__get_youngest_revnum(svn_revnum_t *youngest,
1127 svn_ra_serf__session_t *session,
1128 apr_pool_t *scratch_pool);
1131 /* Generate a revision-stable URL.
1133 The RA APIs all refer to user/public URLs that float along with the
1134 youngest revision. In many cases, we do NOT want to work with that URL
1135 since it can change from one moment to the next. Especially if we
1136 attempt to operation against multiple floating URLs -- we could end up
1137 referring to two separate revisions.
1139 The DAV RA provider(s) solve this by generating a URL that is specific
1140 to a revision by using a URL into a "baseline collection".
1142 For a specified SESSION, generate a revision-stable URL for URL at
1143 REVISION. If REVISION is SVN_INVALID_REVNUM, then the stable URL will
1144 refer to the youngest revision at the time this function was called.
1146 If URL is NULL, then the session root will be used.
1148 The stable URL will be placed into *STABLE_URL, allocated from RESULT_POOL.
1150 If LATEST_REVNUM is not NULL, then the revision used will be placed into
1151 *LATEST_REVNUM. That will be equal to youngest, or the given REVISION.
1153 This function operates synchronously, if any communication to the server
1154 is required. Communication is needed if REVISION is SVN_INVALID_REVNUM
1155 (to get the current youngest revnum), or if the specified REVISION is not
1156 (yet) in our cache of baseline collections.
1158 All temporary allocations are performed in SCRATCH_POOL. */
1160 svn_ra_serf__get_stable_url(const char **stable_url,
1161 svn_revnum_t *latest_revnum,
1162 svn_ra_serf__session_t *session,
1164 svn_revnum_t revision,
1165 apr_pool_t *result_pool,
1166 apr_pool_t *scratch_pool);
1169 /** RA functions **/
1171 /* Implements svn_ra__vtable_t.reparent(). */
1173 svn_ra_serf__reparent(svn_ra_session_t *ra_session,
1177 /* Implements svn_ra__vtable_t.rev_prop(). */
1179 svn_ra_serf__rev_prop(svn_ra_session_t *session,
1182 svn_string_t **value,
1185 /* Implements svn_ra__vtable_t.get_log(). */
1187 svn_ra_serf__get_log(svn_ra_session_t *session,
1188 const apr_array_header_t *paths,
1192 svn_boolean_t discover_changed_paths,
1193 svn_boolean_t strict_node_history,
1194 svn_boolean_t include_merged_revisions,
1195 const apr_array_header_t *revprops,
1196 svn_log_entry_receiver_t receiver,
1197 void *receiver_baton,
1200 /* Implements svn_ra__vtable_t.check_path(). */
1202 svn_ra_serf__check_path(svn_ra_session_t *ra_session,
1203 const char *rel_path,
1204 svn_revnum_t revision,
1205 svn_node_kind_t *kind,
1208 /* Implements svn_ra__vtable_t.stat(). */
1210 svn_ra_serf__stat(svn_ra_session_t *ra_session,
1211 const char *rel_path,
1212 svn_revnum_t revision,
1213 svn_dirent_t **dirent,
1216 /* Implements svn_ra__vtable_t.get_locations(). */
1218 svn_ra_serf__get_locations(svn_ra_session_t *session,
1219 apr_hash_t **locations,
1221 svn_revnum_t peg_revision,
1222 const apr_array_header_t *location_revisions,
1225 /* Implements svn_ra__vtable_t.get_location_segments(). */
1227 svn_ra_serf__get_location_segments(svn_ra_session_t *session,
1229 svn_revnum_t peg_revision,
1230 svn_revnum_t start_rev,
1231 svn_revnum_t end_rev,
1232 svn_location_segment_receiver_t receiver,
1233 void *receiver_baton,
1236 /* Implements svn_ra__vtable_t.do_diff(). */
1238 svn_ra_serf__do_diff(svn_ra_session_t *session,
1239 const svn_ra_reporter3_t **reporter,
1240 void **report_baton,
1241 svn_revnum_t revision,
1242 const char *diff_target,
1244 svn_boolean_t ignore_ancestry,
1245 svn_boolean_t text_deltas,
1246 const char *versus_url,
1247 const svn_delta_editor_t *diff_editor,
1251 /* Implements svn_ra__vtable_t.do_status(). */
1253 svn_ra_serf__do_status(svn_ra_session_t *ra_session,
1254 const svn_ra_reporter3_t **reporter,
1255 void **report_baton,
1256 const char *status_target,
1257 svn_revnum_t revision,
1259 const svn_delta_editor_t *status_editor,
1263 /* Implements svn_ra__vtable_t.do_update(). */
1265 svn_ra_serf__do_update(svn_ra_session_t *ra_session,
1266 const svn_ra_reporter3_t **reporter,
1267 void **report_baton,
1268 svn_revnum_t revision_to_update_to,
1269 const char *update_target,
1271 svn_boolean_t send_copyfrom_args,
1272 svn_boolean_t ignore_ancestry,
1273 const svn_delta_editor_t *update_editor,
1275 apr_pool_t *result_pool,
1276 apr_pool_t *scratch_pool);
1278 /* Implements svn_ra__vtable_t.do_switch(). */
1280 svn_ra_serf__do_switch(svn_ra_session_t *ra_session,
1281 const svn_ra_reporter3_t **reporter,
1282 void **report_baton,
1283 svn_revnum_t revision_to_switch_to,
1284 const char *switch_target,
1286 const char *switch_url,
1287 svn_boolean_t send_copyfrom_args,
1288 svn_boolean_t ignore_ancestry,
1289 const svn_delta_editor_t *switch_editor,
1291 apr_pool_t *result_pool,
1292 apr_pool_t *scratch_pool);
1294 /* Implements svn_ra__vtable_t.get_file_revs(). */
1296 svn_ra_serf__get_file_revs(svn_ra_session_t *session,
1300 svn_boolean_t include_merged_revisions,
1301 svn_file_rev_handler_t handler,
1302 void *handler_baton,
1305 /* Implements svn_ra__vtable_t.get_dated_revision(). */
1307 svn_ra_serf__get_dated_revision(svn_ra_session_t *session,
1308 svn_revnum_t *revision,
1312 /* Implements svn_ra__vtable_t.get_commit_editor().
1314 * Note: Like other commit editors, the returned editor requires that the
1315 * @c copyfrom_path parameter passed to its @c add_file and @c add_directory
1316 * methods is a URL, not a relative path.
1319 svn_ra_serf__get_commit_editor(svn_ra_session_t *session,
1320 const svn_delta_editor_t **editor,
1322 apr_hash_t *revprop_table,
1323 svn_commit_callback2_t callback,
1324 void *callback_baton,
1325 apr_hash_t *lock_tokens,
1326 svn_boolean_t keep_locks,
1329 /* Implements svn_ra__vtable_t.get_file(). */
1331 svn_ra_serf__get_file(svn_ra_session_t *session,
1333 svn_revnum_t revision,
1334 svn_stream_t *stream,
1335 svn_revnum_t *fetched_rev,
1339 /* Implements svn_ra__vtable_t.get_dir(). */
1341 svn_ra_serf__get_dir(svn_ra_session_t *ra_session,
1342 apr_hash_t **dirents,
1343 svn_revnum_t *fetched_rev,
1344 apr_hash_t **ret_props,
1345 const char *rel_path,
1346 svn_revnum_t revision,
1347 apr_uint32_t dirent_fields,
1348 apr_pool_t *result_pool);
1350 /* Implements svn_ra__vtable_t.change_rev_prop(). */
1352 svn_ra_serf__change_rev_prop(svn_ra_session_t *session,
1355 const svn_string_t *const *old_value_p,
1356 const svn_string_t *value,
1359 /* Implements svn_ra__vtable_t.replay(). */
1361 svn_ra_serf__replay(svn_ra_session_t *ra_session,
1362 svn_revnum_t revision,
1363 svn_revnum_t low_water_mark,
1364 svn_boolean_t text_deltas,
1365 const svn_delta_editor_t *editor,
1369 /* Implements svn_ra__vtable_t.replay_range(). */
1371 svn_ra_serf__replay_range(svn_ra_session_t *ra_session,
1372 svn_revnum_t start_revision,
1373 svn_revnum_t end_revision,
1374 svn_revnum_t low_water_mark,
1375 svn_boolean_t send_deltas,
1376 svn_ra_replay_revstart_callback_t revstart_func,
1377 svn_ra_replay_revfinish_callback_t revfinish_func,
1381 /* Implements svn_ra__vtable_t.lock(). */
1383 svn_ra_serf__lock(svn_ra_session_t *ra_session,
1384 apr_hash_t *path_revs,
1385 const char *comment,
1386 svn_boolean_t force,
1387 svn_ra_lock_callback_t lock_func,
1391 /* Implements svn_ra__vtable_t.unlock(). */
1393 svn_ra_serf__unlock(svn_ra_session_t *ra_session,
1394 apr_hash_t *path_tokens,
1395 svn_boolean_t force,
1396 svn_ra_lock_callback_t lock_func,
1400 /* Implements svn_ra__vtable_t.get_lock(). */
1402 svn_ra_serf__get_lock(svn_ra_session_t *ra_session,
1407 /* Implements svn_ra__vtable_t.get_locks(). */
1409 svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
1415 /* Request a mergeinfo-report from the URL attached to SESSION,
1416 and fill in the MERGEINFO hash with the results.
1418 Implements svn_ra__vtable_t.get_mergeinfo().
1421 svn_ra_serf__get_mergeinfo(svn_ra_session_t *ra_session,
1422 apr_hash_t **mergeinfo,
1423 const apr_array_header_t *paths,
1424 svn_revnum_t revision,
1425 svn_mergeinfo_inheritance_t inherit,
1426 svn_boolean_t include_descendants,
1429 /* Exchange capabilities with the server, by sending an OPTIONS
1430 * request announcing the client's capabilities, and by filling
1431 * SERF_SESS->capabilities with the server's capabilities as read from
1432 * the response headers. Use POOL only for temporary allocation.
1434 * If the CORRECTED_URL is non-NULL, allow the OPTIONS response to
1435 * report a server-dictated redirect or relocation (HTTP 301 or 302
1436 * error codes), setting *CORRECTED_URL to the value of the corrected
1437 * repository URL. Otherwise, such responses from the server will
1438 * generate an error. (In either case, no capabilities are exchanged
1439 * if there is, in fact, such a response from the server.)
1442 svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess,
1443 const char **corrected_url,
1444 apr_pool_t *result_pool,
1445 apr_pool_t *scratch_pool);
1447 /* Implements svn_ra__vtable_t.has_capability(). */
1449 svn_ra_serf__has_capability(svn_ra_session_t *ra_session,
1451 const char *capability,
1454 /* Implements svn_ra__vtable_t.get_deleted_rev(). */
1456 svn_ra_serf__get_deleted_rev(svn_ra_session_t *session,
1458 svn_revnum_t peg_revision,
1459 svn_revnum_t end_revision,
1460 svn_revnum_t *revision_deleted,
1463 /* Implements the get_inherited_props RA layer function. */
1464 svn_error_t * svn_ra_serf__get_inherited_props(svn_ra_session_t *session,
1465 apr_array_header_t **iprops,
1467 svn_revnum_t revision,
1468 apr_pool_t *result_pool,
1469 apr_pool_t *scratch_pool);
1471 /* Implements svn_ra__vtable_t.get_repos_root(). */
1473 svn_ra_serf__get_repos_root(svn_ra_session_t *ra_session,
1477 /* Implements svn_ra__vtable_t.register_editor_shim_callbacks(). */
1479 svn_ra_serf__register_editor_shim_callbacks(svn_ra_session_t *session,
1480 svn_delta_shim_callbacks_t *callbacks);
1482 /*** Authentication handler declarations ***/
1485 * Callback function that loads the credentials for Basic and Digest
1486 * authentications, both for server and proxy authentication.
1489 svn_ra_serf__credentials_callback(char **username, char **password,
1490 serf_request_t *request, void *baton,
1491 int code, const char *authn_type,
1496 /*** General utility functions ***/
1499 * Convert an HTTP STATUS_CODE resulting from a WebDAV request against
1500 * PATH to the relevant error code. Use the response-supplied LOCATION
1501 * where it necessary.
1503 * Returns SVN_NO_ERROR if sline doesn't specify an error condition
1506 svn_ra_serf__error_on_status(serf_status_line sline,
1508 const char *location);
1511 * Convert an unexpected HTTP STATUS_CODE from a request to the relevant error
1512 * code. Unlike svn_ra_serf__error_on_status() this function creates an error
1516 svn_ra_serf__unexpected_status(svn_ra_serf__handler_t *handler);
1521 svn_ra_serf__copy_into_spillbuf(svn_spillbuf_t **spillbuf,
1523 apr_pool_t *result_pool,
1524 apr_pool_t *scratch_pool);
1528 svn_ra_serf__create_sb_bucket(svn_spillbuf_t *spillbuf,
1529 serf_bucket_alloc_t *allocator,
1530 apr_pool_t *result_pool,
1531 apr_pool_t *scratch_pool);
1533 /** Wrap STATUS from an serf function. If STATUS is not serf error code,
1534 * this is equivalent to svn_error_wrap_apr().
1537 svn_ra_serf__wrap_err(apr_status_t status,
1541 /* Create a bucket that just returns DATA (with length LEN) and then returns
1542 the APR_EAGAIN status */
1544 svn_ra_serf__create_bucket_with_eagain(const char *data,
1546 serf_bucket_alloc_t *allocator);
1548 /* Parse a given URL_STR, fill in all supplied fields of URI
1551 * This function is a compatibility wrapper around apr_uri_parse().
1552 * Different apr-util versions set apr_uri_t.path to either NULL or ""
1553 * for root paths, and serf expects to see "/". This function always
1554 * sets URI.path to "/" for these paths. */
1556 svn_ra_serf__uri_parse(apr_uri_t *uri,
1557 const char *url_str,
1558 apr_pool_t *result_pool);
1561 #if defined(SVN_DEBUG)
1562 /* Wrapper macros to collect file and line information */
1563 #define svn_ra_serf__wrap_err \
1564 (svn_error__locate(__FILE__,__LINE__), (svn_ra_serf__wrap_err))
1570 #endif /* __cplusplus */
1572 #endif /* SVN_LIBSVN_RA_SERF_RA_SERF_H */