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