Search in sources :

Example 1 with NotEnoughDataDecoderException

use of io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException in project netty by netty.

the class HttpPostMultipartRequestDecoder method findMultipartDisposition.

/**
     * Find the next Disposition
     *
     * @return the next InterfaceHttpData if any
     * @throws ErrorDataDecoderException
     */
private InterfaceHttpData findMultipartDisposition() {
    int readerIndex = undecodedChunk.readerIndex();
    if (currentStatus == MultiPartStatus.DISPOSITION) {
        currentFieldAttributes = new TreeMap<CharSequence, Attribute>(CaseIgnoringComparator.INSTANCE);
    }
    // read many lines until empty line with newline found! Store all data
    while (!skipOneLine()) {
        String newline;
        try {
            skipControlCharacters();
            newline = readLine();
        } catch (NotEnoughDataDecoderException ignored) {
            undecodedChunk.readerIndex(readerIndex);
            return null;
        }
        String[] contents = splitMultipartHeader(newline);
        if (HttpHeaderNames.CONTENT_DISPOSITION.contentEqualsIgnoreCase(contents[0])) {
            boolean checkSecondArg;
            if (currentStatus == MultiPartStatus.DISPOSITION) {
                checkSecondArg = HttpHeaderValues.FORM_DATA.contentEqualsIgnoreCase(contents[1]);
            } else {
                checkSecondArg = HttpHeaderValues.ATTACHMENT.contentEqualsIgnoreCase(contents[1]) || HttpHeaderValues.FILE.contentEqualsIgnoreCase(contents[1]);
            }
            if (checkSecondArg) {
                // read next values and store them in the map as Attribute
                for (int i = 2; i < contents.length; i++) {
                    String[] values = contents[i].split("=", 2);
                    Attribute attribute;
                    try {
                        String name = cleanString(values[0]);
                        String value = values[1];
                        // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
                        if (HttpHeaderValues.FILENAME.contentEquals(name)) {
                            // filename value is quoted string so strip them
                            value = value.substring(1, value.length() - 1);
                        } else {
                            // otherwise we need to clean the value
                            value = cleanString(value);
                        }
                        attribute = factory.createAttribute(request, name, value);
                    } catch (NullPointerException e) {
                        throw new ErrorDataDecoderException(e);
                    } catch (IllegalArgumentException e) {
                        throw new ErrorDataDecoderException(e);
                    }
                    currentFieldAttributes.put(attribute.getName(), attribute);
                }
            }
        } else if (HttpHeaderNames.CONTENT_TRANSFER_ENCODING.contentEqualsIgnoreCase(contents[0])) {
            Attribute attribute;
            try {
                attribute = factory.createAttribute(request, HttpHeaderNames.CONTENT_TRANSFER_ENCODING.toString(), cleanString(contents[1]));
            } catch (NullPointerException e) {
                throw new ErrorDataDecoderException(e);
            } catch (IllegalArgumentException e) {
                throw new ErrorDataDecoderException(e);
            }
            currentFieldAttributes.put(HttpHeaderNames.CONTENT_TRANSFER_ENCODING, attribute);
        } else if (HttpHeaderNames.CONTENT_LENGTH.contentEqualsIgnoreCase(contents[0])) {
            Attribute attribute;
            try {
                attribute = factory.createAttribute(request, HttpHeaderNames.CONTENT_LENGTH.toString(), cleanString(contents[1]));
            } catch (NullPointerException e) {
                throw new ErrorDataDecoderException(e);
            } catch (IllegalArgumentException e) {
                throw new ErrorDataDecoderException(e);
            }
            currentFieldAttributes.put(HttpHeaderNames.CONTENT_LENGTH, attribute);
        } else if (HttpHeaderNames.CONTENT_TYPE.contentEqualsIgnoreCase(contents[0])) {
            // Take care of possible "multipart/mixed"
            if (HttpHeaderValues.MULTIPART_MIXED.contentEqualsIgnoreCase(contents[1])) {
                if (currentStatus == MultiPartStatus.DISPOSITION) {
                    String values = StringUtil.substringAfter(contents[2], '=');
                    multipartMixedBoundary = "--" + values;
                    currentStatus = MultiPartStatus.MIXEDDELIMITER;
                    return decodeMultipart(MultiPartStatus.MIXEDDELIMITER);
                } else {
                    throw new ErrorDataDecoderException("Mixed Multipart found in a previous Mixed Multipart");
                }
            } else {
                for (int i = 1; i < contents.length; i++) {
                    if (contents[i].toLowerCase().startsWith(HttpHeaderValues.CHARSET.toString())) {
                        String values = StringUtil.substringAfter(contents[i], '=');
                        Attribute attribute;
                        try {
                            attribute = factory.createAttribute(request, HttpHeaderValues.CHARSET.toString(), cleanString(values));
                        } catch (NullPointerException e) {
                            throw new ErrorDataDecoderException(e);
                        } catch (IllegalArgumentException e) {
                            throw new ErrorDataDecoderException(e);
                        }
                        currentFieldAttributes.put(HttpHeaderValues.CHARSET, attribute);
                    } else {
                        Attribute attribute;
                        try {
                            attribute = factory.createAttribute(request, cleanString(contents[0]), contents[i]);
                        } catch (NullPointerException e) {
                            throw new ErrorDataDecoderException(e);
                        } catch (IllegalArgumentException e) {
                            throw new ErrorDataDecoderException(e);
                        }
                        currentFieldAttributes.put(attribute.getName(), attribute);
                    }
                }
            }
        } else {
            throw new ErrorDataDecoderException("Unknown Params: " + newline);
        }
    }
    // Is it a FileUpload
    Attribute filenameAttribute = currentFieldAttributes.get(HttpHeaderValues.FILENAME);
    if (currentStatus == MultiPartStatus.DISPOSITION) {
        if (filenameAttribute != null) {
            // FileUpload
            currentStatus = MultiPartStatus.FILEUPLOAD;
            // do not change the buffer position
            return decodeMultipart(MultiPartStatus.FILEUPLOAD);
        } else {
            // Field
            currentStatus = MultiPartStatus.FIELD;
            // do not change the buffer position
            return decodeMultipart(MultiPartStatus.FIELD);
        }
    } else {
        if (filenameAttribute != null) {
            // FileUpload
            currentStatus = MultiPartStatus.MIXEDFILEUPLOAD;
            // do not change the buffer position
            return decodeMultipart(MultiPartStatus.MIXEDFILEUPLOAD);
        } else {
            // Field is not supported in MIXED mode
            throw new ErrorDataDecoderException("Filename not found");
        }
    }
}
Also used : NotEnoughDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException) ErrorDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException)

Example 2 with NotEnoughDataDecoderException

use of io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException in project netty by netty.

the class HttpPostMultipartRequestDecoder method getFileUpload.

/**
     * Get the FileUpload (new one or current one)
     *
     * @param delimiter
     *            the delimiter to use
     * @return the InterfaceHttpData if any
     * @throws ErrorDataDecoderException
     */
protected InterfaceHttpData getFileUpload(String delimiter) {
    // eventually restart from existing FileUpload
    // Now get value according to Content-Type and Charset
    Attribute encoding = currentFieldAttributes.get(HttpHeaderNames.CONTENT_TRANSFER_ENCODING);
    Charset localCharset = charset;
    // Default
    TransferEncodingMechanism mechanism = TransferEncodingMechanism.BIT7;
    if (encoding != null) {
        String code;
        try {
            code = encoding.getValue().toLowerCase();
        } catch (IOException e) {
            throw new ErrorDataDecoderException(e);
        }
        if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT7.value())) {
            localCharset = CharsetUtil.US_ASCII;
        } else if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT8.value())) {
            localCharset = CharsetUtil.ISO_8859_1;
            mechanism = TransferEncodingMechanism.BIT8;
        } else if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value())) {
            // no real charset, so let the default
            mechanism = TransferEncodingMechanism.BINARY;
        } else {
            throw new ErrorDataDecoderException("TransferEncoding Unknown: " + code);
        }
    }
    Attribute charsetAttribute = currentFieldAttributes.get(HttpHeaderValues.CHARSET);
    if (charsetAttribute != null) {
        try {
            localCharset = Charset.forName(charsetAttribute.getValue());
        } catch (IOException e) {
            throw new ErrorDataDecoderException(e);
        } catch (UnsupportedCharsetException e) {
            throw new ErrorDataDecoderException(e);
        }
    }
    if (currentFileUpload == null) {
        Attribute filenameAttribute = currentFieldAttributes.get(HttpHeaderValues.FILENAME);
        Attribute nameAttribute = currentFieldAttributes.get(HttpHeaderValues.NAME);
        Attribute contentTypeAttribute = currentFieldAttributes.get(HttpHeaderNames.CONTENT_TYPE);
        Attribute lengthAttribute = currentFieldAttributes.get(HttpHeaderNames.CONTENT_LENGTH);
        long size;
        try {
            size = lengthAttribute != null ? Long.parseLong(lengthAttribute.getValue()) : 0L;
        } catch (IOException e) {
            throw new ErrorDataDecoderException(e);
        } catch (NumberFormatException ignored) {
            size = 0;
        }
        try {
            String contentType;
            if (contentTypeAttribute != null) {
                contentType = contentTypeAttribute.getValue();
            } else {
                contentType = HttpPostBodyUtil.DEFAULT_BINARY_CONTENT_TYPE;
            }
            currentFileUpload = factory.createFileUpload(request, cleanString(nameAttribute.getValue()), cleanString(filenameAttribute.getValue()), contentType, mechanism.value(), localCharset, size);
        } catch (NullPointerException e) {
            throw new ErrorDataDecoderException(e);
        } catch (IllegalArgumentException e) {
            throw new ErrorDataDecoderException(e);
        } catch (IOException e) {
            throw new ErrorDataDecoderException(e);
        }
    }
    // load data as much as possible
    try {
        readFileUploadByteMultipart(delimiter);
    } catch (NotEnoughDataDecoderException e) {
        // So do not change the currentStatus
        return null;
    }
    if (currentFileUpload.isCompleted()) {
        // ready to load the next one
        if (currentStatus == MultiPartStatus.FILEUPLOAD) {
            currentStatus = MultiPartStatus.HEADERDELIMITER;
            currentFieldAttributes = null;
        } else {
            currentStatus = MultiPartStatus.MIXEDDELIMITER;
            cleanMixedAttributes();
        }
        FileUpload fileUpload = currentFileUpload;
        currentFileUpload = null;
        return fileUpload;
    }
    // So do not change the currentStatus
    return null;
}
Also used : TransferEncodingMechanism(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism) Charset(java.nio.charset.Charset) NotEnoughDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException) IOException(java.io.IOException) UnsupportedCharsetException(java.nio.charset.UnsupportedCharsetException) ErrorDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException)

Example 3 with NotEnoughDataDecoderException

use of io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException in project netty by netty.

the class HttpPostMultipartRequestDecoder method loadFieldMultipart.

/**
     * Load the field value from a Multipart request
     *
     * @throws NotEnoughDataDecoderException
     *             Need more chunks
     * @throws ErrorDataDecoderException
     */
private void loadFieldMultipart(String delimiter) {
    SeekAheadOptimize sao;
    try {
        sao = new SeekAheadOptimize(undecodedChunk);
    } catch (SeekAheadNoBackArrayException ignored) {
        loadFieldMultipartStandard(delimiter);
        return;
    }
    int readerIndex = undecodedChunk.readerIndex();
    try {
        // found the decoder limit
        boolean newLine = true;
        int index = 0;
        int lastPosition;
        int lastrealpos = sao.pos;
        boolean found = false;
        while (sao.pos < sao.limit) {
            byte nextByte = sao.bytes[sao.pos++];
            if (newLine) {
                // Check the delimiter
                if (nextByte == delimiter.codePointAt(index)) {
                    index++;
                    if (delimiter.length() == index) {
                        found = true;
                        break;
                    }
                } else {
                    newLine = false;
                    index = 0;
                    // continue until end of line
                    if (nextByte == HttpConstants.CR) {
                        if (sao.pos < sao.limit) {
                            nextByte = sao.bytes[sao.pos++];
                            if (nextByte == HttpConstants.LF) {
                                newLine = true;
                                index = 0;
                                lastrealpos = sao.pos - 2;
                            } else {
                                // Unread last nextByte
                                sao.pos--;
                                lastrealpos = sao.pos;
                            }
                        }
                    } else if (nextByte == HttpConstants.LF) {
                        newLine = true;
                        index = 0;
                        lastrealpos = sao.pos - 1;
                    } else {
                        lastrealpos = sao.pos;
                    }
                }
            } else {
                // continue until end of line
                if (nextByte == HttpConstants.CR) {
                    if (sao.pos < sao.limit) {
                        nextByte = sao.bytes[sao.pos++];
                        if (nextByte == HttpConstants.LF) {
                            newLine = true;
                            index = 0;
                            lastrealpos = sao.pos - 2;
                        } else {
                            // Unread last nextByte
                            sao.pos--;
                            lastrealpos = sao.pos;
                        }
                    }
                } else if (nextByte == HttpConstants.LF) {
                    newLine = true;
                    index = 0;
                    lastrealpos = sao.pos - 1;
                } else {
                    lastrealpos = sao.pos;
                }
            }
        }
        lastPosition = sao.getReadPosition(lastrealpos);
        if (found) {
            // so go back of delimiter size
            try {
                currentAttribute.addContent(undecodedChunk.copy(readerIndex, lastPosition - readerIndex), true);
            } catch (IOException e) {
                throw new ErrorDataDecoderException(e);
            }
            undecodedChunk.readerIndex(lastPosition);
        } else {
            try {
                currentAttribute.addContent(undecodedChunk.copy(readerIndex, lastPosition - readerIndex), false);
            } catch (IOException e) {
                throw new ErrorDataDecoderException(e);
            }
            undecodedChunk.readerIndex(lastPosition);
            throw new NotEnoughDataDecoderException();
        }
    } catch (IndexOutOfBoundsException e) {
        undecodedChunk.readerIndex(readerIndex);
        throw new NotEnoughDataDecoderException(e);
    }
}
Also used : SeekAheadOptimize(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize) SeekAheadNoBackArrayException(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException) NotEnoughDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException) IOException(java.io.IOException) ErrorDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException)

Example 4 with NotEnoughDataDecoderException

use of io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException in project netty by netty.

the class HttpPostMultipartRequestDecoder method readLine.

/**
     * Read one line up to the CRLF or LF
     *
     * @return the String from one line
     * @throws NotEnoughDataDecoderException
     *             Need more chunks and reset the readerInder to the previous
     *             value
     */
private String readLine() {
    SeekAheadOptimize sao;
    try {
        sao = new SeekAheadOptimize(undecodedChunk);
    } catch (SeekAheadNoBackArrayException ignored) {
        return readLineStandard();
    }
    int readerIndex = undecodedChunk.readerIndex();
    try {
        ByteBuf line = buffer(64);
        while (sao.pos < sao.limit) {
            byte nextByte = sao.bytes[sao.pos++];
            if (nextByte == HttpConstants.CR) {
                if (sao.pos < sao.limit) {
                    nextByte = sao.bytes[sao.pos++];
                    if (nextByte == HttpConstants.LF) {
                        sao.setReadPosition(0);
                        return line.toString(charset);
                    } else {
                        // Write CR (not followed by LF)
                        sao.pos--;
                        line.writeByte(HttpConstants.CR);
                    }
                } else {
                    line.writeByte(nextByte);
                }
            } else if (nextByte == HttpConstants.LF) {
                sao.setReadPosition(0);
                return line.toString(charset);
            } else {
                line.writeByte(nextByte);
            }
        }
    } catch (IndexOutOfBoundsException e) {
        undecodedChunk.readerIndex(readerIndex);
        throw new NotEnoughDataDecoderException(e);
    }
    undecodedChunk.readerIndex(readerIndex);
    throw new NotEnoughDataDecoderException();
}
Also used : SeekAheadOptimize(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize) SeekAheadNoBackArrayException(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException) NotEnoughDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException) ByteBuf(io.netty.buffer.ByteBuf)

Example 5 with NotEnoughDataDecoderException

use of io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException in project netty by netty.

the class HttpPostMultipartRequestDecoder method readDelimiter.

/**
     * Read one line up to --delimiter or --delimiter-- and if existing the CRLF
     * or LF. Note that CRLF or LF are mandatory for opening delimiter
     * (--delimiter) but not for closing delimiter (--delimiter--) since some
     * clients does not include CRLF in this case.
     *
     * @param delimiter
     *            of the form --string, such that '--' is already included
     * @return the String from one line as the delimiter searched (opening or
     *         closing)
     * @throws NotEnoughDataDecoderException
     *             Need more chunks and reset the readerInder to the previous
     *             value
     */
