You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ol...@apache.org on 2003/07/13 15:54:51 UTC
cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestParameterParser.java TestHeaderElement.java TestNoHost.java
olegk 2003/07/13 06:54:51
Modified: httpclient/src/java/org/apache/commons/httpclient
ChunkedInputStream.java Header.java
HeaderElement.java HttpMethodBase.java
HttpState.java package.html
httpclient/src/java/org/apache/commons/httpclient/auth
AuthChallengeParser.java HttpAuthenticator.java
httpclient/src/java/org/apache/commons/httpclient/cookie
CookieSpecBase.java
httpclient/src/java/org/apache/commons/httpclient/util
DateParser.java
httpclient/src/test/org/apache/commons/httpclient
TestHeaderElement.java TestNoHost.java
Added: httpclient/src/java/org/apache/commons/httpclient/util
ParameterParser.java
httpclient/src/test/org/apache/commons/httpclient
TestParameterParser.java
Log:
Bug fix #21210 (HeaderElement#parse(String) implementation is not optimal)
Changelog:
- Header parsing routines completely reworked
- Handling of Netscape cookies improved
- Javadoc tags cleaned up
Contributed by Oleg Kalnichevski
Reviewed by Michael Becke
Revision Changes Path
1.17 +3 -5 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java
Index: ChunkedInputStream.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- ChunkedInputStream.java 8 May 2003 17:33:51 -0000 1.16
+++ ChunkedInputStream.java 13 Jul 2003 13:54:50 -0000 1.17
@@ -78,8 +78,6 @@
* not requiring the client to remember to read the entire contents of the
* response.</p>
*
- * @see ResponseInputStream
- *
* @author Ortwin Gl�ck
* @author Sean C. Sullivan
* @author Martin Elwin
1.11 +18 -4 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Header.java
Index: Header.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Header.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- Header.java 28 Jan 2003 04:40:20 -0000 1.10
+++ Header.java 13 Jul 2003 13:54:50 -0000 1.11
@@ -123,9 +123,23 @@
* @see HeaderElement#parse
* @throws HttpException When ? occurs
* @return an array of header elements
+ *
+ * @deprecated Use #getElements
*/
public HeaderElement[] getValues() throws HttpException {
return HeaderElement.parse(getValue());
+ }
+
+ /**
+ * Returns an array of {@link HeaderElement}s
+ * constructed from my value.
+ *
+ * @see HeaderElement#parseElements(String)
+ *
+ * @return an array of header elements
+ */
+ public HeaderElement[] getElements() {
+ return HeaderElement.parseElements(getValue());
}
}
1.19 +99 -234 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java
Index: HeaderElement.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- HeaderElement.java 14 Apr 2003 04:06:55 -0000 1.18
+++ HeaderElement.java 13 Jul 2003 13:54:50 -0000 1.19
@@ -63,15 +63,13 @@
package org.apache.commons.httpclient;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.httpclient.util.ParameterParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import java.util.BitSet;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-
/**
* <p>One element of an HTTP header's value.</p>
* <p>
@@ -114,6 +112,7 @@
* @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
* @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.com">Oleg Kalnichevski</a>
*
* @since 1.0
* @version $Revision$ $Date$
@@ -148,87 +147,47 @@
public HeaderElement(String name, String value,
NameValuePair[] parameters) {
super(name, value);
- setParameters(parameters);
+ this.parameters = parameters;
}
- // -------------------------------------------------------- Constants
-
- /** Log object for this class. */
- private static final Log LOG = LogFactory.getLog(HeaderElement.class);
-
/**
- * Map of numeric values to whether or not the
- * corresponding character is a "separator
- * character" (tspecial).
- */
- private static final BitSet SEPARATORS = new BitSet(128);
-
- /**
- * Map of numeric values to whether or not the
- * corresponding character is a "token
- * character".
- */
- private static final BitSet TOKEN_CHAR = new BitSet(128);
+ * Constructor with array of characters.
+ *
+ * @param chars the array of characters
+ * @param offset - the initial offset.
+ * @param length - the length.
+ */
+ public HeaderElement(char[] chars, int offset, int length) {
+ this();
+ if (chars == null) {
+ return;
+ }
+ ParameterParser parser = new ParameterParser();
+ List params = parser.parse(chars, offset, length, ';');
+ if (params.size() > 0) {
+ NameValuePair element = (NameValuePair)params.remove(0);
+ setName(element.getName());
+ setValue(element.getValue());
+ if (params.size() > 0) {
+ this.parameters = (NameValuePair[])
+ params.toArray(new NameValuePair[params.size()]);
+ }
+ }
+ }
/**
- * Map of numeric values to whether or not the
- * corresponding character is an "unsafe
- * character".
+ * Constructor with array of characters.
+ *
+ * @param chars the array of characters
*/
- private static final BitSet UNSAFE_CHAR = new BitSet(128);
+ public HeaderElement(char[] chars) {
+ this(chars, 0, chars.length);
+ }
- /**
- * Static initializer for {@link #SEPARATORS},
- * {@link #TOKEN_CHAR}, and {@link #UNSAFE_CHAR}.
- */
- static {
- // rfc-2068 tspecial
- SEPARATORS.set('(');
- SEPARATORS.set(')');
- SEPARATORS.set('<');
- SEPARATORS.set('>');
- SEPARATORS.set('@');
- SEPARATORS.set(',');
- SEPARATORS.set(';');
- SEPARATORS.set(':');
- SEPARATORS.set('\\');
- SEPARATORS.set('"');
- SEPARATORS.set('/');
- SEPARATORS.set('[');
- SEPARATORS.set(']');
- SEPARATORS.set('?');
- SEPARATORS.set('=');
- SEPARATORS.set('{');
- SEPARATORS.set('}');
- SEPARATORS.set(' ');
- SEPARATORS.set('\t');
-
- // rfc-2068 token
- for (int ch = 32; ch < 127; ch++) {
- TOKEN_CHAR.set(ch);
- }
- TOKEN_CHAR.xor(SEPARATORS);
+ // -------------------------------------------------------- Constants
- // rfc-1738 unsafe characters, including CTL and SP, and excluding
- // "#" and "%"
- for (int ch = 0; ch < 32; ch++) {
- UNSAFE_CHAR.set(ch);
- }
- UNSAFE_CHAR.set(' ');
- UNSAFE_CHAR.set('<');
- UNSAFE_CHAR.set('>');
- UNSAFE_CHAR.set('"');
- UNSAFE_CHAR.set('{');
- UNSAFE_CHAR.set('}');
- UNSAFE_CHAR.set('|');
- UNSAFE_CHAR.set('\\');
- UNSAFE_CHAR.set('^');
- UNSAFE_CHAR.set('~');
- UNSAFE_CHAR.set('[');
- UNSAFE_CHAR.set(']');
- UNSAFE_CHAR.set('`');
- UNSAFE_CHAR.set(127);
- }
+ /** Log object for this class. */
+ private static final Log LOG = LogFactory.getLog(HeaderElement.class);
// ----------------------------------------------------- Instance Variables
@@ -247,187 +206,91 @@
return this.parameters;
}
- /**
- *
- * @param pairs The new parameters. May be null.
- */
- protected void setParameters(final NameValuePair[] pairs) {
- parameters = pairs;
- }
// --------------------------------------------------------- Public Methods
/**
* This parses the value part of a header. The result is an array of
* HeaderElement objects.
*
- * @param headerValue the string representation of the header value
+ * @param headerValue the array of char representation of the header value
* (as received from the web server).
- * @return the header elements containing <code>Header</code> elements.
- * @throws HttpException if the above syntax rules are violated.
+ * @return array of {@link HeaderElement}s.
*/
- public static final HeaderElement[] parse(String headerValue)
- throws HttpException {
+ public static final HeaderElement[] parseElements(char[] headerValue) {
- LOG.trace("enter HeaderElement.parse(String)");
+ LOG.trace("enter HeaderElement.parseElements(char[])");
if (headerValue == null) {
- return null;
+ return new HeaderElement[] {};
}
+ List elements = new ArrayList();
- Vector elements = new Vector();
- StringTokenizer tokenizer =
- new StringTokenizer(headerValue.trim(), ",");
-
- while (tokenizer.countTokens() > 0) {
- String nextToken = tokenizer.nextToken();
-
- // FIXME: refactor into private method named ?
- // careful... there may have been a comma in a quoted string
- try {
- while (HeaderElement.hasOddNumberOfQuotationMarks(nextToken)) {
- nextToken += "," + tokenizer.nextToken();
- }
- } catch (NoSuchElementException exception) {
- throw new HttpException(
- "Bad header format: wrong number of quotation marks");
+ int i = 0;
+ int from = 0;
+ int len = headerValue.length;
+ boolean qouted = false;
+ while(i < len) {
+ char ch = headerValue[i];
+ if (ch == '"') {
+ qouted = !qouted;
}
-
- // FIXME: Refactor out into a private method named ?
- try {
- /*
- * Following to RFC 2109 and 2965, in order not to conflict
- * with the next header element, make it sure to parse tokens.
- * the expires date format is "Wdy, DD-Mon-YY HH:MM:SS GMT".
- * Notice that there is always comma(',') sign.
- * For the general cases, rfc1123-date, rfc850-date.
- */
- if (tokenizer.hasMoreTokens()) {
- String s = nextToken.toLowerCase();
- if (s.endsWith("mon")
- || s.endsWith("tue")
- || s.endsWith("wed")
- || s.endsWith("thu")
- || s.endsWith("fri")
- || s.endsWith("sat")
- || s.endsWith("sun")
- || s.endsWith("monday")
- || s.endsWith("tuesday")
- || s.endsWith("wednesday")
- || s.endsWith("thursday")
- || s.endsWith("friday")
- || s.endsWith("saturday")
- || s.endsWith("sunday")) {
-
- nextToken += "," + tokenizer.nextToken();
- }
- }
- } catch (NoSuchElementException exception) {
- throw new HttpException
- ("Bad header format: parsing with wrong header elements");
- }
-
- String tmp = nextToken.trim();
- if (!tmp.endsWith(";")) {
- tmp += ";";
+ HeaderElement element = null;
+ if ((!qouted) && (ch == ',')) {
+ element = new HeaderElement(headerValue, from, i);
+ from = i + 1;
+ } else if (i == len - 1) {
+ element = new HeaderElement(headerValue, from, len);
}
- char[] header = tmp.toCharArray();
-
- // FIXME: refactor into a private method named? parseElement?
- boolean inAString = false;
- int startPos = 0;
- HeaderElement element = new HeaderElement();
- Vector paramlist = new Vector();
- for (int i = 0 ; i < header.length ; i++) {
- if (header[i] == ';' && !inAString) {
- NameValuePair pair = parsePair(header, startPos, i);
- if (pair == null) {
- throw new HttpException(
- "Bad header format: empty name/value pair in"
- + nextToken);
-
- // the first name/value pair are handled differently
- } else if (startPos == 0) {
- element.setName(pair.getName());
- element.setValue(pair.getValue());
- } else {
- paramlist.addElement(pair);
- }
- startPos = i + 1;
- } else if (header[i] == '"'
- && !(inAString && i > 0 && header[i - 1] == '\\')) {
- inAString = !inAString;
- }
+ if ((element != null) && (element.getName() != null)) {
+ elements.add(element);
}
-
- // now let's add all the parameters into the header element
- if (paramlist.size() > 0) {
- NameValuePair[] tmp2 = new NameValuePair[paramlist.size()];
- paramlist.copyInto((NameValuePair[]) tmp2);
- element.setParameters (tmp2);
- paramlist.removeAllElements();
- }
-
- // and save the header element into the list of header elements
- elements.addElement(element);
+ i++;
}
-
- HeaderElement[] headerElements = new HeaderElement[elements.size()];
- elements.copyInto((HeaderElement[]) headerElements);
- return headerElements;
+ return (HeaderElement[])
+ elements.toArray(new HeaderElement[elements.size()]);
}
/**
- * Return <tt>true</tt> if <i>string</i> has
- * an odd number of <tt>"</tt> characters.
+ * This parses the value part of a header. The result is an array of
+ * HeaderElement objects.
*
- * @param string the string to test
- * @return true if there are an odd number of quotation marks, false
- * otherwise
+ * @param headerValue the string representation of the header value
+ * (as received from the web server).
+ * @return array of {@link HeaderElement}s.
+ * @throws HttpException if the above syntax rules are violated.
*/
- private static final boolean hasOddNumberOfQuotationMarks(String string) {
- boolean odd = false;
- int start = -1;
- while ((start = string.indexOf('"', start + 1)) != -1) {
- odd = !odd;
+ public static final HeaderElement[] parseElements(String headerValue) {
+
+ LOG.trace("enter HeaderElement.parseElements(String)");
+
+ if (headerValue == null) {
+ return new HeaderElement[] {};
}
- return odd;
+ return parseElements(headerValue.toCharArray());
}
/**
- * Parse a header character array into a {@link NameValuePair}
+ * This parses the value part of a header. The result is an array of
+ * HeaderElement objects.
*
- * @param header the character array to parse
- * @param start the starting position of the text within the array
- * @param end the end position of the text within the array
- * @return a {@link NameValuePair} representing the header
+ * @param headerValue the string representation of the header value
+ * (as received from the web server).
+ * @return array of {@link HeaderElement}s.
+ * @throws HttpException if the above syntax rules are violated.
+ *
+ * @deprecated Use #parseElements(String).
*/
- private static final NameValuePair parsePair(char[] header,
- int start, int end) {
+ public static final HeaderElement[] parse(String headerValue)
+ throws HttpException {
- LOG.trace("enter HeaderElement.parsePair(char[], int, int)");
+ LOG.trace("enter HeaderElement.parse(String)");
- NameValuePair pair = null;
- String name = new String(header, start, end - start).trim();
- String value = null;
-
- //TODO: This would certainly benefit from a StringBuffer
- int index = name.indexOf("=");
- if (index >= 0) {
- if ((index + 1) < name.length()) {
- value = name.substring(index + 1).trim();
- // strip quotation marks
- if (value.startsWith("\"") && value.endsWith("\"")) {
- value = value.substring(1, value.length() - 1);
- }
- }
- name = name.substring(0, index).trim();
+ if (headerValue == null) {
+ return new HeaderElement[] {};
}
-
- pair = new NameValuePair(name, value);
-
- return pair;
+ return parseElements(headerValue.toCharArray());
}
-
+
/**
* Returns parameter with the given name, if found. Otherwise null
@@ -438,8 +301,11 @@
*/
public NameValuePair getParameterByName(String name) {
+
+ LOG.trace("enter HeaderElement.getParameterByName(String)");
+
if (name == null) {
- throw new NullPointerException("Name is null");
+ throw new IllegalArgumentException("Name may not be null");
}
NameValuePair found = null;
NameValuePair parameters[] = getParameters();
@@ -454,7 +320,6 @@
}
return found;
}
-
}
1.165 +14 -18 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java
Index: HttpMethodBase.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v
retrieving revision 1.164
retrieving revision 1.165
diff -u -r1.164 -r1.165
--- HttpMethodBase.java 11 Jul 2003 01:07:29 -0000 1.164
+++ HttpMethodBase.java 13 Jul 2003 13:54:50 -0000 1.165
@@ -2054,7 +2054,7 @@
LOG.warn("Unsupported transfer encoding: " + transferEncoding);
}
}
- HeaderElement[] encodings = transferEncodingHeader.getValues();
+ HeaderElement[] encodings = transferEncodingHeader.getElements();
// The chunked encoding must be the last one applied
// RFC2616, 14.41
int len = encodings.length;
@@ -2655,20 +2655,16 @@
LOG.trace("enter getContentCharSet( Header contentheader )");
String charset = null;
if (contentheader != null) {
- try {
- HeaderElement values[] = contentheader.getValues();
- // I expect only one header element to be there
- // No more. no less
- if (values.length == 1) {
- NameValuePair param = values[0].getParameterByName("charset");
- if (param != null) {
- // If I get anything "funny"
- // UnsupportedEncondingException will result
- charset = param.getValue();
- }
+ HeaderElement values[] = contentheader.getElements();
+ // I expect only one header element to be there
+ // No more. no less
+ if (values.length == 1) {
+ NameValuePair param = values[0].getParameterByName("charset");
+ if (param != null) {
+ // If I get anything "funny"
+ // UnsupportedEncondingException will result
+ charset = param.getValue();
}
- } catch (HttpException e) {
- LOG.error(e);
}
}
if (charset == null) {
1.25 +9 -8 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java
Index: HttpState.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- HttpState.java 5 Jul 2003 22:31:20 -0000 1.24
+++ HttpState.java 13 Jul 2003 13:54:50 -0000 1.25
@@ -233,7 +233,7 @@
*
* @return an array of my {@link Cookie}s.
*
- * @see #getCookies(String, int, String, boolean, java.util.Date)
+ * @see #getCookies(String, int, String, boolean)
*
*/
public synchronized Cookie[] getCookies() {
@@ -251,9 +251,10 @@
* @param secure <code>true</code> when using HTTPS
* @return an array of my {@link Cookie}s.
*
- * @see Cookie#matches
* @see #getCookies()
*
+ * @deprecated Use {@link CookieSpec#match(String,int,String,boolean,Cookie)}
+ *
*/
public synchronized Cookie[] getCookies(
String domain,
@@ -455,8 +456,8 @@
* @param proxyHost the proxy host
* @param credentials the authentication credentials for the given realm
*
- * @see #getProxyCredentials(String)
- * @see #setCredentials(String, Credentials)
+ * @see #getProxyCredentials(String,String)
+ * @see #setCredentials(String, String, Credentials)
*
*/
public synchronized void setProxyCredentials(
1.10 +3 -3 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/package.html
Index: package.html
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/package.html,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- package.html 17 Dec 2002 02:41:38 -0000 1.9
+++ package.html 13 Jul 2003 13:54:50 -0000 1.10
@@ -82,12 +82,12 @@
<dd>
an enumeration of HttpStatus codes.
</dd>
- <dt>{@link org.apache.commons.httpclient.RequestOutputStream}</dt>
+ <dt>{@link org.apache.commons.httpclient.ChunkedOutputStream}</dt>
<dd>
an {@link java.io.OutputStream} wrapper supporting the "chunked"
transfer encoding.
</dd>
- <dt>{@link org.apache.commons.httpclient.ResponseInputStream}</dt>
+ <dt>{@link org.apache.commons.httpclient.ChunkedInputStream}</dt>
<dd>
an {@link java.io.InputStream} wrapper supporting the "chunked"
transfer encoding.
1.5 +21 -113 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthChallengeParser.java
Index: AuthChallengeParser.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthChallengeParser.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- AuthChallengeParser.java 6 Apr 2003 22:31:53 -0000 1.4
+++ AuthChallengeParser.java 13 Jul 2003 13:54:51 -0000 1.5
@@ -63,8 +63,12 @@
package org.apache.commons.httpclient.auth;
-import java.util.Map;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.util.ParameterParser;
/**
* This class provides utility methods for parsing HTTP www and proxy authentication
@@ -92,12 +96,12 @@
if (challengeStr == null) {
throw new IllegalArgumentException("Challenge may not be null");
}
- int i = challengeStr.indexOf(' ');
+ int idx = challengeStr.indexOf(' ');
String s = null;
- if (i == -1) {
+ if (idx == -1) {
s = challengeStr;
} else {
- s = challengeStr.substring(0, i);
+ s = challengeStr.substring(0, idx);
}
if (s.equals("")) {
throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
@@ -121,114 +125,18 @@
if (challengeStr == null) {
throw new IllegalArgumentException("Challenge may not be null");
}
- int i = challengeStr.indexOf(' ');
- if (i == -1) {
+ int idx = challengeStr.indexOf(' ');
+ if (idx == -1) {
throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
}
-
- Map elements = new HashMap();
-
- i++;
- int len = challengeStr.length();
-
- String name = null;
- String value = null;
-
- StringBuffer buffer = new StringBuffer();
-
- boolean parsingName = true;
- boolean inQuote = false;
- boolean gotIt = false;
-
- while (i < len) {
- // Parse one char at a time
- char ch = challengeStr.charAt(i);
- i++;
- // Process the char
- if (parsingName) {
- // parsing name
- if (ch == '=') {
- name = buffer.toString().trim();
- parsingName = false;
- buffer.setLength(0);
- } else if (ch == ',') {
- name = buffer.toString().trim();
- value = null;
- gotIt = true;
- buffer.setLength(0);
- } else {
- buffer.append(ch);
- }
- // Have I reached the end of the challenge string?
- if (i == len) {
- name = buffer.toString().trim();
- value = null;
- gotIt = true;
- }
- } else {
- //parsing value
- if (!inQuote) {
- // Value is not quoted or not found yet
- if (ch == ',') {
- value = buffer.toString().trim();
- gotIt = true;
- buffer.setLength(0);
- } else {
- // no value yet
- if (buffer.length() == 0) {
- if (ch == ' ') {
- //discard
- } else if (ch == '\t') {
- //discard
- } else if (ch == '\n') {
- //discard
- } else if (ch == '\r') {
- //discard
- } else {
- // otherwise add to the buffer
- buffer.append(ch);
- if (ch == '"') {
- inQuote = true;
- }
- }
- } else {
- // already got something
- // just keep on adding to the buffer
- buffer.append(ch);
- }
- }
- } else {
- // Value is quoted
- // Keep on adding until closing quote is encountered
- buffer.append(ch);
- if (ch == '"') {
- inQuote = false;
- }
- }
- // Have I reached the end of the challenge string?
- if (i == len) {
- value = buffer.toString().trim();
- gotIt = true;
- }
- }
- if (gotIt) {
- // Got something
- if ((name == null) || (name.equals(""))) {
- throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
- }
- // Strip quotes when present
- if ((value != null) && (value.length() > 1)) {
- if ((value.charAt(0) == '"')
- && (value.charAt(value.length() - 1) == '"')) {
- value = value.substring(1, value.length() - 1);
- }
- }
-
- elements.put(name, value);
- parsingName = true;
- gotIt = false;
- }
+ Map map = new HashMap();
+ ParameterParser parser = new ParameterParser();
+ List params = parser.parse(
+ challengeStr.substring(idx + 1, challengeStr.length()), ',');
+ for (int i = 0; i < params.size(); i++) {
+ NameValuePair param = (NameValuePair)params.get(i);
+ map.put(param.getName().toLowerCase(), param.getValue());
}
- return elements;
+ return map;
}
}
1.8 +6 -6 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java
Index: HttpAuthenticator.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- HttpAuthenticator.java 26 May 2003 22:07:22 -0000 1.7
+++ HttpAuthenticator.java 13 Jul 2003 13:54:51 -0000 1.8
@@ -261,7 +261,7 @@
*
* @throws AuthenticationException when a parsing or other error occurs
- * @see HttpState#setCredentials(String,Credentials)
+ * @see HttpState#setCredentials(String,String,Credentials)
*/
public static boolean authenticateProxyDefault(
HttpMethod method,
@@ -342,7 +342,7 @@
*
* @throws AuthenticationException when a parsing or other error occurs
- * @see HttpState#setCredentials(String,Credentials)
+ * @see HttpState#setCredentials(String,String,Credentials)
*/
public static boolean authenticate(
AuthScheme authscheme,
@@ -374,7 +374,7 @@
*
* @throws AuthenticationException when a parsing or other error occurs
- * @see HttpState#setCredentials(String,Credentials)
+ * @see HttpState#setCredentials(String,String,Credentials)
*/
public static boolean authenticateProxy(
AuthScheme authscheme,
1.17 +29 -20 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/CookieSpecBase.java
Index: CookieSpecBase.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/CookieSpecBase.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- CookieSpecBase.java 12 Jun 2003 19:12:16 -0000 1.16
+++ CookieSpecBase.java 13 Jul 2003 13:54:51 -0000 1.17
@@ -70,7 +70,6 @@
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HeaderElement;
-import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.util.DateParseException;
import org.apache.commons.httpclient.util.DateParser;
@@ -166,14 +165,7 @@
path = PATH_DELIM;
}
host = host.toLowerCase();
-
- HeaderElement[] headerElements = null;
- try {
- headerElements = HeaderElement.parse(header);
- } catch (HttpException e) {
- throw new MalformedCookieException(e.getMessage());
- }
-
+
String defaultPath = path;
int lastSlashIndex = defaultPath.lastIndexOf(PATH_DELIM);
if (lastSlashIndex >= 0) {
@@ -183,6 +175,31 @@
}
defaultPath = defaultPath.substring(0, lastSlashIndex);
}
+
+ HeaderElement[] headerElements = null;
+
+ boolean isNetscapeCookie = false;
+ int i1 = header.toLowerCase().indexOf("expires=");
+ if (i1 != -1) {
+ i1 += "expires=".length();
+ int i2 = header.indexOf(";", i1);
+ if (i2 == -1) {
+ i2 = header.length();
+ }
+ try {
+ DateParser.parseDate(header.substring(i1, i2));
+ isNetscapeCookie = true;
+ } catch(DateParseException e) {
+ // Does not look like a valid expiry date
+ }
+ }
+ if (isNetscapeCookie) {
+ headerElements = new HeaderElement[] {
+ new HeaderElement(header.toCharArray())
+ };
+ } else {
+ headerElements = HeaderElement.parseElements(header.toCharArray());
+ }
Cookie[] cookies = new Cookie[headerElements.length];
@@ -330,14 +347,6 @@
if (paramValue == null) {
throw new MalformedCookieException(
"Missing value for expires attribute");
- }
- // trim single quotes around expiry if present
- // see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5279
- if (paramValue.length() > 1
- && paramValue.startsWith("'")
- && paramValue.endsWith("'")) {
- paramValue
- = paramValue.substring (1, paramValue.length() - 1);
}
try {
1.4 +12 -3 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/DateParser.java
Index: DateParser.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/DateParser.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- DateParser.java 26 May 2003 21:51:37 -0000 1.3
+++ DateParser.java 13 Jul 2003 13:54:51 -0000 1.4
@@ -144,6 +144,15 @@
if (dateValue == null) {
throw new IllegalArgumentException("dateValue is null");
}
+
+ // trim single quotes around date if present
+ // see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5279
+ if (dateValue.length() > 1
+ && dateValue.startsWith("'")
+ && dateValue.endsWith("'"))
+ {
+ dateValue = dateValue.substring (1, dateValue.length() - 1);
+ }
SimpleDateFormat dateParser = null;
1.1 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/ParameterParser.java
Index: ParameterParser.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.commons.httpclient.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.NameValuePair;
/**
* A simple parser intended to parse sequences of name/value pairs.
* Parameter values are exptected to be enclosed in quotes if they
* contain unsafe characters, such as '=' characters or separators.
* Parameter values are optional and can be omitted.
*
* <p>
* <code>param1 = value; param2 = "anything goes; really"; param3</code>
* </p>
*
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*/
public class ParameterParser {
/** String to be parsed */
private char[] chars = null;
/** Current position in the string */
private int pos = 0;
/** Maximum position in the string */
private int len = 0;
/** Start of a token */
private int i1 = 0;
/** End of a token */
private int i2 = 0;
/** Default ParameterParser constructor */
public ParameterParser() {
super();
}
/** Are there any characters left to parse? */
private boolean hasChar() {
return this.pos < this.len;
}
/** A helper method to process the parsed token. */
private String getToken(boolean quoted) {
// Trim leading white spaces
while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) {
i1++;
}
// Trim trailing white spaces
while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) {
i2--;
}
// Strip away quotes if necessary
if (quoted) {
if (((i2 - i1) >= 2) &&
(chars[i1] == '"') &&
(chars[i2 - 1] == '"') ) {
i1++;
i2--;
}
}
String result = null;
if (i2 > i1) {
result = new String(chars, i1, i2 - i1);
}
return result;
}
/** Is given character present in the array of characters? */
private boolean isOneOf(char ch, char[] charray) {
boolean result = false;
for (int i = 0; i < charray.length; i ++) {
if (ch == charray[i]) {
result = true;
break;
}
}
return result;
}
/** Parse out a token until any of the given terminators
* is encountered. */
private String parseToken(final char[] terminators) {
char ch;
i1 = pos;
i2 = pos;
while (hasChar()) {
ch = chars[pos];
if (isOneOf(ch, terminators)) {
break;
}
i2++;
pos++;
}
return getToken(false);
}
/** Parse out a token until any of the given terminators
* is encountered. Special characters in quoted tokens
* are escaped. */
private String parseQuotedToken(final char[] terminators) {
char ch;
i1 = pos;
i2 = pos;
boolean quoted = false;
while (hasChar()) {
ch = chars[pos];
if (!quoted && isOneOf(ch, terminators)) {
break;
}
if (ch == '"') {
quoted = !quoted;
}
i2++;
pos++;
}
return getToken(true);
}
/**
* Extracts a list of {@link NameValuePair}s from the given string.
*
* @param str the string that contains a sequence of name/value pairs
* @return a list of {@link NameValuePair}s
*
*/
public List parse(final String str, char separator) {
if (str == null) {
return new ArrayList();
}
return parse(str.toCharArray(), separator);
}
/**
* Extracts a list of {@link NameValuePair}s from the given array of
* characters.
*
* @param chars the array of characters that contains a sequence of
* name/value pairs
*
* @return a list of {@link NameValuePair}s
*/
public List parse(final char[] chars, char separator) {
if (chars == null) {
return new ArrayList();
}
return parse(chars, 0, chars.length, separator);
}
/**
* Extracts a list of {@link NameValuePair}s from the given array of
* characters.
*
* @param chars the array of characters that contains a sequence of
* name/value pairs
* @param offset - the initial offset.
* @param length - the length.
*
* @return a list of {@link NameValuePair}s
*/
public List parse(final char[] chars, int offset, int length, char separator) {
if (chars == null) {
return new ArrayList();
}
List params = new ArrayList();
this.chars = chars;
this.pos = offset;
this.len = length;
String paramName = null;
String paramValue = null;
boolean done = false;
while (hasChar()) {
paramName = parseToken(new char[] {'=', separator});
paramValue = null;
if (hasChar() && (chars[pos] == '=')) {
pos++; // skip '='
paramValue = parseQuotedToken(new char[] {separator});
}
if (hasChar() && (chars[pos] == separator)) {
pos++; // skip separator
}
if ((paramName != null) && (paramName.length() > 0)) {
params.add(new NameValuePair(paramName, paramValue));
}
}
return params;
}
}
1.6 +27 -6 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHeaderElement.java
Index: TestHeaderElement.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHeaderElement.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- TestHeaderElement.java 28 Jan 2003 04:40:23 -0000 1.5
+++ TestHeaderElement.java 13 Jul 2003 13:54:51 -0000 1.6
@@ -70,6 +70,7 @@
* @author Rodney Waldhoff
* @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
* @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
+ * @author <a href="mailto:oleg@ural.ru">oleg Kalnichevski</a>
* @version $Id$
*/
public class TestHeaderElement extends TestNVP {
@@ -108,7 +109,7 @@
// this is derived from the old main method in HeaderElement
String headerValue = "name1 = value1; name2; name3=\"value3\" , name4=value4; " +
"name5=value5, name6= ; name7 = value7; name8 = \" value8\"";
- HeaderElement[] elements = HeaderElement.parse(headerValue);
+ HeaderElement[] elements = HeaderElement.parseElements(headerValue);
// there are 3 elements
assertEquals(3,elements.length);
// 1st element
@@ -129,12 +130,32 @@
assertEquals("value5",elements[1].getParameters()[0].getValue());
// 3rd element
assertEquals("name6",elements[2].getName());
- assertTrue(null == elements[2].getValue());
+ assertEquals(null,elements[2].getValue());
// 3rd element has 2 getParameters()
assertEquals(2,elements[2].getParameters().length);
assertEquals("name7",elements[2].getParameters()[0].getName());
assertEquals("value7",elements[2].getParameters()[0].getValue());
assertEquals("name8",elements[2].getParameters()[1].getName());
assertEquals(" value8",elements[2].getParameters()[1].getValue());
+ }
+
+ public void testFringeCase1() throws Exception {
+ String headerValue = "name1 = value1,";
+ HeaderElement[] elements = HeaderElement.parseElements(headerValue);
+ assertEquals("Number of elements", 1, elements.length);
+ }
+
+
+ public void testFringeCase2() throws Exception {
+ String headerValue = "name1 = value1, ";
+ HeaderElement[] elements = HeaderElement.parseElements(headerValue);
+ assertEquals("Number of elements", 1, elements.length);
+ }
+
+
+ public void testFringeCase3() throws Exception {
+ String headerValue = ",, ,, ,";
+ HeaderElement[] elements = HeaderElement.parseElements(headerValue);
+ assertEquals("Number of elements", 0, elements.length);
}
}
1.23 +5 -4 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java
Index: TestNoHost.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- TestNoHost.java 17 Apr 2003 11:34:19 -0000 1.22
+++ TestNoHost.java 13 Jul 2003 13:54:51 -0000 1.23
@@ -87,6 +87,7 @@
suite.addTest(TestCookie.suite());
suite.addTest(TestNVP.suite());
suite.addTest(TestHeader.suite());
+ suite.addTest(TestParameterParser.suite());
suite.addTest(TestHeaderElement.suite());
suite.addTest(TestChallengeParser.suite());
suite.addTest(TestAuthenticator.suite());
1.1 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestParameterParser.java
Index: TestParameterParser.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.commons.httpclient;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.util.List;
import org.apache.commons.httpclient.util.ParameterParser;
/**
* Unit tests for {@link ParameterParser}.
*
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*/
public class TestParameterParser extends TestCase {
// ------------------------------------------------------------ Constructor
public TestParameterParser(String testName) {
super(testName);
}
// ------------------------------------------------------------------- Main
public static void main(String args[]) {
String[] testCaseName = { TestParameterParser.class.getName() };
junit.textui.TestRunner.main(testCaseName);
}
// ------------------------------------------------------- TestCase Methods
public static Test suite() {
return new TestSuite(TestParameterParser.class);
}
public void testParsing() {
String s =
"test; test1 = stuff ; test2 = \"stuff; stuff\"; test3=\"stuff";
ParameterParser parser = new ParameterParser();
List params = parser.parse(s, ';');
assertEquals("test", ((NameValuePair)params.get(0)).getName());
assertEquals(null, ((NameValuePair)params.get(0)).getValue());
assertEquals("test1", ((NameValuePair)params.get(1)).getName());
assertEquals("stuff", ((NameValuePair)params.get(1)).getValue());
assertEquals("test2", ((NameValuePair)params.get(2)).getName());
assertEquals("stuff; stuff", ((NameValuePair)params.get(2)).getValue());
assertEquals("test3", ((NameValuePair)params.get(3)).getName());
assertEquals("\"stuff", ((NameValuePair)params.get(3)).getValue());
s = " test , test1=stuff , , test2=, test3, ";
params = parser.parse(s, ',');
assertEquals("test", ((NameValuePair)params.get(0)).getName());
assertEquals(null, ((NameValuePair)params.get(0)).getValue());
assertEquals("test1", ((NameValuePair)params.get(1)).getName());
assertEquals("stuff", ((NameValuePair)params.get(1)).getValue());
assertEquals("test2", ((NameValuePair)params.get(2)).getName());
assertEquals(null, ((NameValuePair)params.get(2)).getValue());
assertEquals("test3", ((NameValuePair)params.get(3)).getName());
assertEquals(null, ((NameValuePair)params.get(3)).getValue());
s = " test";
params = parser.parse(s, ';');
assertEquals("test", ((NameValuePair)params.get(0)).getName());
assertEquals(null, ((NameValuePair)params.get(0)).getValue());
s = " ";
params = parser.parse(s, ';');
assertEquals(0, params.size());
s = " = stuff ";
params = parser.parse(s, ';');
assertEquals(0, params.size());
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org