001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package com.noelios.restlet.util;
020:
021: import java.io.IOException;
022:
023: import com.noelios.restlet.http.HttpUtils;
024:
025: /**
026: * HTTP-style header reader.
027: *
028: * @author Jerome Louvel (contact@noelios.com)
029: */
030: public class HeaderReader {
031: /** The header to read. */
032: private String header;
033:
034: /** The current read index (or -1 if not reading anymore). */
035: private int index;
036:
037: /**
038: * Constructor.
039: *
040: * @param header
041: * The header to read.
042: */
043: public HeaderReader(String header) {
044: this .header = header;
045: this .index = ((header == null) || (header.length() == 0)) ? -1
046: : 0;
047: }
048:
049: /**
050: * Reads the next character.
051: *
052: * @return The next character.
053: */
054: public int read() {
055: int result = -1;
056:
057: if (index != -1) {
058: result = this .header.charAt(index++);
059: if (index >= this .header.length())
060: index = -1;
061: }
062:
063: return result;
064: }
065:
066: /**
067: * Read the next value of a multi-value header. It skips separator commas
068: * and spaces.
069: *
070: * @see <a
071: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2">HTTP
072: * parsing rule</a>
073: * @return The next value or null.
074: */
075: public String readValue() {
076: StringBuilder sb = null;
077: int next = read();
078:
079: // Skip leading spaces
080: while ((next != -1) && isLinearWhiteSpace(next)) {
081: next = read();
082: }
083:
084: while ((next != -1) && !isValueSeparator(next)) {
085: if (sb == null)
086: sb = new StringBuilder();
087: sb.append((char) next);
088: next = read();
089: }
090:
091: // Remove trailing spaces
092: if (sb != null) {
093: for (int i = sb.length() - 1; (i >= 0)
094: && isLinearWhiteSpace(sb.charAt(i)); i--) {
095: sb.deleteCharAt(i);
096: }
097: }
098:
099: return (sb == null) ? null : sb.toString();
100: }
101:
102: /**
103: * Indicates if the given character is a value separator.
104: *
105: * @param character
106: * The character to test.
107: * @return True if the given character is a value separator.
108: */
109: protected boolean isValueSeparator(int character) {
110: return (character == ',');
111: }
112:
113: /**
114: * Indicates if the given character is a value separator.
115: *
116: * @param character
117: * The character to test.
118: * @return True if the given character is a value separator.
119: */
120: protected boolean isLinearWhiteSpace(int character) {
121: return (HttpUtils.isCarriageReturn(character)
122: || HttpUtils.isSpace(character)
123: || HttpUtils.isLineFeed(character) || HttpUtils
124: .isHorizontalTab(character));
125: }
126:
127: /**
128: * Reads the next quoted string.
129: *
130: * @return The next quoted string.
131: * @throws IOException
132: */
133: protected String readQuotedString() throws IOException {
134: StringBuilder sb = new StringBuilder();
135: appendQuotedString(sb);
136: return sb.toString();
137: }
138:
139: /**
140: * Appends the next quoted string.
141: *
142: * @param buffer
143: * The buffer to append.
144: * @throws IOException
145: */
146: protected void appendQuotedString(Appendable buffer)
147: throws IOException {
148: boolean done = false;
149: boolean quotedPair = false;
150: int nextChar = 0;
151:
152: while ((!done) && (nextChar != -1)) {
153: nextChar = read();
154:
155: if (quotedPair) {
156: // End of quoted pair (escape sequence)
157: if (HttpUtils.isText(nextChar)) {
158: buffer.append((char) nextChar);
159: quotedPair = false;
160: } else {
161: throw new IOException(
162: "Invalid character detected in quoted string. Please check your value");
163: }
164: } else if (HttpUtils.isDoubleQuote(nextChar)) {
165: // End of quoted string
166: done = true;
167: } else if (nextChar == '\\') {
168: // Begin of quoted pair (escape sequence)
169: quotedPair = true;
170: } else if (HttpUtils.isText(nextChar)) {
171: buffer.append((char) nextChar);
172: } else {
173: throw new IOException(
174: "Invalid character detected in quoted string. Please check your value");
175: }
176: }
177: }
178:
179: }
|