private String readDelimiter(String delimiter) {
    SeekAheadOptimize sao;
    try {
        sao = new SeekAheadOptimize(undecodedChunk);
    } catch (SeekAheadNoBackArrayException ignored) {
        return readDelimiterStandard(delimiter);
    }
    int readerIndex = undecodedChunk.readerIndex();
    int delimiterPos = 0;
    int len = delimiter.length();
    try {
        StringBuilder sb = new StringBuilder(64);
        // check conformity with delimiter
        while (sao.pos < sao.limit && delimiterPos < len) {
            byte nextByte = sao.bytes[sao.pos++];
            if (nextByte == delimiter.charAt(delimiterPos)) {
                delimiterPos++;
                sb.append((char) nextByte);
            } else {
                // delimiter not found so break here !
                undecodedChunk.readerIndex(readerIndex);
                throw new NotEnoughDataDecoderException();
            }
        }
        // Now check if either opening delimiter or closing delimiter
        if (sao.pos < sao.limit) {
            byte nextByte = sao.bytes[sao.pos++];
            if (nextByte == HttpConstants.CR) {
                // first check for opening delimiter
                if (sao.pos < sao.limit) {
                    nextByte = sao.bytes[sao.pos++];
                    if (nextByte == HttpConstants.LF) {
                        sao.setReadPosition(0);
                        return sb.toString();
                    } else {
                        // error CR without LF
                        // delimiter not found so break here !
                        undecodedChunk.readerIndex(readerIndex);
                        throw new NotEnoughDataDecoderException();
                    }
                } else {
                    // error since CR must be followed by LF
                    // delimiter not found so break here !
                    undecodedChunk.readerIndex(readerIndex);
                    throw new NotEnoughDataDecoderException();
                }
            } else if (nextByte == HttpConstants.LF) {
                // same first check for opening delimiter where LF used with
                // no CR
                sao.setReadPosition(0);
                return sb.toString();
            } else if (nextByte == '-') {
                sb.append('-');
                // second check for closing delimiter
                if (sao.pos < sao.limit) {
                    nextByte = sao.bytes[sao.pos++];
                    if (nextByte == '-') {
                        sb.append('-');
                        // now try to find if CRLF or LF there
                        if (sao.pos < sao.limit) {
                            nextByte = sao.bytes[sao.pos++];
                            if (nextByte == HttpConstants.CR) {
                                if (sao.pos < sao.limit) {
                                    nextByte = sao.bytes[sao.pos++];
                                    if (nextByte == HttpConstants.LF) {
                                        sao.setReadPosition(0);
                                        return sb.toString();
                                    } else {
                                        // error CR without LF
                                        // delimiter not found so break here !
                                        undecodedChunk.readerIndex(readerIndex);
                                        throw new NotEnoughDataDecoderException();
                                    }
                                } else {
                                    // error CR without LF
                                    // delimiter not found so break here !
                                    undecodedChunk.readerIndex(readerIndex);
                                    throw new NotEnoughDataDecoderException();
                                }
                            } else if (nextByte == HttpConstants.LF) {
                                sao.setReadPosition(0);
                                return sb.toString();
                            } else {
                                // No CRLF but ok however (Adobe Flash
                                // uploader)
                                // minus 1 since we read one char ahead but
                                // should not
                                sao.setReadPosition(1);
                                return sb.toString();
                            }
                        }
                        // FIXME what do we do here?
                        // either considering it is fine, either waiting for
                        // more data to come?
                        // lets try considering it is fine...
                        sao.setReadPosition(0);
                        return sb.toString();
                    }
                // whatever now => error since incomplete
                // only one '-' => not enough or whatever not enough
                // element
                }
            }
        }
    } catch (IndexOutOfBoundsException e) {
        undecodedChunk.readerIndex(readerIndex);
        throw new NotEnoughDataDecoderException(e);
    }
    undecodedChunk.readerIndex(readerIndex);
    throw new NotEnoughDataDecoderException();
}
Also used : SeekAheadOptimize(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize) SeekAheadNoBackArrayException(io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException) NotEnoughDataDecoderException(io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException)

Aggregations

NotEnoughDataDecoderException (io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException)10 ErrorDataDecoderException (io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException)6 IOException (java.io.IOException)5 ByteBuf (io.netty.buffer.ByteBuf)4 SeekAheadNoBackArrayException (io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException)4 SeekAheadOptimize (io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize)4 TransferEncodingMechanism (io.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism)1 Charset (java.nio.charset.Charset)1 UnsupportedCharsetException (java.nio.charset.UnsupportedCharsetException)1