1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.coyote.http11.filters;
19
20 import java.io.IOException;
21 import org.apache.coyote.Request;
22 import org.apache.coyote.InputBuffer;
23 import org.apache.coyote.http11.InputFilter;
24 import org.apache.tomcat.util.buf.ByteChunk;
25
26 /**
27 * Input filter responsible for reading and buffering the request body, so that
28 * it does not interfere with client SSL handshake messages.
29 */
30 public class BufferedInputFilter implements InputFilter {
31
32 // -------------------------------------------------------------- Constants
33
34 private static final String ENCODING_NAME = "buffered";
35 private static final ByteChunk ENCODING = new ByteChunk();
36
37
38 // ----------------------------------------------------- Instance Variables
39
40 private ByteChunk buffered = null;
41 private ByteChunk tempRead = new ByteChunk(1024);
42 private InputBuffer buffer;
43 private boolean hasRead = false;
44
45
46 // ----------------------------------------------------- Static Initializer
47
48 static {
49 ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
50 }
51
52
53 // --------------------------------------------------------- Public Methods
54
55
56 /**
57 * Set the buffering limit. This should be reset every time the buffer is
58 * used.
59 */
60 public void setLimit(int limit) {
61 if (buffered == null) {
62 buffered = new ByteChunk(4048);
63 buffered.setLimit(limit);
64 }
65 }
66
67
68 // ---------------------------------------------------- InputBuffer Methods
69
70
71 /**
72 * Reads the request body and buffers it.
73 */
74 public void setRequest(Request request) {
75 // save off the Request body
76 try {
77 while (buffer.doRead(tempRead, request) >= 0) {
78 buffered.append(tempRead);
79 tempRead.recycle();
80 }
81 } catch(IOException iex) {
82 // Ignore
83 }
84 }
85
86 /**
87 * Fills the given ByteChunk with the buffered request body.
88 */
89 public int doRead(ByteChunk chunk, Request request) throws IOException {
90 if (hasRead || buffered.getLength() <= 0) {
91 return -1;
92 } else {
93 chunk.setBytes(buffered.getBytes(), buffered.getStart(),
94 buffered.getLength());
95 hasRead = true;
96 }
97 return chunk.getLength();
98 }
99
100 public void setBuffer(InputBuffer buffer) {
101 this.buffer = buffer;
102 }
103
104 public void recycle() {
105 if (buffered.getBuffer().length > 65536) {
106 buffered = null;
107 } else {
108 buffered.recycle();
109 }
110 tempRead.recycle();
111 hasRead = false;
112 buffer = null;
113 }
114
115 public ByteChunk getEncodingName() {
116 return ENCODING;
117 }
118
119 public long end() throws IOException {
120 return 0;
121 }
122
123 public int available() {
124 return buffered.getLength();
125 }
126
127 }