View Javadoc
1 /* Reattore HTTP Server 2 3 Copyright (C) 2002 Michael Hope <michaelh@juju.net.nz> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19 $Id: StartLineParser.java,v 1.6 2003/02/22 04:29:52 michaelh Exp $ 20 */ 21 22 package juju.reattore.protocol.http.impl; 23 24 import java.util.*; 25 import java.io.IOException; 26 27 import juju.reattore.io.impl.*; 28 import juju.reattore.io.ByteSource; 29 import juju.reattore.protocol.http.ParseException; 30 import juju.reattore.util.CharUtil; 31 32 import org.apache.commons.logging.*; 33 34 /*** Parses a HTTP start (request/response) line. 35 36 @todo Minor/Strict: Doesn't detect invalid leading spaces. 37 */ 38 public class StartLineParser { 39 40 private static Log log = LogFactory.getLog(StartLineParser.class); 41 42 private StringBuffer method; 43 private StringBuffer path; 44 private StringBuffer query; 45 private StringBuffer version; 46 47 private static final int IN_SP = 0; 48 private static final int IN_METHOD = 1; 49 private static final int IN_PATH = 2; 50 private static final int IN_QUERY = 3; 51 private static final int IN_ENCODED_1 = 4; 52 private static final int IN_ENCODED_2 = 5; 53 private static final int IN_VERSION = 6; 54 private static final int IN_EOL = 7; 55 private static final int IN_RESET = 8; 56 57 private int state = IN_RESET; 58 private int nextState; 59 60 private Callback callback; 61 62 private int encVal; 63 private StringBuffer encTo; 64 65 /*** May be used to generate events on the end of parse instead of 66 being data driven. Register using #setCallback 67 */ 68 public interface Callback { 69 /*** Called when a line has been parsed. 70 71 @param method The parsed method 72 @param path The parsed path 73 @param query The parsed query 74 @param version The parsed version 75 */ 76 void onStartLine(String method, String path, String query, 77 String version); 78 }; 79 80 /*** Sets what to call when a line has been parsed. 81 82 @param callback The class to call, or null to disable. 83 */ 84 public void setCallback(Callback callback) { 85 this.callback = callback; 86 } 87 88 /*** Parse the line. 89 90 @param in Source to parse from 91 @return false means more parsing needed 92 @throws ParseException if an error occurs while parsing. 93 @throws IOException on error. 94 */ 95 public boolean add(PushbackByteSource in) 96 throws ParseException, IOException { 97 98 int got; 99 100 if (state == IN_RESET) { 101 reset(); 102 } 103 104 while ((got = in.get()) != PushbackByteSource.EOF) { 105 switch (state) { 106 case IN_SP: 107 switch (got) { 108 case ' ': 109 break; 110 default: 111 in.pushback(got); 112 state = nextState; 113 break; 114 } 115 break; 116 case IN_METHOD: 117 switch (got) { 118 case ' ': 119 state = IN_SP; 120 nextState = IN_PATH; 121 break; 122 default: 123 method.append((char)got); 124 break; 125 } 126 break; 127 case IN_PATH: 128 switch (got) { 129 case '\r': 130 state = IN_EOL; 131 break; 132 case '%': 133 encTo = path; 134 nextState = state; 135 state = IN_ENCODED_1; 136 break; 137 case ' ': 138 state = IN_SP; 139 nextState = IN_VERSION; 140 break; 141 case '?': 142 state = IN_QUERY; 143 break; 144 default: 145 path.append((char)got); 146 break; 147 } 148 break; 149 case IN_QUERY: 150 switch (got) { 151 case '\r': 152 state = IN_EOL; 153 break; 154 case '%': 155 encTo = query; 156 nextState = state; 157 state = IN_ENCODED_1; 158 break; 159 case ' ': 160 state = IN_SP; 161 nextState = IN_VERSION; 162 break; 163 case '+': 164 query.append(' '); 165 break; 166 default: 167 query.append((char)got); 168 break; 169 } 170 break; 171 case IN_ENCODED_1: 172 encVal = CharUtil.fromNibble(got) * 16; 173 state = IN_ENCODED_2; 174 break; 175 case IN_ENCODED_2: 176 encTo.append((char)(CharUtil.fromNibble(got) + encVal)); 177 state = nextState; 178 break; 179 case IN_VERSION: 180 switch (got) { 181 case '\r': 182 state = IN_EOL; 183 break; 184 default: 185 version.append((char)got); 186 break; 187 } 188 break; 189 case IN_EOL: 190 switch (got) { 191 case '\n': 192 runCallback(); 193 state = IN_RESET; 194 return true; 195 default: 196 throw new ParseException(); 197 } 198 default: 199 throw new ParseException(); 200 } 201 } 202 203 return false; 204 } 205 206 private void runCallback() { 207 if (callback != null) { 208 callback.onStartLine(method.toString(), 209 path.toString(), 210 query.toString(), 211 version.toString()); 212 } 213 } 214 215 /*** Resets back to a clean state. 216 */ 217 public void reset() { 218 method = new StringBuffer(); 219 path = new StringBuffer(); 220 query = new StringBuffer(); 221 version = new StringBuffer(); 222 223 state = IN_SP; 224 nextState = IN_METHOD; 225 } 226 227 /*** Gets the parsed method. 228 229 @return The parsed value, or "" if none. 230 */ 231 public String getMethod() { 232 return method.toString(); 233 } 234 235 /*** Gets the parsed path. 236 237 @return The parsed value, or "" if none. 238 */ 239 public String getPath() { 240 return path.toString(); 241 } 242 243 /*** Gets the parsed query. 244 245 @return The parsed value, or "" if none. 246 */ 247 public String getQuery() { 248 return query.toString(); 249 } 250 251 /*** Gets the parsed version. 252 253 @return The parsed value, or "" if none. 254 */ 255 public String getVersion() { 256 return version.toString(); 257 } 258 }

This page was automatically generated by Maven