All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.grizzly.config.portunif.HttpProtocolFinder Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2007-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.grizzly.config.portunif;

import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.attributes.Attribute;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.portunif.PUContext;
import org.glassfish.grizzly.portunif.ProtocolFinder;

/**
 * A {@link ProtocolFinder} implementation that parse the available
 * SocketChannel bytes looking for the 'http' bytes. An http request will
 * always has the form of:
 *
 * METHOD URI PROTOCOL/VERSION
 *
 * example: GET / HTTP/1.1
 *
 * The algorithm will try to find the protocol token. 
 *
 * @author Jeanfrancois Arcand
 * @author Alexey Stashok
 */
public class HttpProtocolFinder implements ProtocolFinder {
    private static final char[] METHOD_FIRST_LETTERS = new char[] {'G', 'P', 'O', 'H', 'D', 'T', 'C'};
    private final Attribute parsingStateAttribute =
            Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(
                    HttpProtocolFinder.class + "-" + hashCode()
                            + ".parsingStateAttribute");

    private final int maxRequestLineSize;

    public HttpProtocolFinder() {
        this(2048);
    }

    public HttpProtocolFinder(int maxRequestLineSize) {
        this.maxRequestLineSize = maxRequestLineSize;
    }

    @Override
    public Result find(final PUContext puContext, final FilterChainContext ctx) {
        final Connection connection = ctx.getConnection();
        final Buffer buffer = ctx.getMessage();

        final ParsingState parsingState = parsingStateAttribute.get(connection);

        final int limit = buffer.limit();

        int position;
        int state;

        if (parsingState == null) {
            position = buffer.position();
            state = 0;
        } else {
            position = parsingState.position;
            state = parsingState.state;
        }
        
        byte c = 0;
        byte c2;

        // Rule b - try to determine the context-root
        while (position < limit) {
            c2 = c;
            c = buffer.get(position++);
            // State Machine
            // 0 - Search for the first SPACE ' ' between the method and the
            //     the request URI
            // 1 - Search for the second SPACE ' ' between the request URI
            //     and the method
            _1:
            switch (state) {
                case 0:
                    // Check method name
                    for (int i = 0; i < METHOD_FIRST_LETTERS.length; i++) {
                        if (c == METHOD_FIRST_LETTERS[i]) {
                            state = 1;
                            break _1;
                        }
                    }
                    
                    return Result.NOT_FOUND;
                case 1:
                    // Search for first ' '
                    if (c == 0x20) {
                        state = 2;
                    }
                    break;
                case 2:
                    // Search for next ' '
                    if (c == 0x20) {
                        state = 3;
                    }
                    break;
                case 3:
                    // Check 'H' part of HTTP/
                    if (c == 'H') {
                        state = 4;
                        break;
                    }
                    return Result.NOT_FOUND;

                case 4:
                    // Search for P/ (part of HTTP/)
                    if (c == 0x2f && c2 == 'P') {
                        // find SSL preprocessor
                        if (parsingState != null) {
                            parsingStateAttribute.remove(connection);
                        }
                        
                        return Result.FOUND;
                    }
                    break;
                default:
                    return Result.NOT_FOUND;
            }
        }

        if (position >= maxRequestLineSize) {
            return Result.NOT_FOUND;
        }
        
        if (parsingState == null) {
            parsingStateAttribute.set(connection, new ParsingState(position, state));
        } else {
            parsingState.position = position;
            parsingState.state = state;
        }
        
        return Result.NEED_MORE_DATA;
    }

    private static final class ParsingState {
        int position;
        int state;

        public ParsingState(int position, int state) {
            this.position = position;
            this.state = state;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy