1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http2;
17
18 import io.netty.util.internal.PlatformDependent;
19 import io.netty.util.internal.SuppressJava6Requirement;
20 import io.netty.util.internal.ThrowableUtil;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import static io.netty.handler.codec.http2.Http2CodecUtil.CONNECTION_STREAM_ID;
28 import static io.netty.util.internal.ObjectUtil.checkNotNull;
29
30
31
32
33 public class Http2Exception extends Exception {
34 private static final long serialVersionUID = -6941186345430164209L;
35 private final Http2Error error;
36 private final ShutdownHint shutdownHint;
37
38 public Http2Exception(Http2Error error) {
39 this(error, ShutdownHint.HARD_SHUTDOWN);
40 }
41
42 public Http2Exception(Http2Error error, ShutdownHint shutdownHint) {
43 this.error = checkNotNull(error, "error");
44 this.shutdownHint = checkNotNull(shutdownHint, "shutdownHint");
45 }
46
47 public Http2Exception(Http2Error error, String message) {
48 this(error, message, ShutdownHint.HARD_SHUTDOWN);
49 }
50
51 public Http2Exception(Http2Error error, String message, ShutdownHint shutdownHint) {
52 super(message);
53 this.error = checkNotNull(error, "error");
54 this.shutdownHint = checkNotNull(shutdownHint, "shutdownHint");
55 }
56
57 public Http2Exception(Http2Error error, String message, Throwable cause) {
58 this(error, message, cause, ShutdownHint.HARD_SHUTDOWN);
59 }
60
61 public Http2Exception(Http2Error error, String message, Throwable cause, ShutdownHint shutdownHint) {
62 super(message, cause);
63 this.error = checkNotNull(error, "error");
64 this.shutdownHint = checkNotNull(shutdownHint, "shutdownHint");
65 }
66
67 static Http2Exception newStatic(Http2Error error, String message, ShutdownHint shutdownHint,
68 Class<?> clazz, String method) {
69 final Http2Exception exception;
70 if (PlatformDependent.javaVersion() >= 7) {
71 exception = new StacklessHttp2Exception(error, message, shutdownHint, true);
72 } else {
73 exception = new StacklessHttp2Exception(error, message, shutdownHint);
74 }
75 return ThrowableUtil.unknownStackTrace(exception, clazz, method);
76 }
77
78 @SuppressJava6Requirement(reason = "uses Java 7+ Exception.<init>(String, Throwable, boolean, boolean)" +
79 " but is guarded by version checks")
80 private Http2Exception(Http2Error error, String message, ShutdownHint shutdownHint, boolean shared) {
81 super(message, null, false, true);
82 assert shared;
83 this.error = checkNotNull(error, "error");
84 this.shutdownHint = checkNotNull(shutdownHint, "shutdownHint");
85 }
86
87 public Http2Error error() {
88 return error;
89 }
90
91
92
93
94 public ShutdownHint shutdownHint() {
95 return shutdownHint;
96 }
97
98
99
100
101
102
103
104
105
106 public static Http2Exception connectionError(Http2Error error, String fmt, Object... args) {
107 return new Http2Exception(error, formatErrorMessage(fmt, args));
108 }
109
110
111
112
113
114
115
116
117
118
119 public static Http2Exception connectionError(Http2Error error, Throwable cause,
120 String fmt, Object... args) {
121 return new Http2Exception(error, formatErrorMessage(fmt, args), cause);
122 }
123
124
125
126
127
128
129
130
131
132 public static Http2Exception closedStreamError(Http2Error error, String fmt, Object... args) {
133 return new ClosedStreamCreationException(error, formatErrorMessage(fmt, args));
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public static Http2Exception streamError(int id, Http2Error error, String fmt, Object... args) {
149 return CONNECTION_STREAM_ID == id ?
150 connectionError(error, fmt, args) :
151 new StreamException(id, error, formatErrorMessage(fmt, args));
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 public static Http2Exception streamError(int id, Http2Error error, Throwable cause,
168 String fmt, Object... args) {
169 return CONNECTION_STREAM_ID == id ?
170 connectionError(error, cause, fmt, args) :
171 new StreamException(id, error, formatErrorMessage(fmt, args), cause);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 public static Http2Exception headerListSizeError(int id, Http2Error error, boolean onDecode,
190 String fmt, Object... args) {
191 return CONNECTION_STREAM_ID == id ?
192 connectionError(error, fmt, args) :
193 new HeaderListSizeException(id, error, formatErrorMessage(fmt, args), onDecode);
194 }
195
196 private static String formatErrorMessage(String fmt, Object[] args) {
197 if (fmt == null) {
198 if (args == null || args.length == 0) {
199 return "Unexpected error";
200 }
201 return "Unexpected error: " + Arrays.toString(args);
202 }
203 return String.format(fmt, args);
204 }
205
206
207
208
209
210
211
212 public static boolean isStreamError(Http2Exception e) {
213 return e instanceof StreamException;
214 }
215
216
217
218
219
220
221
222 public static int streamId(Http2Exception e) {
223 return isStreamError(e) ? ((StreamException) e).streamId() : CONNECTION_STREAM_ID;
224 }
225
226
227
228
229 public enum ShutdownHint {
230
231
232
233 NO_SHUTDOWN,
234
235
236
237
238 GRACEFUL_SHUTDOWN,
239
240
241
242 HARD_SHUTDOWN
243 }
244
245
246
247
248 public static final class ClosedStreamCreationException extends Http2Exception {
249 private static final long serialVersionUID = -6746542974372246206L;
250
251 public ClosedStreamCreationException(Http2Error error) {
252 super(error);
253 }
254
255 public ClosedStreamCreationException(Http2Error error, String message) {
256 super(error, message);
257 }
258
259 public ClosedStreamCreationException(Http2Error error, String message, Throwable cause) {
260 super(error, message, cause);
261 }
262 }
263
264
265
266
267 public static class StreamException extends Http2Exception {
268 private static final long serialVersionUID = 602472544416984384L;
269 private final int streamId;
270
271 StreamException(int streamId, Http2Error error, String message) {
272 super(error, message, ShutdownHint.NO_SHUTDOWN);
273 this.streamId = streamId;
274 }
275
276 StreamException(int streamId, Http2Error error, String message, Throwable cause) {
277 super(error, message, cause, ShutdownHint.NO_SHUTDOWN);
278 this.streamId = streamId;
279 }
280
281 public int streamId() {
282 return streamId;
283 }
284 }
285
286 public static final class HeaderListSizeException extends StreamException {
287 private static final long serialVersionUID = -8807603212183882637L;
288
289 private final boolean decode;
290
291 HeaderListSizeException(int streamId, Http2Error error, String message, boolean decode) {
292 super(streamId, error, message);
293 this.decode = decode;
294 }
295
296 public boolean duringDecode() {
297 return decode;
298 }
299 }
300
301
302
303
304 public static final class CompositeStreamException extends Http2Exception implements Iterable<StreamException> {
305 private static final long serialVersionUID = 7091134858213711015L;
306 private final List<StreamException> exceptions;
307
308 public CompositeStreamException(Http2Error error, int initialCapacity) {
309 super(error, ShutdownHint.NO_SHUTDOWN);
310 exceptions = new ArrayList<StreamException>(initialCapacity);
311 }
312
313 public void add(StreamException e) {
314 exceptions.add(e);
315 }
316
317 @Override
318 public Iterator<StreamException> iterator() {
319 return exceptions.iterator();
320 }
321 }
322
323 private static final class StacklessHttp2Exception extends Http2Exception {
324
325 private static final long serialVersionUID = 1077888485687219443L;
326
327 StacklessHttp2Exception(Http2Error error, String message, ShutdownHint shutdownHint) {
328 super(error, message, shutdownHint);
329 }
330
331 StacklessHttp2Exception(Http2Error error, String message, ShutdownHint shutdownHint, boolean shared) {
332 super(error, message, shutdownHint, shared);
333 }
334
335
336
337 @Override
338 public Throwable fillInStackTrace() {
339 return this;
340 }
341 }
342 }