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 {
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.
*
......
......@@ -22,6 +22,7 @@ package org.xmpp.packet;
import org.jivesoftware.stringprep.IDNA;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import java.io.Serializable;
import java.util.Collections;
......@@ -53,7 +54,7 @@ public class JID implements Comparable, Serializable {
// Stringprep operations are very expensive. Therefore, we cache node, domain and
// resource values that have already had stringprep applied so that we can check
// 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 domain;
......@@ -203,6 +204,19 @@ public class JID implements Comparable, Serializable {
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.
*
......@@ -213,48 +227,9 @@ public class JID implements Comparable, Serializable {
if (jid == null) {
throw new NullPointerException("JID cannot be null");
}
String node = null;
String domain = null;
String resource = null;
int atIndex = jid.indexOf("@");
int slashIndex = jid.indexOf("/");
// Node
if (atIndex > 0) {
node = jid.substring(0, atIndex);
}
String[] parts = getParts(jid);
// Domain
if (atIndex + 1 > jid.length()) {
throw new IllegalArgumentException("JID with empty domain not valid");
}
if (atIndex < 0) {
if (slashIndex > 0) {
domain = jid.substring(0, slashIndex);
}
else {
domain = jid;
}
}
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(parts[0], parts[1], parts[2]);
}
/**
......@@ -273,18 +248,43 @@ public class JID implements Comparable, Serializable {
}
/**
* Constructs a new JID, bypassing all stringprep profiles. This
* is useful for constructing a JID object when it's already known
* that the String representation is well-formed.
* Constructs a JID given a node, domain, and resource being able to specify if stringprep
* should be applied or not.
*
* @param jid the JID.
* @param fake an extra param to create a different method signature.
* The value <tt>null</tt> should be passed in as this argument.
* @param node the node.
* @param domain the domain, which must not be <tt>null</tt>.
* @param resource the resource.
* @param skipStringprep true if stringprep should not be applied.
* @throws IllegalArgumentException if the JID is not valid.
*/
JID(String jid, Object fake) {
fake = null; // Workaround IDE warnings for unused param.
public JID(String node, String domain, String resource, boolean skipStringprep) {
if (domain == 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);
}
}
/**
* Returns a String array with the parsed node, domain and resource.
* No Stringprep is performed while parsing the textual representation.
*
* @param jid the textual JID representation.
* @return a string array with the parsed node, domain and resource.
*/
static String[] getParts(String jid) {
String[] parts = new String[3];
String node = null , domain, resource;
if (jid == null) {
throw new NullPointerException("JID cannot be null");
return parts;
}
int atIndex = jid.indexOf("@");
......@@ -323,8 +323,10 @@ public class JID implements Comparable, Serializable {
else {
resource = jid.substring(slashIndex + 1);
}
// Cache the bare and full JID String representation
updateCache();
parts[0] = node;
parts[1] = domain;
parts[2] = resource;
return parts;
}
/**
......@@ -349,7 +351,7 @@ public class JID implements Comparable, Serializable {
if (!stringprepCache.containsKey(node)) {
this.node = Stringprep.nodeprep(node);
// 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. " +
"Size is " + (node.length() * 2) + " bytes.");
}
......@@ -365,26 +367,20 @@ public class JID implements Comparable, Serializable {
if (!stringprepCache.containsKey(domain)) {
this.domain = Stringprep.nameprep(IDNA.toASCII(domain), false);
// 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. " +
"Size is " + (domain.length() * 2) + " bytes.");
"Size is " + (this.domain.length() * 2) + " bytes.");
}
stringprepCache.put(this.domain, null);
}
else {
this.domain = domain;
}
if (!stringprepCache.containsKey(resource)) {
this.resource = Stringprep.resourceprep(resource);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (resource != null && resource.length()*2 > 1023) {
throw new IllegalArgumentException("Resource cannot be larger than 1023 bytes. " +
"Size is " + (resource.length() * 2) + " bytes.");
}
stringprepCache.put(this.resource, null);
}
else {
this.resource = resource;
this.resource = resourceprep(resource);
// Validate field is not greater than 1023 bytes. UTF-8 characters use two bytes.
if (resource != null && resource.length()*2 > 1023) {
throw new IllegalArgumentException("Resource cannot be larger than 1023 bytes. " +
"Size is " + (resource.length() * 2) + " bytes.");
}
// Cache the bare and full JID String representation
updateCache();
......
......@@ -59,6 +59,19 @@ public class Message extends Packet {
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.
*
......
......@@ -56,21 +56,40 @@ public abstract class Packet {
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.
*/
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;
// Apply stringprep profiles to the "to" and "from" values.
String to = element.attributeValue("to");
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());
}
String from = element.attributeValue("from");
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());
}
}
......@@ -125,7 +144,8 @@ public abstract class Packet {
// This improves speed and is safe as long as the user doesn't
// directly manipulate the attributes of the underlying Element
// 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;
}
}
......@@ -184,7 +204,8 @@ public abstract class Packet {
// This improves speed and is safe as long as the user doesn't
// directly manipulate the attributes of the underlying Element
// 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;
}
}
......
......@@ -63,6 +63,19 @@ public class Presence extends Packet {
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.
*
......
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