Package juju.reattore.protocol.http.impl

Source Code of juju.reattore.protocol.http.impl.StartLineParser$Callback

/*  Reattore HTTP Server

    Copyright (C) 2002 Michael Hope <michaelh@juju.net.nz>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    $Id: StartLineParser.java,v 1.6 2003/02/22 04:29:52 michaelh Exp $
*/

package juju.reattore.protocol.http.impl;

import java.util.*;
import java.io.IOException;

import juju.reattore.io.impl.*;
import juju.reattore.io.ByteSource;
import juju.reattore.protocol.http.ParseException;
import juju.reattore.util.CharUtil;

import org.apache.commons.logging.*;

/** Parses a HTTP start (request/response) line.

   @todo Minor/Strict: Doesn't detect invalid leading spaces.
*/
public class StartLineParser {

    private static Log log = LogFactory.getLog(StartLineParser.class);

    private StringBuffer method;
    private StringBuffer path;
    private StringBuffer query;
    private StringBuffer version;

    private static final int IN_SP = 0;
    private static final int IN_METHOD = 1;
    private static final int IN_PATH = 2;
    private static final int IN_QUERY = 3;
    private static final int IN_ENCODED_1 = 4;
    private static final int IN_ENCODED_2 = 5;
    private static final int IN_VERSION = 6;
    private static final int IN_EOL = 7;
    private static final int IN_RESET = 8;

    private int state = IN_RESET;
    private int nextState;

    private Callback callback;

    private int encVal;
    private StringBuffer encTo;

    /** May be used to generate events on the end of parse instead of
        being data driven.  Register using #setCallback
    */
    public interface Callback {
        /** Called when a line has been parsed.

            @param method  The parsed method
            @param path  The parsed path
            @param query  The parsed query
            @param version  The parsed version
        */
        void onStartLine(String method, String path, String query,
                         String version);
    };

    /** Sets what to call when a line has been parsed.

        @param callback  The class to call, or null to disable.
     */
    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    /** Parse the line.
       
        @param in  Source to parse from
        @return false means more parsing needed
        @throws ParseException if an error occurs while parsing.
        @throws IOException on error.
    */
    public boolean add(PushbackByteSource in)
        throws ParseException, IOException {

        int got;

        if (state == IN_RESET) {
            reset();
        }

        while ((got = in.get()) != PushbackByteSource.EOF) {
            switch (state) {
            case IN_SP:
                switch (got) {
                case ' ':
                    break;
                default:
                    in.pushback(got);
                    state = nextState;
                    break;
                }
                break;
            case IN_METHOD:
                switch (got) {
                case ' ':
                    state = IN_SP;
                    nextState = IN_PATH;
                    break;
                default:
                    method.append((char)got);
                    break;
                }
                break;
            case IN_PATH:
                switch (got) {
                case '\r':
                    state = IN_EOL;
                    break;
                case '%':
                    encTo = path;
                    nextState = state;
                    state = IN_ENCODED_1;
                    break;
                case ' ':
                    state = IN_SP;
                    nextState = IN_VERSION;
                    break;
                case '?':
                    state = IN_QUERY;
                    break;
                default:
                    path.append((char)got);
                    break;
                }
                break;
            case IN_QUERY:
                switch (got) {
                case '\r':
                    state = IN_EOL;
                    break;
                case '%':
                    encTo = query;
                    nextState = state;
                    state = IN_ENCODED_1;
                    break;
                case ' ':
                    state = IN_SP;
                    nextState = IN_VERSION;
                    break;
                case '+':
                    query.append(' ');
                    break;
                default:
                    query.append((char)got);
                    break;
                }
                break;
            case IN_ENCODED_1:
                encVal = CharUtil.fromNibble(got) * 16;
                state = IN_ENCODED_2;
                break;
            case IN_ENCODED_2:
                encTo.append((char)(CharUtil.fromNibble(got) + encVal));
                state = nextState;
                break;
            case IN_VERSION:
                switch (got) {
                case '\r':
                    state = IN_EOL;
                    break;
                default:
                    version.append((char)got);
                    break;
                }
                break;
            case IN_EOL:
                switch (got) {
                case '\n':
                    runCallback();
                    state = IN_RESET;
                    return true;
                default:
                    throw new ParseException();
                }
            default:
                throw new ParseException();
            }
        }

        return false;
    }

    private void runCallback() {
        if (callback != null) {
            callback.onStartLine(method.toString(),
                                 path.toString(),
                                 query.toString(),
                                 version.toString());
        }
    }

    /** Resets back to a clean state.
     */
    public void reset() {
        method = new StringBuffer();
        path = new StringBuffer();
        query = new StringBuffer();
        version = new StringBuffer();

        state = IN_SP;
        nextState = IN_METHOD;
    }

    /** Gets the parsed method.

        @return The parsed value, or "" if none.
    */
    public String getMethod() {
        return method.toString();
    }

    /** Gets the parsed path.

        @return The parsed value, or "" if none.
    */
    public String getPath() {
        return path.toString();
    }

    /** Gets the parsed query.

        @return The parsed value, or "" if none.
    */
    public String getQuery() {
        return query.toString();
    }

    /** Gets the parsed version.

        @return The parsed value, or "" if none.
    */
    public String getVersion() {
        return version.toString();
    }
}
TOP

Related Classes of juju.reattore.protocol.http.impl.StartLineParser$Callback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.