Commit 149115e8 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Optimization - Avoid stringprep whenever possible. JM-925

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@6550 b35dd754-fafc-0310-a699-88a17e54d16e
parent b9f0c26b
...@@ -69,6 +69,19 @@ public class IQ extends Packet { ...@@ -69,6 +69,19 @@ public class IQ extends Packet {
super(element); super(element);
} }
/**
* Constructs a new IQ using an existing Element. This is useful
* for parsing incoming IQ Elements into IQ objects. Stringprep validation
* on the TO address can be disabled. The FROM address will not be validated since the
* server is the one that sets that value.
*
* @param element the IQ Element.
* @param skipValidation true if stringprep should not be applied to the TO address.
*/
public IQ(Element element, boolean skipValidation) {
super(element, skipValidation);
}
/** /**
* Constructs a new IQ that is a copy of an existing IQ. * Constructs a new IQ that is a copy of an existing IQ.
* *
......
...@@ -22,6 +22,7 @@ package org.xmpp.packet; ...@@ -22,6 +22,7 @@ package org.xmpp.packet;
import org.jivesoftware.stringprep.IDNA; import org.jivesoftware.stringprep.IDNA;
import org.jivesoftware.stringprep.Stringprep; import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections; import java.util.Collections;
...@@ -53,7 +54,7 @@ public class JID implements Comparable, Serializable { ...@@ -53,7 +54,7 @@ public class JID implements Comparable, Serializable {
// Stringprep operations are very expensive. Therefore, we cache node, domain and // Stringprep operations are very expensive. Therefore, we cache node, domain and
// resource values that have already had stringprep applied so that we can check // resource values that have already had stringprep applied so that we can check
// incoming values against the cache. // incoming values against the cache.
private static Map stringprepCache = Collections.synchronizedMap(new Cache(1000)); private static Map stringprepCache = Collections.synchronizedMap(new Cache(10000));
private String node; private String node;
private String domain; private String domain;
...@@ -203,6 +204,19 @@ public class JID implements Comparable, Serializable { ...@@ -203,6 +204,19 @@ public class JID implements Comparable, Serializable {
return buf.toString(); return buf.toString();
} }
public static String resourceprep(String resource) throws StringprepException {
String answer = resource;
if (!stringprepCache.containsKey(resource)) {
answer = Stringprep.resourceprep(resource);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (answer != null && answer.length()*2 > 1023) {
return answer;
}
stringprepCache.put(answer, null);
}
return answer;
}
/** /**
* Constructs a JID from it's String representation. * Constructs a JID from it's String representation.
* *
...@@ -213,78 +227,64 @@ public class JID implements Comparable, Serializable { ...@@ -213,78 +227,64 @@ public class JID implements Comparable, Serializable {
if (jid == null) { if (jid == null) {
throw new NullPointerException("JID cannot be null"); throw new NullPointerException("JID cannot be null");
} }
String node = null; String[] parts = getParts(jid);
String domain = null;
String resource = null;
int atIndex = jid.indexOf("@");
int slashIndex = jid.indexOf("/");
// Node init(parts[0], parts[1], parts[2]);
if (atIndex > 0) {
node = jid.substring(0, atIndex);
} }
// Domain /**
if (atIndex + 1 > jid.length()) { * Constructs a JID given a node, domain, and resource.
throw new IllegalArgumentException("JID with empty domain not valid"); *
} * @param node the node.
if (atIndex < 0) { * @param domain the domain, which must not be <tt>null</tt>.
if (slashIndex > 0) { * @param resource the resource.
domain = jid.substring(0, slashIndex); * @throws IllegalArgumentException if the JID is not valid.
} */
else { public JID(String node, String domain, String resource) {
domain = jid; if (domain == null) {
} throw new NullPointerException("Domain cannot be null");
}
else {
if (slashIndex > 0) {
domain = jid.substring(atIndex + 1, slashIndex);
}
else {
domain = jid.substring(atIndex + 1);
}
}
// Resource
if (slashIndex + 1 > jid.length() || slashIndex < 0) {
resource = null;
}
else {
resource = jid.substring(slashIndex + 1);
} }
init(node, domain, resource);
init(node, domain,resource);
} }
/** /**
* Constructs a JID given a node, domain, and resource. * Constructs a JID given a node, domain, and resource being able to specify if stringprep
* should be applied or not.
* *
* @param node the node. * @param node the node.
* @param domain the domain, which must not be <tt>null</tt>. * @param domain the domain, which must not be <tt>null</tt>.
* @param resource the resource. * @param resource the resource.
* @param skipStringprep true if stringprep should not be applied.
* @throws IllegalArgumentException if the JID is not valid. * @throws IllegalArgumentException if the JID is not valid.
*/ */
public JID(String node, String domain, String resource) { public JID(String node, String domain, String resource, boolean skipStringprep) {
if (domain == null) { if (domain == null) {
throw new NullPointerException("Domain cannot be null"); throw new NullPointerException("Domain cannot be null");
} }
if (skipStringprep) {
this.node = node;
this.domain = domain;
this.resource = resource;
// Cache the bare and full JID String representation
updateCache();
}
else {
init(node, domain, resource); init(node, domain, resource);
} }
}
/** /**
* Constructs a new JID, bypassing all stringprep profiles. This * Returns a String array with the parsed node, domain and resource.
* is useful for constructing a JID object when it's already known * No Stringprep is performed while parsing the textual representation.
* that the String representation is well-formed.
* *
* @param jid the JID. * @param jid the textual JID representation.
* @param fake an extra param to create a different method signature. * @return a string array with the parsed node, domain and resource.
* The value <tt>null</tt> should be passed in as this argument.
*/ */
JID(String jid, Object fake) { static String[] getParts(String jid) {
fake = null; // Workaround IDE warnings for unused param. String[] parts = new String[3];
String node = null , domain, resource;
if (jid == null) { if (jid == null) {
throw new NullPointerException("JID cannot be null"); return parts;
} }
int atIndex = jid.indexOf("@"); int atIndex = jid.indexOf("@");
...@@ -323,8 +323,10 @@ public class JID implements Comparable, Serializable { ...@@ -323,8 +323,10 @@ public class JID implements Comparable, Serializable {
else { else {
resource = jid.substring(slashIndex + 1); resource = jid.substring(slashIndex + 1);
} }
// Cache the bare and full JID String representation parts[0] = node;
updateCache(); parts[1] = domain;
parts[2] = resource;
return parts;
} }
/** /**
...@@ -349,7 +351,7 @@ public class JID implements Comparable, Serializable { ...@@ -349,7 +351,7 @@ public class JID implements Comparable, Serializable {
if (!stringprepCache.containsKey(node)) { if (!stringprepCache.containsKey(node)) {
this.node = Stringprep.nodeprep(node); this.node = Stringprep.nodeprep(node);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes. // Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (node != null && node.length()*2 > 1023) { if (this.node != null && this.node.length()*2 > 1023) {
throw new IllegalArgumentException("Node cannot be larger than 1023 bytes. " + throw new IllegalArgumentException("Node cannot be larger than 1023 bytes. " +
"Size is " + (node.length() * 2) + " bytes."); "Size is " + (node.length() * 2) + " bytes.");
} }
...@@ -365,27 +367,21 @@ public class JID implements Comparable, Serializable { ...@@ -365,27 +367,21 @@ public class JID implements Comparable, Serializable {
if (!stringprepCache.containsKey(domain)) { if (!stringprepCache.containsKey(domain)) {
this.domain = Stringprep.nameprep(IDNA.toASCII(domain), false); this.domain = Stringprep.nameprep(IDNA.toASCII(domain), false);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes. // Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (domain.length()*2 > 1023) { if (this.domain.length()*2 > 1023) {
throw new IllegalArgumentException("Domain cannot be larger than 1023 bytes. " + throw new IllegalArgumentException("Domain cannot be larger than 1023 bytes. " +
"Size is " + (domain.length() * 2) + " bytes."); "Size is " + (this.domain.length() * 2) + " bytes.");
} }
stringprepCache.put(this.domain, null); stringprepCache.put(this.domain, null);
} }
else { else {
this.domain = domain; this.domain = domain;
} }
if (!stringprepCache.containsKey(resource)) { this.resource = resourceprep(resource);
this.resource = Stringprep.resourceprep(resource);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes. // Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (resource != null && resource.length()*2 > 1023) { if (resource != null && resource.length()*2 > 1023) {
throw new IllegalArgumentException("Resource cannot be larger than 1023 bytes. " + throw new IllegalArgumentException("Resource cannot be larger than 1023 bytes. " +
"Size is " + (resource.length() * 2) + " bytes."); "Size is " + (resource.length() * 2) + " bytes.");
} }
stringprepCache.put(this.resource, null);
}
else {
this.resource = resource;
}
// Cache the bare and full JID String representation // Cache the bare and full JID String representation
updateCache(); updateCache();
} }
......
...@@ -59,6 +59,19 @@ public class Message extends Packet { ...@@ -59,6 +59,19 @@ public class Message extends Packet {
super(element); super(element);
} }
/**
* Constructs a new Message using an existing Element. This is useful
* for parsing incoming message Elements into Message objects. Stringprep validation
* on the TO address can be disabled. The FROM address will not be validated since the
* server is the one that sets that value.
*
* @param element the message Element.
* @param skipValidation true if stringprep should not be applied to the TO address.
*/
public Message(Element element, boolean skipValidation) {
super(element, skipValidation);
}
/** /**
* Constructs a new Message that is a copy of an existing Message. * Constructs a new Message that is a copy of an existing Message.
* *
......
...@@ -56,21 +56,40 @@ public abstract class Packet { ...@@ -56,21 +56,40 @@ public abstract class Packet {
protected JID fromJID; protected JID fromJID;
/** /**
* Constructs a new Packet. * Constructs a new Packet. The TO address contained in the XML Element will only be
* validated. In other words, stringprep operations will only be performed on the TO JID to
* verify that it is well-formed. The FROM address is assigned by the server so there is no
* need to verify it.
* *
* @param element the XML Element that contains the packet contents. * @param element the XML Element that contains the packet contents.
*/ */
public Packet(Element element) { public Packet(Element element) {
this(element, false);
}
/**
* Constructs a new Packet. The JID address contained in the XML Element may not be
* validated. When validation can be skipped then stringprep operations will not be performed
* on the JIDs to verify that addresses are well-formed. However, when validation cannot be
* skipped then <tt>only</tt> the TO address will be verified. The FROM address is assigned by
* the server so there is no need to verify it.
*
* @param element the XML Element that contains the packet contents.
* @param skipValidation true if stringprep should not be applied to the TO address.
*/
public Packet(Element element, boolean skipValidation) {
this.element = element; this.element = element;
// Apply stringprep profiles to the "to" and "from" values. // Apply stringprep profiles to the "to" and "from" values.
String to = element.attributeValue("to"); String to = element.attributeValue("to");
if (to != null) { if (to != null) {
toJID = new JID(to); String[] parts = JID.getParts(to);
toJID = new JID(parts[0], parts[1], parts[2], skipValidation);
element.addAttribute("to", toJID.toString()); element.addAttribute("to", toJID.toString());
} }
String from = element.attributeValue("from"); String from = element.attributeValue("from");
if (from != null) { if (from != null) {
fromJID = new JID(from); String[] parts = JID.getParts(from);
fromJID = new JID(parts[0], parts[1], parts[2], true);
element.addAttribute("from", fromJID.toString()); element.addAttribute("from", fromJID.toString());
} }
} }
...@@ -125,7 +144,8 @@ public abstract class Packet { ...@@ -125,7 +144,8 @@ public abstract class Packet {
// This improves speed and is safe as long as the user doesn't // This improves speed and is safe as long as the user doesn't
// directly manipulate the attributes of the underlying Element // directly manipulate the attributes of the underlying Element
// that represent JID's. // that represent JID's.
toJID = new JID(to, null); String[] parts = JID.getParts(to);
toJID = new JID(parts[0], parts[1], parts[2], true);
return toJID; return toJID;
} }
} }
...@@ -184,7 +204,8 @@ public abstract class Packet { ...@@ -184,7 +204,8 @@ public abstract class Packet {
// This improves speed and is safe as long as the user doesn't // This improves speed and is safe as long as the user doesn't
// directly manipulate the attributes of the underlying Element // directly manipulate the attributes of the underlying Element
// that represent JID's. // that represent JID's.
fromJID = new JID(from, null); String[] parts = JID.getParts(from);
fromJID = new JID(parts[0], parts[1], parts[2], true);
return fromJID; return fromJID;
} }
} }
......
...@@ -63,6 +63,19 @@ public class Presence extends Packet { ...@@ -63,6 +63,19 @@ public class Presence extends Packet {
super(element); super(element);
} }
/**
* Constructs a new Presence using an existing Element. This is useful
* for parsing incoming Presence Elements into Presence objects. Stringprep validation
* on the TO address can be disabled. The FROM address will not be validated since the
* server is the one that sets that value.
*
* @param element the Presence Element.
* @param skipValidation true if stringprep should not be applied to the TO address.
*/
public Presence(Element element, boolean skipValidation) {
super(element, skipValidation);
}
/** /**
* Constructs a new Presence that is a copy of an existing Presence. * Constructs a new Presence that is a copy of an existing Presence.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment