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

org.glassfish.grizzly.http2.EncoderUtils Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2014-2016 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.http2;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.util.Ascii;
import org.glassfish.grizzly.http.util.BufferChunk;
import org.glassfish.grizzly.http.util.ByteChunk;
import org.glassfish.grizzly.http.util.DataChunk;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.MimeHeaders;

import static org.glassfish.grizzly.http.util.DataChunk.Type.Buffer;
import static org.glassfish.grizzly.http.util.DataChunk.Type.Bytes;

import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.ssl.SSLUtils;

/**
 * HTTP Packet -> SpdyFrames encoder utils.
 * 
 * @author Grizzly team
 */
class EncoderUtils {
    private static final String HTTP = "http";
    private static final String HTTPS = "https";

    @SuppressWarnings("unchecked")
    static Buffer encodeResponseHeaders(final Http2Connection http2Connection,
            final HttpResponsePacket response) throws IOException {
        
        assert http2Connection.getDeflaterLock().isLocked();
        
        final MimeHeaders headers = response.getHeaders();
        
        headers.removeHeader(Header.Connection);
        headers.removeHeader(Header.KeepAlive);
        headers.removeHeader(Header.ProxyConnection);
        headers.removeHeader(Header.TransferEncoding);
        headers.removeHeader(Header.Upgrade);
        
        final HeadersEncoder encoder = http2Connection.getHeadersEncoder();

//        encoder.encodeHeader(Constants.STATUS_HEADER_BYTES,
//                response.getHttpStatus().getStatusBytes(), false);
        
        encoder.encodeHeader(Constants.STATUS_HEADER,
                String.valueOf(response.getHttpStatus().getStatusCode()));

        encodeUserHeaders(headers, encoder);

        return encoder.flushHeaders();
    }
    
    @SuppressWarnings("unchecked")
    static Buffer encodeRequestHeaders(
            final Http2Connection http2Connection,
            final HttpRequestPacket request) throws IOException {

        assert http2Connection.getDeflaterLock().isLocked();
        
        // ----------------- Parse URI scheme and path ----------------
//        int schemeStart = -1;
//        int schemeLen = -1;
//
//        final byte[] requestURI =
//                request.getRequestURI().getBytes(DEFAULT_HTTP_CHARACTER_ENCODING);
//        final int len = requestURI.length;
//
//        final int nonSpaceIdx = skipSpaces(requestURI, 0, len, len);
//        final int idx = ByteChunk.indexOf(requestURI, nonSpaceIdx, len, '/');
//
//        if (idx > 0 && idx < len - 1 &&
//                requestURI[idx - 1] == ':' && requestURI[idx + 1] == '/') {
//            schemeStart = nonSpaceIdx;
//            schemeLen = idx - schemeStart - 1;
//        }
//
//        
//        final int pathStart = schemeStart == -1 ?
//                idx :
//                ByteChunk.indexOf(requestURI, idx + 2, len, '/');
//        final int pathLen = len - pathStart;
//
//        if (pathStart == -1) {
//            throw new IllegalStateException("Request URI path is not set");
//        }
        
        int schemeStart = -1;
        int schemeLen = -1;

        final String requestURI = request.getRequestURI().trim();
        
        final int len = requestURI.length();

        final int idx = requestURI.indexOf('/');

        if (idx > 0 && idx < len - 1 &&
                requestURI.charAt(idx - 1) == ':' && requestURI.charAt(idx + 1) == '/') {
            schemeStart = 0;
            schemeLen = idx - 1;
        }

        
        final int pathStart = schemeStart == -1 ?
                idx :
                requestURI.indexOf('/', idx + 2);
        final int pathLen = len - pathStart;

        if (pathStart == -1) {
            throw new IllegalStateException("Request URI path is not set");
        }
        
// ---------------------------------------------------------------

        final MimeHeaders headers = request.getHeaders();
        
        String hostHeader = headers.getHeader(Header.Host);
        
        if (hostHeader == null) {
            if (schemeStart == -1) {
                throw new IllegalStateException("Missing the Host header");
            }

            hostHeader = requestURI.substring(schemeStart + schemeLen + 3, pathStart);
        }
        
        headers.removeHeader(Header.Connection);
        headers.removeHeader(Header.Host);
        headers.removeHeader(Header.KeepAlive);
        headers.removeHeader(Header.ProxyConnection);
        headers.removeHeader(Header.TransferEncoding);
        headers.removeHeader(Header.Upgrade);
        
        final HeadersEncoder encoder = http2Connection.getHeadersEncoder();

        encoder.encodeHeader(Constants.METHOD_HEADER,
                request.getMethod().toString());

        if (schemeLen > 0) {
            encoder.encodeHeader(Constants.SCHEMA_HEADER,
                    requestURI.substring(0, schemeLen));
        } else {
            // guess
            encoder.encodeHeader(Constants.SCHEMA_HEADER,
                    ((SSLUtils.getSSLEngine(http2Connection.getConnection()) == null)
                    ? HTTP
                    : HTTPS));
        }

        encoder.encodeHeader(Constants.AUTHORITY_HEADER, hostHeader);

        encoder.encodeHeader(Constants.PATH_HEADER,
                (pathLen == requestURI.length())
                    ? requestURI
                    : requestURI.substring(pathStart, pathStart + pathLen));
        
//        encoder.encodeHeader(Constants.METHOD_HEADER_BYTES,
//                request.getMethod().getMethodBytes(), false);
//
//        if (schemeLen > 0) {
//            encoder.encodeHeader(Constants.SCHEMA_HEADER_BYTES,
//                    Arrays.copyOfRange(requestURI, schemeStart,
//                            schemeStart + schemeLen), false);
//        } else {
//            encoder.encodeHeader(Constants.SCHEMA_HEADER_BYTES,
//                    ((SSLUtils.getSSLEngine(http2Connection.getConnection()) == null)
//                    ? HTTP_BYTES
//                    : HTTPS_BYTES),
//                    false);
//        }
//
//        encoder.encodeHeader(Constants.AUTHORITY_HEADER_BYTES,
//                (hostHeaderLen == hostHeaderBytes.length)
//                    ? hostHeaderBytes
//                    : Arrays.copyOfRange(hostHeaderBytes, hostHeaderStart, hostHeaderStart + hostHeaderLen),
//                false);
//
//        encoder.encodeHeader(Constants.PATH_HEADER_BYTES,
//                (pathLen == requestURI.length)
//                    ? requestURI
//                    : Arrays.copyOfRange(requestURI, pathStart, pathStart + pathLen),
//                false);

        encodeUserHeaders(headers, encoder);

        return encoder.flushHeaders();
    }

    @SuppressWarnings("unchecked")
    private static void encodeUserHeaders(final MimeHeaders headers,
            final HeadersEncoder encoder) throws IOException {
        
        final int mimeHeadersCount = headers.size();
        List tmpList = null;
        
        for (int i = 0; i < mimeHeadersCount; i++) {
            int valueSize = 0;
        
            if (!headers.setSerialized(i, true)) {
                final DataChunk name = headers.getName(i);
                
                if (name.isNull() || name.getLength() == 0) {
                    continue;
                }
                
                final DataChunk value1 = headers.getValue(i);
                
                for (int j = i; j < mimeHeadersCount; j++) {
                    if (!headers.isSerialized(j) &&
                            name.equalsIgnoreCase(headers.getName(j))) {
                        headers.setSerialized(j, true);
                        final DataChunk value = headers.getValue(j);
                        if (!value.isNull()) {
                            if (tmpList == null) {
                                tmpList = new ArrayList<>(2);
                                if (!value1.isNull()) {
                                    tmpList.add(value1);
                                    valueSize += value1.getLength();
                                }
                            }
                            tmpList.add(value);
                            valueSize += value.getLength();
                        }
                    }
                }
                
////                encodeDataChunkWithLenPrefixLowerCase(encoder, headers.getName(i));
//                final byte[] nameBytes = nameToLowerCaseByteArray(headers.getName(i));
//                final byte[] valueBytes;
//                if (tmpList != null && !tmpList.isEmpty()) {
//                    final int valuesCount = tmpList.size();
//                    
//                    valueSize += valuesCount - 1; // 0 delims
//                    
//                    valueBytes = new byte[valueSize];
//                    int offs = 0;
//                    for (int j = 0; j < valuesCount; j++) {
//                        offs += valueToByteArray(tmpList.get(j), valueBytes, offs);
//                        offs++; // 0 delim
//                    }
//                    
//                    tmpList.clear();
//                } else {
//                    valueBytes = valueToByteArray(value1);
//                }
//                
//                encoder.encodeHeader(nameBytes, valueBytes, false);

                final String nameStr = nameToLowerCase(name);
                
                String valueStr;
                if (tmpList != null && !tmpList.isEmpty()) {
                    final int valuesCount = tmpList.size();
                    
                    valueSize += valuesCount - 1; // 0 delims
                    
                    final StringBuilder sb = new StringBuilder(valueSize);
                    int j = 0;
                    
                    for (;j < valuesCount - 1; j++) {
                        sb.append(tmpList.get(j).toString());
                        sb.append('\u0000');
                    }
                    
                    sb.append(tmpList.get(j).toString());
                    
                    valueStr = sb.toString();
                    tmpList.clear();
                } else {
                    valueStr = value1.toString();
                }
                
                encoder.encodeHeader(nameStr, valueStr);
            
            }
        }
    }
    
    @SuppressWarnings("unused")
    private static byte[] nameToLowerCaseByteArray(final DataChunk name) {
        final int length = name.getLength();
        final byte[] lowercase = new byte[length];
        
        if (name.getType() == Bytes) {
            final ByteChunk byteChunk = name.getByteChunk();
            final byte[] bytes = byteChunk.getBuffer();
            final int offs = byteChunk.getStart();
            for (int i = 0; i < length; i++) {
                lowercase[i] = (byte) Ascii.toLower(bytes[i + offs]);
            }
        } else if (name.getType() == Buffer) {
            final BufferChunk bufferChunk = name.getBufferChunk();
            final Buffer buffer = bufferChunk.getBuffer();
            final int offs = bufferChunk.getStart();
            for (int i = 0; i < length; i++) {
                lowercase[i] = (byte) Ascii.toLower(buffer.get(i + offs));
            }
        } else {
            final String s = name.toString();
            for (int i = 0; i < length; i++) {
                lowercase[i] = (byte) Ascii.toLower(s.charAt(i));
            }
        }
        
        return lowercase;
    }

    private static String nameToLowerCase(final DataChunk name) {
        final int length = name.getLength();
        final StringBuilder sb = new StringBuilder(length);
        
        if (name.getType() == Bytes) {
            final ByteChunk byteChunk = name.getByteChunk();
            final byte[] bytes = byteChunk.getBuffer();
            final int offs = byteChunk.getStart();
            for (int i = 0; i < length; i++) {
                sb.append((char) Ascii.toLower(bytes[i + offs]));
            }
        } else if (name.getType() == Buffer) {
            final BufferChunk bufferChunk = name.getBufferChunk();
            final Buffer buffer = bufferChunk.getBuffer();
            final int offs = bufferChunk.getStart();
            for (int i = 0; i < length; i++) {
                sb.append((char) Ascii.toLower(buffer.get(i + offs)));
            }
        } else {
            final String s = name.toString();
            for (int i = 0; i < length; i++) {
                sb.append((char) Ascii.toLower(s.charAt(i)));
            }
        }
        
        return sb.toString();
    }
    
    @SuppressWarnings("unused")
    private static int valueToByteArray(final DataChunk value,
                                        final byte[] dstArray, int arrayOffs) {
        
        final int length = value.getLength();

        if (value.getType() == Bytes) {
            final ByteChunk byteChunk = value.getByteChunk();
            final byte[] bytes = byteChunk.getBuffer();
            final int offs = byteChunk.getStart();
            System.arraycopy(bytes, offs, dstArray, arrayOffs, length);
        } else if (value.getType() == Buffer) {
            final BufferChunk bufferChunk = value.getBufferChunk();
            final Buffer buffer = bufferChunk.getBuffer();
            final int offs = bufferChunk.getStart();
            
            final int oldPos = buffer.position();
            final int oldLim = buffer.limit();
            
            Buffers.setPositionLimit(buffer, offs, offs + length);
            buffer.get(dstArray, arrayOffs, length);
            Buffers.setPositionLimit(buffer, oldPos, oldLim);
        } else {
            final String s = value.toString();
            for (int i = 0; i < length; i++) {
                dstArray[arrayOffs + i] = (byte) s.charAt(i);
            }
        }
        
        return length;
    }

    @SuppressWarnings("unused")
    private static byte[] valueToByteArray(final DataChunk value) {
        final int length = value.getLength();

        if (value.getType() == Bytes) {
            final ByteChunk byteChunk = value.getByteChunk();
            final byte[] bytes = byteChunk.getBuffer();
            final int offs = byteChunk.getStart();
            
            if (bytes.length == length) {
                return bytes;
            }
            
            final byte[] dstArray = new byte[length];
            System.arraycopy(bytes, offs, dstArray, 0, length);
            return dstArray;
        } else if (value.getType() == Buffer) {
            final BufferChunk bufferChunk = value.getBufferChunk();
            final Buffer buffer = bufferChunk.getBuffer();
            
            if (buffer.hasArray() && buffer.array().length == length) {
                return buffer.array();
            }
            
            final byte[] dstArray = new byte[length];
            final int offs = bufferChunk.getStart();
            
            final int oldPos = buffer.position();
            final int oldLim = buffer.limit();
            
            Buffers.setPositionLimit(buffer, offs, offs + length);
            buffer.get(dstArray);
            Buffers.setPositionLimit(buffer, oldPos, oldLim);
            return dstArray;
        } else {
            final byte[] dstArray = new byte[length];
            final String s = value.toString();
            for (int i = 0; i < length; i++) {
                dstArray[i] = (byte) s.charAt(i);
            }
            
            return dstArray;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy