Passed
Pull Request — dev (#265)
by Konstantin
04:41
created

WrappedOriginalServletInputStream(ServletInputStream,int)   A

Complexity

Conditions 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
c 1
b 0
f 0
dl 0
loc 6
rs 10
1
package easytests.swagger;
2
3
import java.io.BufferedReader;
4
import java.io.ByteArrayInputStream;
5
import java.io.ByteArrayOutputStream;
6
import java.io.IOException;
7
import java.io.InputStreamReader;
8
import javax.servlet.ReadListener;
9
import javax.servlet.ServletInputStream;
10
import javax.servlet.http.HttpServletRequest;
11
import javax.servlet.http.HttpServletRequestWrapper;
12
13
14
/**
15
 * @author atlassian
16
 * A {@link javax.servlet.http.HttpServletRequestWrapper} those {@link ServletInputStream} is
17
 * cached and can be reset and read again as often as necessary.
18
 */
19
public class ResettableRequestServletWrapper extends HttpServletRequestWrapper {
20
    private ServletInputStream servletInputStream;
21
22
    private BufferedReader reader;
23
24
    ResettableRequestServletWrapper(final HttpServletRequest request) {
25
        super(request);
26
    }
27
28
    /**
29
     * Will rewind the {@link ServletInputStream} to its beginning so it can be
30
     * read again.
31
     * <p>
32
     * Additionally the {@link #getReader()} will be removed if it was used. It will be
33
     * created again on its next usage.
34
     * <p>
35
     * Before resetting the stream the first time it has to be read entirely. The
36
     * reset will only provide a view from position 0 to the already read bytes from
37
     * that stream.
38
     * If the stream wasn't read at all the content will be empty.
39
     */
40
    public void resetInputStream() throws IOException {
41
        if (servletInputStream == null) {
42
            this.servletInputStream = new CachedServletInputStream(new byte[0]);
43
        } else if (servletInputStream instanceof WrappedOriginalServletInputStream) {
44
            final byte[] bytes = ((WrappedOriginalServletInputStream) servletInputStream)
45
                    .byteArrayOutputStream.toByteArray();
46
            this.servletInputStream = new CachedServletInputStream(bytes);
47
        } else if (servletInputStream instanceof CachedServletInputStream) {
48
            // just reset the already cached stream
49
            this.servletInputStream.reset();
50
        }
51
        this.reader = null;
52
    }
53
54
    @Override
55
    public ServletInputStream getInputStream() throws IOException {
56
        if (servletInputStream == null) {
57
            this.servletInputStream = new WrappedOriginalServletInputStream(
58
                    super.getInputStream(),
59
                    super.getContentLength()
60
            );
61
        }
62
        return this.servletInputStream;
63
    }
64
65
    @Override
66
    public BufferedReader getReader() throws IOException {
67
        if (this.reader == null) {
68
            final String encoding = super.getCharacterEncoding();
69
            final InputStreamReader streamReader = encoding == null
70
                    ? new InputStreamReader(this.getInputStream())
71
                    : new InputStreamReader(this.getInputStream(), encoding);
72
            this.reader = new BufferedReader(streamReader);
73
        }
74
        return this.reader;
75
    }
76
77
    /**
78
     * A {@link ServletInputStream} wrapping the original request and saving all read bytes.
79
     */
80
    private static final class WrappedOriginalServletInputStream extends ServletInputStream {
81
82
        private final ServletInputStream originalServletInputStream;
83
84
        private final ByteArrayOutputStream byteArrayOutputStream;
85
86
        private WrappedOriginalServletInputStream(
87
                final ServletInputStream originalServletInputStream,
88
                final int contentLength
89
        ) {
90
            this.originalServletInputStream = originalServletInputStream;
91
            this.byteArrayOutputStream = new ByteArrayOutputStream(contentLength > 0 ? contentLength : 1024);
92
        }
93
94
        @Override
95
        public boolean isFinished() {
96
            return originalServletInputStream.isFinished();
97
        }
98
99
        @Override
100
        public boolean isReady() {
101
            return originalServletInputStream.isReady();
102
        }
103
104
        @Override
105
        public void setReadListener(final ReadListener readListener) {
106
            originalServletInputStream.setReadListener(readListener);
107
        }
108
109
        @Override
110
        public int read() throws IOException {
111
            final int value = originalServletInputStream.read();
112
            if (value != -1) {
113
                byteArrayOutputStream.write(value);
114
            }
115
            return value;
116
        }
117
118
        @Override
119
        public int read(final byte[] b, final int off, final int len) throws IOException {
120
            final int result = originalServletInputStream.read(b, off, len);
121
            if (result > 0) {
122
                byteArrayOutputStream.write(b, off, result);
123
            }
124
            return result;
125
        }
126
    }
127
128
    /**
129
     * A {@link ServletInputStream} backed by a non-blocking {@link java.io.InputStream}
130
     * which can be reset freely.
131
     */
132
    private static final class CachedServletInputStream extends ServletInputStream {
133
134
        private final ByteArrayInputStream inputStream;
135
136
        private CachedServletInputStream(final byte[] bytes) {
137
            this.inputStream = new ByteArrayInputStream(bytes);
138
        }
139
140
        @Override
141
        public int read() throws IOException {
142
            return inputStream.read();
143
        }
144
145
        @Override
146
        public int read(final byte[] b, final int off, final int len) throws IOException {
147
            return inputStream.read(b, off, len);
148
        }
149
150
        @Override
151
        public boolean isFinished() {
152
            return inputStream.available() == 0;
153
        }
154
155
        @Override
156
        public boolean isReady() {
157
            return true;
158
        }
159
160
        @Override
161
        public void setReadListener(final ReadListener readListener) {
162
            throw new IllegalStateException("Can't set ReadListener on CachedServletInputStream.");
163
        }
164
165
        @Override
166
        public void reset() {
167
            inputStream.reset();
168
        }
169
    }
170
}
171