View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http.multipart;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.util.CharsetUtil;
20  
21  import java.nio.charset.Charset;
22  
23  /**
24   * Shared Static object between HttpMessageDecoder, HttpPostRequestDecoder and HttpPostRequestEncoder
25   */
26  final class HttpPostBodyUtil {
27  
28      public static final int chunkSize = 8096;
29      /**
30       * HTTP content disposition header name.
31       */
32      public static final String CONTENT_DISPOSITION = "Content-Disposition";
33  
34      public static final String NAME = "name";
35  
36      public static final String FILENAME = "filename";
37  
38      /**
39       * Content-disposition value for form data.
40       */
41      public static final String FORM_DATA = "form-data";
42  
43      /**
44       * Content-disposition value for file attachment.
45       */
46      public static final String ATTACHMENT = "attachment";
47  
48      /**
49       * Content-disposition value for file attachment.
50       */
51      public static final String FILE = "file";
52  
53      /**
54       * HTTP content type body attribute for multiple uploads.
55       */
56      public static final String MULTIPART_MIXED = "multipart/mixed";
57  
58      /**
59       * Charset for 8BIT
60       */
61      public static final Charset ISO_8859_1 = CharsetUtil.ISO_8859_1;
62  
63      /**
64       * Charset for 7BIT
65       */
66      public static final Charset US_ASCII = CharsetUtil.US_ASCII;
67  
68      /**
69       * Default Content-Type in binary form
70       */
71      public static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream";
72  
73      /**
74       * Default Content-Type in Text form
75       */
76      public static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain";
77  
78      /**
79       * Allowed mechanism for multipart
80       * mechanism := "7bit"
81                    / "8bit"
82                    / "binary"
83         Not allowed: "quoted-printable"
84                    / "base64"
85       */
86      public enum TransferEncodingMechanism {
87          /**
88           * Default encoding
89           */
90          BIT7("7bit"),
91          /**
92           * Short lines but not in ASCII - no encoding
93           */
94          BIT8("8bit"),
95          /**
96           * Could be long text not in ASCII - no encoding
97           */
98          BINARY("binary");
99  
100         private final String value;
101 
102         TransferEncodingMechanism(String value) {
103             this.value = value;
104         }
105 
106         public String value() {
107             return value;
108         }
109 
110         @Override
111         public String toString() {
112             return value;
113         }
114     }
115 
116     private HttpPostBodyUtil() {
117     }
118 
119     /**
120     * This class intends to decrease the CPU in seeking ahead some bytes in
121     * HttpPostRequestDecoder
122     */
123     static class SeekAheadOptimize {
124         byte[] bytes;
125         int readerIndex;
126         int pos;
127         int origPos;
128         int limit;
129         ByteBuf buffer;
130 
131         /**
132          * @param buffer buffer with a backing byte array
133          */
134         SeekAheadOptimize(ByteBuf buffer) {
135             if (!buffer.hasArray()) {
136                 throw new IllegalArgumentException("buffer hasn't backing byte array");
137             }
138             this.buffer = buffer;
139             bytes = buffer.array();
140             readerIndex = buffer.readerIndex();
141             origPos = pos = buffer.arrayOffset() + readerIndex;
142             limit = buffer.arrayOffset() + buffer.writerIndex();
143         }
144 
145         /**
146         *
147         * @param minus this value will be used as (currentPos - minus) to set
148         * the current readerIndex in the buffer.
149         */
150         void setReadPosition(int minus) {
151             pos -= minus;
152             readerIndex = getReadPosition(pos);
153             buffer.readerIndex(readerIndex);
154         }
155 
156         /**
157         *
158         * @param index raw index of the array (pos in general)
159         * @return the value equivalent of raw index to be used in readerIndex(value)
160         */
161         int getReadPosition(int index) {
162             return index - origPos + readerIndex;
163         }
164     }
165 
166     /**
167      * Find the first non whitespace
168      * @return the rank of the first non whitespace
169      */
170     static int findNonWhitespace(String sb, int offset) {
171         int result;
172         for (result = offset; result < sb.length(); result ++) {
173             if (!Character.isWhitespace(sb.charAt(result))) {
174                 break;
175             }
176         }
177         return result;
178     }
179 
180     /**
181      * Find the end of String
182      * @return the rank of the end of string
183      */
184     static int findEndOfString(String sb) {
185         int result;
186         for (result = sb.length(); result > 0; result --) {
187             if (!Character.isWhitespace(sb.charAt(result - 1))) {
188                 break;
189             }
190         }
191         return result;
192     }
193 
194 }