You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gs...@apache.org on 2012/05/12 08:55:29 UTC

svn commit: r1337455 - in /subversion/trunk/subversion/libsvn_ra_serf: ra_serf.h util.c

Author: gstein
Date: Sat May 12 06:55:29 2012
New Revision: 1337455

URL: http://svn.apache.org/viewvc?rev=1337455&view=rev
Log:
Write a response handler to pass the body to an Expat parser, and
onwards to the v2 XML processing code.

* subversion/libsvn_ra_serf/ra_serf.h:
  (svn_ra_serf__create_expat_handler): returns a new handler that
    parses the body using Expat, passing info to and xml context.

* subversion/libsvn_ra_serf/util.c:
  (struct expat_ctx_t): new context for parsing response bodies
  (expat_start, expat_end, expat_cdata): new Expat callbacks to pass
    the parse data over to an xml context.
  (expat_response_handler): a new response handler to feed a response
    body into an Expat parser
  (svn_ra_serf__create_expat_handler): new implementation to wire
    everything up

Modified:
    subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
    subversion/trunk/subversion/libsvn_ra_serf/util.c

Modified: subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h?rev=1337455&r1=1337454&r2=1337455&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h Sat May 12 06:55:29 2012
@@ -696,6 +696,16 @@ svn_ra_serf__xml_context_create(
   apr_pool_t *result_pool);
 
 
+/* Construct a handler with the response function/baton set up to parse
+   a response body using the given XML context. The handler and its
+   internal structures are allocated in RESULT_POOL.
+
+   This also initializes HANDLER_POOL to the given RESULT_POOL.  */
+svn_ra_serf__handler_t *
+svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+                                  apr_pool_t *result_pool);
+
+
 /* Allocated within XES->STATE_POOL. Changes are not allowd. Make a deep
    copy, as appropriate.
 

Modified: subversion/trunk/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/util.c?rev=1337455&r1=1337454&r2=1337455&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/util.c Sat May 12 06:55:29 2012
@@ -80,6 +80,19 @@ struct svn_ra_serf__pending_t {
                              && svn_spillbuf__get_size((p)->buf) != 0)
 
 
+struct expat_ctx_t {
+  svn_ra_serf__xml_context_t *xmlctx;
+  XML_Parser parser;
+  svn_ra_serf__handler_t *handler;
+
+  svn_error_t *inner_error;
+
+  /* Do not use this pool for allocation. It is merely recorded for running
+     the cleanup handler.  */
+  apr_pool_t *cleanup_pool;
+};
+
+
 static const apr_uint32_t serf_failure_map[][2] =
 {
   { SERF_SSL_CERT_NOTYETVALID,   SVN_AUTH_SSL_NOTYETVALID },
@@ -2247,3 +2260,150 @@ svn_ra_serf__register_editor_shim_callba
   session->shim_callbacks = callbacks;
   return SVN_NO_ERROR;
 }
+
+
+/* Conforms to Expat's XML_StartElementHandler  */
+static void
+expat_start(void *userData, const char *raw_name, const char **attrs)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_start(ectx->xmlctx,
+                                                  raw_name, attrs));
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+}
+
+
+/* Conforms to Expat's XML_EndElementHandler  */
+static void
+expat_end(void *userData, const char *raw_name)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_end(ectx->xmlctx, raw_name));
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+}
+
+
+/* Conforms to Expat's XML_CharacterDataHandler  */
+static void
+expat_cdata(void *userData, const char *data, int len)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_cdata(ectx->xmlctx, data, len));
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+}
+
+
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+expat_response_handler(serf_request_t *request,
+                       serf_bucket_t *response,
+                       void *baton,
+                       apr_pool_t *pool)
+{
+  struct expat_ctx_t *ectx = baton;
+
+  SVN_ERR_ASSERT(ectx->parser != NULL);
+
+  while (1)
+    {
+      apr_status_t status;
+      const char *data;
+      apr_size_t len;
+      int expat_status;
+
+      status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
+      if (SERF_BUCKET_READ_ERROR(status))
+        return svn_error_wrap_apr(status, NULL);
+
+#if 0
+      /* ### move restart/skip into the core handler  */
+      ectx->handler->read_size += len;
+#endif
+
+      /* ### move PAUSED behavior to a new response handler that can feed
+         ### an inner handler, or can pause for a while.  */
+
+      /* ### should we have an IGNORE_ERRORS flag like the v1 parser?  */
+
+      expat_status = XML_Parse(ectx->parser, data, (int)len, 0 /* isFinal */);
+      if (expat_status == XML_STATUS_ERROR)
+        return svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
+                                 _("The %s response contains invalid XML"
+                                   " (%d %s)"),
+                                 ectx->handler->method,
+                                 ectx->handler->sline.code,
+                                 ectx->handler->sline.reason);
+
+      /* Was an error dropped off for us?  */
+      if (ectx->inner_error)
+        {
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+          return svn_error_trace(ectx->inner_error);
+        }
+
+      /* The parsing went fine. What has the bucket told us?  */
+
+      if (APR_STATUS_IS_EAGAIN(status))
+        return svn_error_wrap_apr(status, NULL);
+
+      if (APR_STATUS_IS_EOF(status))
+        {
+          /* Tell expat we've reached the end of the content. Ignore the
+             return status. We just don't care.  */
+          (void) XML_Parse(ectx->parser, NULL, 0, 1 /* isFinal */);
+
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+          return svn_error_wrap_apr(status, NULL);
+        }
+    }
+
+  /* NOTREACHED */
+}
+
+
+svn_ra_serf__handler_t *
+svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+                                  apr_pool_t *result_pool)
+{
+  svn_ra_serf__handler_t *handler;
+  struct expat_ctx_t *ectx;
+
+  ectx = apr_pcalloc(result_pool, sizeof(*ectx));
+  ectx->xmlctx = xmlctx;
+  ectx->parser = XML_ParserCreate(NULL);
+  apr_pool_cleanup_register(result_pool, &ectx->parser,
+                            xml_parser_cleanup, apr_pool_cleanup_null);
+  XML_SetUserData(ectx->parser, ectx);
+  XML_SetElementHandler(ectx->parser, expat_start, expat_end);
+  XML_SetCharacterDataHandler(ectx->parser, expat_cdata);
+
+
+  handler = apr_pcalloc(result_pool, sizeof(*handler));
+  handler->handler_pool = result_pool;
+  handler->response_handler = expat_response_handler;
+  handler->response_baton = ectx;
+
+  ectx->handler = handler;
+
+  return handler;
+}