Author: rhs
Date: Mon May 13 13:00:04 2013
New Revision: 1481834

URL: http://svn.apache.org/r1481834
Log:
PROTON-299: added address rewrite API to control what goes into the to field on 
the wire, added default rewrite rules to remove credentials from URLs

Added:
    qpid/proton/trunk/proton-c/src/messenger/transform.c
    qpid/proton/trunk/proton-c/src/messenger/transform.h
Modified:
    qpid/proton/trunk/proton-c/CMakeLists.txt
    qpid/proton/trunk/proton-c/bindings/python/proton.py
    qpid/proton/trunk/proton-c/include/proton/messenger.h
    qpid/proton/trunk/proton-c/include/proton/object.h
    qpid/proton/trunk/proton-c/src/messenger/messenger.c
    qpid/proton/trunk/proton-c/src/object/object.c
    qpid/proton/trunk/proton-c/src/tests/object.c
    qpid/proton/trunk/proton-j/proton-api/src/main/resources/proton.py
    qpid/proton/trunk/tests/python/proton_tests/message.py
    qpid/proton/trunk/tests/python/proton_tests/messenger.py

Modified: qpid/proton/trunk/proton-c/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/CMakeLists.txt?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/CMakeLists.txt (original)
+++ qpid/proton/trunk/proton-c/CMakeLists.txt Mon May 13 13:00:04 2013
@@ -246,6 +246,7 @@ set (qpid-proton-core
 
   src/messenger/messenger.c
   src/messenger/store.c
+  src/messenger/transform.c
 
   ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
   ${CMAKE_CURRENT_BINARY_DIR}/protocol.h

Modified: qpid/proton/trunk/proton-c/bindings/python/proton.py
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/bindings/python/proton.py?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/bindings/python/proton.py (original)
+++ qpid/proton/trunk/proton-c/bindings/python/proton.py Mon May 13 13:00:04 
2013
@@ -492,6 +492,9 @@ send. Defaults to zero.
   def route(self, pattern, address):
     self._check(pn_messenger_route(self._mng, pattern, address))
 
+  def rewrite(self, pattern, address):
+    self._check(pn_messenger_rewrite(self._mng, pattern, address))
+
 class Message(object):
   """
   The L{Message} class is a mutable holder of message content.
@@ -549,9 +552,8 @@ class Message(object):
     props.clear()
     if self.properties is not None:
       props.put_object(self.properties)
+    body.clear()
     if self.body is not None:
-      # XXX: move this out when load/save are gone
-      body.clear()
       body.put_object(self.body)
 
   def _post_decode(self):

Modified: qpid/proton/trunk/proton-c/include/proton/messenger.h
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/include/proton/messenger.h?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/include/proton/messenger.h (original)
+++ qpid/proton/trunk/proton-c/include/proton/messenger.h Mon May 13 13:00:04 
2013
@@ -452,6 +452,9 @@ PN_EXTERN int pn_messenger_incoming(pn_m
 PN_EXTERN int pn_messenger_route(pn_messenger_t *messenger, const char 
*pattern,
                                  const char *address);
 
+PN_EXTERN int pn_messenger_rewrite(pn_messenger_t *messenger, const char 
*pattern,
+                                   const char *address);
+
 #ifdef __cplusplus
 }
 #endif

Modified: qpid/proton/trunk/proton-c/include/proton/object.h
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/include/proton/object.h?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/include/proton/object.h (original)
+++ qpid/proton/trunk/proton-c/include/proton/object.h Mon May 13 13:00:04 2013
@@ -25,6 +25,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <sys/types.h>
 
 #include <proton/import_export.h>
 
@@ -86,7 +87,15 @@ PN_EXTERN const char *pn_string_get(pn_s
 PN_EXTERN size_t pn_string_size(pn_string_t *string);
 PN_EXTERN int pn_string_set(pn_string_t *string, const char *bytes);
 PN_EXTERN int pn_string_setn(pn_string_t *string, const char *bytes, size_t n);
+PN_EXTERN ssize_t pn_string_put(pn_string_t *string, char *dst);
 PN_EXTERN void pn_string_clear(pn_string_t *string);
+PN_EXTERN int pn_string_format(pn_string_t *string, const char *format, ...)
+  __attribute__ ((format (printf, 2, 3)));
+PN_EXTERN char *pn_string_buffer(pn_string_t *string);
+PN_EXTERN size_t pn_string_capacity(pn_string_t *string);
+PN_EXTERN int pn_string_resize(pn_string_t *string, size_t size);
+PN_EXTERN int pn_string_copy(pn_string_t *string, pn_string_t *src);
+
 
 #ifdef __cplusplus
 }

Modified: qpid/proton/trunk/proton-c/src/messenger/messenger.c
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/messenger/messenger.c?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/src/messenger/messenger.c (original)
+++ qpid/proton/trunk/proton-c/src/messenger/messenger.c Mon May 13 13:00:04 
2013
@@ -23,6 +23,7 @@
 #include <proton/driver.h>
 #include <proton/util.h>
 #include <proton/ssl.h>
+#include <proton/object.h>
 #include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
@@ -32,23 +33,10 @@
 #include "../platform.h"
 #include "../platform_fmt.h"
 #include "store.h"
+#include "transform.h"
 
 typedef struct {
-  const char *start;
-  size_t size;
-} pn_group_t;
-
-#define MAX_GROUP (64)
-
-typedef struct {
-  size_t groups;
-  pn_group_t group[MAX_GROUP];
-} pn_matcher_t;
-
-#define PN_MAX_ADDR (1024)
-
-typedef struct {
-  char text[PN_MAX_ADDR + 1];
+  pn_string_t *text;
   bool passive;
   char *scheme;
   char *user;
@@ -58,18 +46,6 @@ typedef struct {
   char *name;
 } pn_address_t;
 
-typedef struct pn_route_t pn_route_t;
-
-#define PN_MAX_PATTERN (255)
-#define PN_MAX_ROUTE (255)
-
-struct pn_route_t {
-  char pattern[PN_MAX_PATTERN + 1];
-  char address[PN_MAX_ROUTE + 1];
-  pn_route_t *next;
-};
-
-
 struct pn_messenger_t {
   char *name;
   char *certificate;
@@ -90,11 +66,13 @@ struct pn_messenger_t {
   size_t sub_count;
   pn_subscription_t *incoming_subscription;
   pn_error_t *error;
-  pn_route_t *routes;
-  pn_matcher_t matcher;
+  pn_transform_t *routes;
+  pn_transform_t *rewrites;
   pn_address_t address;
   pn_tracker_t outgoing_tracker;
   pn_tracker_t incoming_tracker;
+  pn_string_t *original;
+  pn_string_t *rewritten;
 };
 
 struct pn_subscription_t {
@@ -217,9 +195,13 @@ pn_messenger_t *pn_messenger(const char 
     m->sub_count = 0;
     m->incoming_subscription = NULL;
     m->error = pn_error();
-    m->routes = NULL;
+    m->routes = pn_transform();
+    m->rewrites = pn_transform();
     m->outgoing_tracker = 0;
     m->incoming_tracker = 0;
+    m->address.text = pn_string(NULL);
+    m->original = pn_string(NULL);
+    m->rewritten = pn_string(NULL);
   }
 
   return m;
@@ -302,6 +284,9 @@ static void pni_driver_reclaim(pn_driver
 void pn_messenger_free(pn_messenger_t *messenger)
 {
   if (messenger) {
+    pn_free(messenger->rewritten);
+    pn_free(messenger->original);
+    pn_free(messenger->address.text);
     free(messenger->name);
     free(messenger->certificate);
     free(messenger->private_key);
@@ -316,12 +301,8 @@ void pn_messenger_free(pn_messenger_t *m
       free(messenger->subscriptions[i].scheme);
     }
     free(messenger->subscriptions);
-    pn_route_t *route = messenger->routes;
-    while (route) {
-      pn_route_t *next = route->next;
-      free(route);
-      route = next;
-    }
+    pn_free(messenger->rewrites);
+    pn_free(messenger->routes);
     free(messenger);
   }
 }
@@ -750,111 +731,6 @@ static const char *default_port(const ch
     return "5672";
 }
 
-static void pni_sub(pn_matcher_t *matcher, size_t group, const char *text, 
size_t matched)
-{
-  if (group > matcher->groups) {
-    matcher->groups = group;
-  }
-  matcher->group[group].start = text - matched;
-  matcher->group[group].size = matched;
-}
-
-static bool pni_match_r(pn_matcher_t *matcher, const char *pattern, const char 
*text, size_t group, size_t matched)
-{
-  bool match;
-
-  char p = *pattern;
-  char c = *text;
-
-  switch (p) {
-  case '\0': return c == '\0';
-  case '%':
-  case '*':
-    switch (c) {
-    case '\0':
-      match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
-      if (match) pni_sub(matcher, group, text, matched);
-      return match;
-    case '/':
-      if (p == '%') {
-        match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
-        if (match) pni_sub(matcher, group, text, matched);
-        return match;
-      }
-    default:
-      match = pni_match_r(matcher, pattern, text + 1, group, matched + 1);
-      if (!match) {
-        match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
-        if (match) pni_sub(matcher, group, text, matched);
-      }
-      return match;
-    }
-  default:
-    return c == p && pni_match_r(matcher, pattern + 1, text + 1, group, 0);
-  }
-}
-
-static bool pni_match(pn_matcher_t *matcher, const char *pattern, const char 
*text)
-{
-  matcher->groups = 0;
-  if (pni_match_r(matcher, pattern, text, 1, 0)) {
-    matcher->group[0].start = text;
-    matcher->group[0].size = strlen(text);
-    return true;
-  } else {
-    matcher->groups = 0;
-    return false;
-  }
-}
-
-static size_t pni_substitute(pn_matcher_t *matcher, const char *pattern, char 
*dest, size_t limit)
-{
-  size_t result = 0;
-
-  while (*pattern) {
-    switch (*pattern) {
-    case '$':
-      pattern++;
-      if (*pattern == '$') {
-        if (result < limit) {
-          *dest++ = *pattern++;
-        }
-        result++;
-      } else {
-        size_t idx = 0;
-        while (isdigit(*pattern)) {
-          idx *= 10;
-          idx += *pattern++ - '0';
-        }
-
-        if (idx <= matcher->groups) {
-          pn_group_t *group = &matcher->group[idx];
-          for (size_t i = 0; i < group->size; i++) {
-            if (result < limit) {
-              *dest++ = group->start[i];
-            }
-            result++;
-          }
-        }
-      }
-      break;
-    default:
-      if (result < limit) {
-        *dest++ = *pattern++;
-      }
-      result++;
-      break;
-    }
-  }
-
-  if (result < limit) {
-    *dest = '\0';
-  }
-  result++;
-
-  return result;
-}
-
 static void pni_parse(pn_address_t *address)
 {
   address->passive = false;
@@ -864,8 +740,8 @@ static void pni_parse(pn_address_t *addr
   address->host = NULL;
   address->port = NULL;
   address->name = NULL;
-  parse_url(address->text, &address->scheme, &address->user, &address->pass,
-            &address->host, &address->port, &address->name);
+  parse_url(pn_string_buffer(address->text), &address->scheme, &address->user,
+            &address->pass, &address->host, &address->port, &address->name);
   if (address->host[0] == '~') {
     address->passive = true;
     address->host++;
@@ -875,23 +751,9 @@ static void pni_parse(pn_address_t *addr
 static int pni_route(pn_messenger_t *messenger, const char *address)
 {
   pn_address_t *addr = &messenger->address;
-  pn_route_t *route = messenger->routes;
-  while (route) {
-    if (pni_match(&messenger->matcher, route->pattern, address)) {
-      size_t n = pni_substitute(&messenger->matcher, route->address, 
addr->text, PN_MAX_ADDR);
-      if (n < PN_MAX_ADDR) {
-        pni_parse(addr);
-        return 0;
-      } else {
-        return pn_error_format(messenger->error, PN_ERR,
-                               "routing address exceeded maximum length: (%s 
-> %s)",
-                               route->pattern, route->address);
-      }
-    }
-    route = route->next;
-  }
-
-  strcpy(addr->text, address);
+  int err = pn_transform_apply(messenger->routes, address, addr->text);
+  if (err) return pn_error_format(messenger->error, PN_ERR,
+                                  "transformation error");
   pni_parse(addr);
   return 0;
 }
@@ -1171,6 +1033,48 @@ int pni_pump_out(pn_messenger_t *messeng
   }
 }
 
+static void pni_default_rewrite(pn_messenger_t *messenger, const char *address,
+                                pn_string_t *dst)
+{
+  pn_address_t *addr = &messenger->address;
+  if (address && strstr(address, "@")) {
+    int err = pn_string_set(addr->text, address);
+    assert(!err);
+    pni_parse(addr);
+    if (addr->user || addr->pass)
+    {
+      pn_string_format(messenger->rewritten, "%s%s%s%s%s%s%s",
+                       addr->scheme ? addr->scheme : "",
+                       addr->scheme ? "://" : "",
+                       addr->host,
+                       addr->port ? ":" : "",
+                       addr->port ? addr->port : "",
+                       addr->name ? "/" : "",
+                       addr->name ? addr->name : "");
+    }
+  }
+}
+
+static void pni_rewrite(pn_messenger_t *messenger, pn_message_t *msg)
+{
+  const char *address = pn_message_get_address(msg);
+  pn_string_set(messenger->original, address);
+
+  int err = pn_transform_apply(messenger->rewrites, address,
+                               messenger->rewritten);
+  assert(!err);
+  if (!pn_transform_matched(messenger->rewrites)) {
+    pni_default_rewrite(messenger, pn_string_get(messenger->rewritten),
+                        messenger->rewritten);
+  }
+  pn_message_set_address(msg, pn_string_get(messenger->rewritten));
+}
+
+static void pni_restore(pn_messenger_t *messenger, pn_message_t *msg)
+{
+  pn_message_set_address(msg, pn_string_get(messenger->original));
+}
+
 int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg)
 {
   if (!messenger) return PN_ARG_ERR;
@@ -1185,6 +1089,7 @@ int pn_messenger_put(pn_messenger_t *mes
   messenger->outgoing_tracker = pn_tracker(OUTGOING, pni_entry_track(entry));
   pn_buffer_t *buf = pni_entry_bytes(entry);
 
+  pni_rewrite(messenger, msg);
   while (true) {
     char *encoded = pn_buffer_bytes(buf).start;
     size_t size = pn_buffer_capacity(buf);
@@ -1193,12 +1098,15 @@ int pn_messenger_put(pn_messenger_t *mes
       err = pn_buffer_ensure(buf, 2*pn_buffer_capacity(buf));
       if (err) {
         pni_entry_free(entry);
+        pni_restore(messenger, msg);
         return pn_error_format(messenger->error, err, "put: error growing 
buffer");
       }
     } else if (err) {
+      pni_restore(messenger, msg);
       return pn_error_format(messenger->error, err, "encode error: %s",
                              pn_message_error(msg));
     } else {
+      pni_restore(messenger, msg);
       pn_buffer_append(buf, encoded, size); // XXX
       pn_link_t *sender = pn_messenger_target(messenger, address);
       if (!sender) return 0;
@@ -1442,25 +1350,12 @@ int pn_messenger_incoming(pn_messenger_t
 
 int pn_messenger_route(pn_messenger_t *messenger, const char *pattern, const 
char *address)
 {
-  if (strlen(pattern) > PN_MAX_PATTERN || strlen(address) > PN_MAX_ROUTE) {
-    return PN_ERR;
-  }
-  pn_route_t *route = (pn_route_t *) malloc(sizeof(pn_route_t));
-  if (!route) return PN_ERR;
-
-  strcpy(route->pattern, pattern);
-  strcpy(route->address, address);
-  route->next = NULL;
-
-  pn_route_t *tail = messenger->routes;
-  if (!tail) {
-    messenger->routes = route;
-  } else {
-    while (tail->next) {
-      tail = tail->next;
-    }
-    tail->next = route;
-  }
+  pn_transform_rule(messenger->routes, pattern, address);
+  return 0;
+}
 
+int pn_messenger_rewrite(pn_messenger_t *messenger, const char *pattern, const 
char *address)
+{
+  pn_transform_rule(messenger->rewrites, pattern, address);
   return 0;
 }

Added: qpid/proton/trunk/proton-c/src/messenger/transform.c
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/messenger/transform.c?rev=1481834&view=auto
==============================================================================
--- qpid/proton/trunk/proton-c/src/messenger/transform.c (added)
+++ qpid/proton/trunk/proton-c/src/messenger/transform.c Mon May 13 13:00:04 
2013
@@ -0,0 +1,230 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+#include <proton/object.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "transform.h"
+
+typedef struct {
+  const char *start;
+  size_t size;
+} pn_group_t;
+
+#define MAX_GROUP (64)
+
+typedef struct {
+  size_t groups;
+  pn_group_t group[MAX_GROUP];
+} pn_matcher_t;
+
+typedef struct {
+  pn_string_t *pattern;
+  pn_string_t *substitution;
+} pn_rule_t;
+
+struct pn_transform_t {
+  pn_list_t *rules;
+  pn_matcher_t matcher;
+  bool matched;
+};
+
+static void pn_rule_finalize(void *object)
+{
+  pn_rule_t *rule = (pn_rule_t *) object;
+  pn_free(rule->pattern);
+  pn_free(rule->substitution);
+}
+
+pn_rule_t *pn_rule(const char *pattern, const char *substitution)
+{
+  static pn_class_t clazz = {pn_rule_finalize};
+  pn_rule_t *rule = (pn_rule_t *) pn_new(sizeof(pn_rule_t), &clazz);
+  rule->pattern = pn_string(pattern);
+  rule->substitution = pn_string(substitution);
+  return rule;
+}
+
+static void pn_transform_finalize(void *object)
+{
+  pn_transform_t *transform = (pn_transform_t *) object;
+  pn_free(transform->rules);
+}
+
+pn_transform_t *pn_transform()
+{
+  static pn_class_t clazz = {pn_transform_finalize};
+  pn_transform_t *transform = (pn_transform_t *) 
pn_new(sizeof(pn_transform_t), &clazz);
+  transform->rules = pn_list(0, PN_REFCOUNT);
+  transform->matched = false;
+  return transform;
+}
+
+void pn_transform_rule(pn_transform_t *transform, const char *pattern,
+                       const char *substitution)
+{
+  assert(transform);
+  pn_rule_t *rule = pn_rule(pattern, substitution);
+  pn_list_add(transform->rules, rule);
+  pn_decref(rule);
+}
+
+static void pni_sub(pn_matcher_t *matcher, size_t group, const char *text, 
size_t matched)
+{
+  if (group > matcher->groups) {
+    matcher->groups = group;
+  }
+  matcher->group[group].start = text - matched;
+  matcher->group[group].size = matched;
+}
+
+static bool pni_match_r(pn_matcher_t *matcher, const char *pattern, const char 
*text, size_t group, size_t matched)
+{
+  bool match;
+
+  char p = *pattern;
+  char c = *text;
+
+  switch (p) {
+  case '\0': return c == '\0';
+  case '%':
+  case '*':
+    switch (c) {
+    case '\0':
+      match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
+      if (match) pni_sub(matcher, group, text, matched);
+      return match;
+    case '/':
+      if (p == '%') {
+        match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
+        if (match) pni_sub(matcher, group, text, matched);
+        return match;
+      }
+    default:
+      match = pni_match_r(matcher, pattern, text + 1, group, matched + 1);
+      if (!match) {
+        match = pni_match_r(matcher, pattern + 1, text, group + 1, 0);
+        if (match) pni_sub(matcher, group, text, matched);
+      }
+      return match;
+    }
+  default:
+    return c == p && pni_match_r(matcher, pattern + 1, text + 1, group, 0);
+  }
+}
+
+static bool pni_match(pn_matcher_t *matcher, const char *pattern, const char 
*text)
+{
+  matcher->groups = 0;
+  if (pni_match_r(matcher, pattern, text, 1, 0)) {
+    matcher->group[0].start = text;
+    matcher->group[0].size = strlen(text);
+    return true;
+  } else {
+    matcher->groups = 0;
+    return false;
+  }
+}
+
+static size_t pni_substitute(pn_matcher_t *matcher, const char *pattern, char 
*dest, size_t limit)
+{
+  size_t result = 0;
+
+  while (*pattern) {
+    switch (*pattern) {
+    case '$':
+      pattern++;
+      if (*pattern == '$') {
+        if (result < limit) {
+          *dest++ = *pattern;
+        }
+        pattern++;
+        result++;
+      } else {
+        size_t idx = 0;
+        while (isdigit(*pattern)) {
+          idx *= 10;
+          idx += *pattern++ - '0';
+        }
+
+        if (idx <= matcher->groups) {
+          pn_group_t *group = &matcher->group[idx];
+          for (size_t i = 0; i < group->size; i++) {
+            if (result < limit) {
+              *dest++ = group->start[i];
+            }
+            result++;
+          }
+        }
+      }
+      break;
+    default:
+      if (result < limit) {
+        *dest++ = *pattern;
+      }
+      pattern++;
+      result++;
+      break;
+    }
+  }
+
+  if (result < limit) {
+    *dest = '\0';
+  }
+
+  return result;
+}
+
+int pn_transform_apply(pn_transform_t *transform, const char *src,
+                       pn_string_t *dst)
+{
+  for (size_t i = 0; i < pn_list_size(transform->rules); i++)
+  {
+    pn_rule_t *rule = (pn_rule_t *) pn_list_get(transform->rules, i);
+    if (pni_match(&transform->matcher, pn_string_get(rule->pattern), src)) {
+      transform->matched = true;
+      if (!pn_string_get(rule->substitution)) {
+        return pn_string_set(dst, NULL);
+      }
+
+      while (true) {
+        size_t capacity = pn_string_capacity(dst);
+        size_t n = pni_substitute(&transform->matcher,
+                                  pn_string_get(rule->substitution),
+                                  pn_string_buffer(dst), capacity);
+        int err = pn_string_resize(dst, n);
+        if (err) return err;
+        if (n <= capacity) {
+          return 0;
+        }
+      }
+    }
+  }
+
+  transform->matched = false;
+  return pn_string_set(dst, src);
+}
+
+bool pn_transform_matched(pn_transform_t *transform)
+{
+  return transform->matched;
+}

Added: qpid/proton/trunk/proton-c/src/messenger/transform.h
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/messenger/transform.h?rev=1481834&view=auto
==============================================================================
--- qpid/proton/trunk/proton-c/src/messenger/transform.h (added)
+++ qpid/proton/trunk/proton-c/src/messenger/transform.h Mon May 13 13:00:04 
2013
@@ -0,0 +1,37 @@
+#ifndef _PROTON_TRANSFORM_H
+#define _PROTON_TRANSFORM_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+#include <proton/buffer.h>
+
+typedef struct pn_transform_t pn_transform_t;
+
+pn_transform_t *pn_transform();
+void pn_transform_rule(pn_transform_t *transform, const char *pattern,
+                       const char *substitution);
+int pn_transform_apply(pn_transform_t *transform, const char *src,
+                       pn_string_t *dest);
+bool pn_transform_matched(pn_transform_t *transform);
+
+
+#endif /* transform.h */

Modified: qpid/proton/trunk/proton-c/src/object/object.c
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/object/object.c?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/src/object/object.c (original)
+++ qpid/proton/trunk/proton-c/src/object/object.c Mon May 13 13:00:04 2013
@@ -21,7 +21,7 @@
 
 #include <proton/error.h>
 #include <proton/object.h>
-#include <sys/types.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -585,10 +585,10 @@ int pn_string_set(pn_string_t *string, c
   return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
 }
 
-int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+static int pn_string_grow(pn_string_t *string, size_t capacity)
 {
   bool grow = false;
-  while (string->capacity < (n*sizeof(char) + 1)) {
+  while (string->capacity < (capacity*sizeof(char) + 1)) {
     string->capacity *= 2;
     grow = true;
   }
@@ -602,6 +602,14 @@ int pn_string_setn(pn_string_t *string, 
     }
   }
 
+  return 0;
+}
+
+int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+{
+  int err = pn_string_grow(string, n);
+  if (err) return err;
+
   if (bytes) {
     memcpy(string->bytes, bytes, n*sizeof(char));
     string->bytes[n] = '\0';
@@ -613,7 +621,66 @@ int pn_string_setn(pn_string_t *string, 
   return 0;
 }
 
+ssize_t pn_string_put(pn_string_t *string, char *dst)
+{
+  assert(string);
+  assert(dst);
+
+  if (string->size != PNI_NULL_SIZE) {
+    memcpy(dst, string->bytes, string->size + 1);
+  }
+
+  return string->size;
+}
+
 void pn_string_clear(pn_string_t *string)
 {
   pn_string_set(string, NULL);
 }
+
+int pn_string_format(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  while (true) {
+    va_start(ap, format);
+    int err = vsnprintf(string->bytes, string->capacity, format, ap);
+    va_end(ap);
+    if (err < 0) {
+      return err;
+    } else if ((size_t) err >= string->capacity) {
+      pn_string_grow(string, err);
+    } else {
+      string->size = err;
+      return 0;
+    }
+  }
+}
+
+char *pn_string_buffer(pn_string_t *string)
+{
+  assert(string);
+  return string->bytes;
+}
+
+size_t pn_string_capacity(pn_string_t *string)
+{
+  assert(string);
+  return string->capacity - 1;
+}
+
+int pn_string_resize(pn_string_t *string, size_t size)
+{
+  assert(string);
+  int err = pn_string_grow(string, size);
+  if (err) return err;
+  string->size = size;
+  string->bytes[size] = '\0';
+  return 0;
+}
+
+int pn_string_copy(pn_string_t *string, pn_string_t *src)
+{
+  assert(string);
+  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+}

Modified: qpid/proton/trunk/proton-c/src/tests/object.c
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/tests/object.c?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/src/tests/object.c (original)
+++ qpid/proton/trunk/proton-c/src/tests/object.c Mon May 13 13:00:04 2013
@@ -383,6 +383,18 @@ static void test_stringn(const char *val
   pn_free(strsetn);
 }
 
+static void test_string_format()
+{
+  pn_string_t *str = pn_string("");
+  assert(str);
+  int err = pn_string_format(str, "%s", "this is a string that should be long "
+                             "enough to force growth but just in case we'll "
+                             "tack this other really long string on for the "
+                             "heck of it");
+  assert(err == 0);
+  pn_free(str);
+}
+
 int main(int argc, char **argv)
 {
   for (size_t i = 0; i < 128; i++) {
@@ -420,5 +432,7 @@ int main(int argc, char **argv)
   test_string("this has an embedded \000 in it");
   test_stringn("this has an embedded \000 in it", 28);
 
+  test_string_format();
+
   return 0;
 }

Modified: qpid/proton/trunk/proton-j/proton-api/src/main/resources/proton.py
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton-api/src/main/resources/proton.py?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/proton-j/proton-api/src/main/resources/proton.py 
(original)
+++ qpid/proton/trunk/proton-j/proton-api/src/main/resources/proton.py Mon May 
13 13:00:04 2013
@@ -1051,6 +1051,9 @@ class Messenger(object):
   def route(self, *args, **kwargs):
     raise Skipped()
 
+  def rewrite(self, *args, **kwargs):
+    raise Skipped()
+
   def start(self):
     self.impl.start()
 

Modified: qpid/proton/trunk/tests/python/proton_tests/message.py
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/message.py?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/tests/python/proton_tests/message.py (original)
+++ qpid/proton/trunk/tests/python/proton_tests/message.py Mon May 13 13:00:04 
2013
@@ -112,8 +112,7 @@ class CodecTest(Test):
     self.msg.priority = 100
     self.msg.address = "address"
     self.msg.subject = "subject"
-    body = 'Hello World!'
-    self.msg.load(body)
+    self.msg.body = 'Hello World!'
 
     data = self.msg.encode()
 
@@ -126,8 +125,7 @@ class CodecTest(Test):
     assert self.msg.priority == msg2.priority, (self.msg.priority, 
msg2.priority)
     assert self.msg.address == msg2.address, (self.msg.address, msg2.address)
     assert self.msg.subject == msg2.subject, (self.msg.subject, msg2.subject)
-    saved = self.msg.save()
-    assert saved == body, (body, saved)
+    assert self.msg.body == msg2.body, (self.msg.body, msg2.body)
 
 class LoadSaveTest(Test):
 

Modified: qpid/proton/trunk/tests/python/proton_tests/messenger.py
URL: 
http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/messenger.py?rev=1481834&r1=1481833&r2=1481834&view=diff
==============================================================================
--- qpid/proton/trunk/tests/python/proton_tests/messenger.py (original)
+++ qpid/proton/trunk/tests/python/proton_tests/messenger.py Mon May 13 
13:00:04 2013
@@ -25,32 +25,31 @@ from time import sleep, time
 class Test(common.Test):
 
   def setup(self):
-    # Very high timeout expected to only be exceeded by a genuine functional
-    # problem, not by CI server slowness.
-    self.long_timeout_millis = 100000
-
     self.server_credit = 10
     self.server_received = 0
     self.server = Messenger("server")
-    self.server.timeout = self.long_timeout_millis
+    self.server.timeout = int(self.timeout*1000)
     self.server.start()
     self.server.subscribe("amqp://~0.0.0.0:12345")
     self.server_thread = Thread(name="server-thread", target=self.run_server)
     self.server_thread.daemon = True
     self.server_is_running_event = Event()
     self.running = True
+    self.server_thread_started = False
 
     self.client = Messenger("client")
-    self.client.timeout= self.long_timeout_millis
+    self.client.timeout = int(self.timeout*1000)
 
   def start(self):
+    self.server_thread_started = True
     self.server_thread.start()
-    self.server_is_running_event.wait(self.long_timeout_millis/1000)
+    self.server_is_running_event.wait(self.timeout)
     self.client.start()
 
   def teardown(self):
     try:
       if self.running:
+        if not self.server_thread_started: self.start()
         # send a message to cause the server to promptly exit
         self.running = False
         msg = Message()
@@ -59,7 +58,7 @@ class Test(common.Test):
         self.client.send()
     finally:
       self.client.stop()
-      self.server_thread.join()
+      self.server_thread.join(self.timeout)
       self.client = None
       self.server = None
 
@@ -104,7 +103,7 @@ class MessengerTest(Test):
       while len(body) < size:
         body = 2*body
       body = body[:size]
-    msg.load(body)
+    msg.body = body
     self.client.put(msg)
     self.client.send()
 
@@ -114,7 +113,7 @@ class MessengerTest(Test):
     self.client.get(reply)
 
     assert reply.subject == "Hello World!"
-    rbod = reply.save()
+    rbod = reply.body
     assert rbod == body, (rbod, body)
 
   def testSendReceive(self):
@@ -303,7 +302,7 @@ class MessengerTest(Test):
     msg = Message()
     msg.address="amqp://0.0.0.0:12345"
     msg.subject="Hello World!"
-    msg.load("First the world, then the galaxy!")
+    msg.body = "First the world, then the galaxy!"
     assert self.server_received == 0
     self.client.put(msg)
     self.client.send()
@@ -325,7 +324,7 @@ class MessengerTest(Test):
     msg.address="amqp://0.0.0.0:12345/XXX"
     msg.subject="Hello World!"
     body = "First the world, then the galaxy!"
-    msg.load(body)
+    msg.body = body
     self.client.put(msg)
     self.client.send()
 
@@ -335,14 +334,14 @@ class MessengerTest(Test):
     self.client.get(reply)
 
     assert reply.subject == "Hello World!"
-    rbod = reply.save()
+    rbod = reply.body
     assert rbod == body, (rbod, body)
 
     msg = Message()
     msg.address="amqp://0.0.0.0:12345/YYY"
     msg.subject="Hello World!"
     body = "First the world, then the galaxy!"
-    msg.load(body)
+    msg.body = body
     self.client.put(msg)
     self.client.send()
 
@@ -352,7 +351,7 @@ class MessengerTest(Test):
     self.client.get(reply)
 
     assert reply.subject == "Hello World!"
-    rbod = reply.save()
+    rbod = reply.body
     assert rbod == body, (rbod, body)
 
   def _DISABLE_test_proton268(self):
@@ -363,7 +362,7 @@ class MessengerTest(Test):
 
     msg = Message()
     msg.address="amqp://0.0.0.0:12345"
-    msg.load( "X" * 1024 )
+    msg.body = "X" * 1024
 
     for x in range( 100 ):
       self.client.put( msg )
@@ -446,3 +445,120 @@ class MessengerTest(Test):
     reply = Message()
     self.client.get(reply)
     assert reply.body == "test"
+
+  def echo_address(self, msg):
+    while self.server.incoming:
+      self.server.get(msg)
+      msg.body = msg.address
+      self.dispatch(msg)
+
+  def _testRewrite(self, original, rewritten):
+    self.start()
+    self.process_incoming = self.echo_address
+    self.client.route("*", "amqp://0.0.0.0:12345")
+
+    msg = Message()
+    msg.address = original
+    msg.body = "test"
+
+    self.client.put(msg)
+    assert msg.address == original
+    self.client.recv(1)
+    assert self.client.incoming == 1
+
+    echo = Message()
+    self.client.get(echo)
+    assert echo.body == rewritten, (echo.body, rewritten)
+    assert msg.address == original
+
+  def testDefaultRewriteH(self):
+    self._testRewrite("original", "original")
+
+  def testDefaultRewriteUH(self):
+    self._testRewrite("user@original", "original")
+
+  def testDefaultRewriteUPH(self):
+    self._testRewrite("user:pass@original", "original")
+
+  def testDefaultRewriteHP(self):
+    self._testRewrite("original:123", "original:123")
+
+  def testDefaultRewriteUHP(self):
+    self._testRewrite("user@original:123", "original:123")
+
+  def testDefaultRewriteUPHP(self):
+    self._testRewrite("user:pass@original:123", "original:123")
+
+  def testDefaultRewriteHN(self):
+    self._testRewrite("original/name", "original/name")
+
+  def testDefaultRewriteUHN(self):
+    self._testRewrite("user@original/name", "original/name")
+
+  def testDefaultRewriteUPHN(self):
+    self._testRewrite("user:pass@original/name", "original/name")
+
+  def testDefaultRewriteHPN(self):
+    self._testRewrite("original:123/name", "original:123/name")
+
+  def testDefaultRewriteUHPN(self):
+    self._testRewrite("user@original:123/name", "original:123/name")
+
+  def testDefaultRewriteUPHPN(self):
+    self._testRewrite("user:pass@original:123/name", "original:123/name")
+
+  def testDefaultRewriteSH(self):
+    self._testRewrite("amqp://original", "amqp://original")
+
+  def testDefaultRewriteSUH(self):
+    self._testRewrite("amqp://user@original", "amqp://original")
+
+  def testDefaultRewriteSUPH(self):
+    self._testRewrite("amqp://user:pass@original", "amqp://original")
+
+  def testDefaultRewriteSHP(self):
+    self._testRewrite("amqp://original:123", "amqp://original:123")
+
+  def testDefaultRewriteSUHP(self):
+    self._testRewrite("amqp://user@original:123", "amqp://original:123")
+
+  def testDefaultRewriteSUPHP(self):
+    self._testRewrite("amqp://user:pass@original:123", "amqp://original:123")
+
+  def testDefaultRewriteSHN(self):
+    self._testRewrite("amqp://original/name", "amqp://original/name")
+
+  def testDefaultRewriteSUHN(self):
+    self._testRewrite("amqp://user@original/name", "amqp://original/name")
+
+  def testDefaultRewriteSUPHN(self):
+    self._testRewrite("amqp://user:pass@original/name", "amqp://original/name")
+
+  def testDefaultRewriteSHPN(self):
+    self._testRewrite("amqp://original:123/name", "amqp://original:123/name")
+
+  def testDefaultRewriteSUHPN(self):
+    self._testRewrite("amqp://user@original:123/name", 
"amqp://original:123/name")
+
+  def testDefaultRewriteSUPHPN(self):
+    self._testRewrite("amqp://user:pass@original:123/name", 
"amqp://original:123/name")
+
+  def testRewriteSupress(self):
+    self.client.rewrite("*", None)
+    self._testRewrite("asdf", None)
+
+  def testRewrite(self):
+    self.client.rewrite("a", "b")
+    self._testRewrite("a", "b")
+
+  def testRewritePattern(self):
+    self.client.rewrite("amqp://%@*", "amqp://$2")
+    self._testRewrite("amqp://foo@bar", "amqp://bar")
+
+  def testRewriteToAt(self):
+    self.client.rewrite("amqp://%/*", "$2@$1")
+    self._testRewrite("amqp://domain/name", "name@domain")
+
+  def testRewriteOverrideDefault(self):
+    self.client.rewrite("*", "$1")
+    self._testRewrite("amqp://user:pass@host", "amqp://user:pass@host")



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to