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