View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at:
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  
16  package io.netty.handler.codec.http2;
17  
18  import static io.netty.handler.codec.http2.Http2CodecUtil.CONNECTION_STREAM_ID;
19  
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  /**
25   * Exception thrown when an HTTP/2 error was encountered.
26   */
27  public class Http2Exception extends Exception {
28      private static final long serialVersionUID = -6943456574080986447L;
29      private final Http2Error error;
30  
31      public Http2Exception(Http2Error error) {
32          this.error = error;
33      }
34  
35      public Http2Exception(Http2Error error, String message) {
36          super(message);
37          this.error = error;
38      }
39  
40      public Http2Exception(Http2Error error, String message, Throwable cause) {
41          super(message, cause);
42          this.error = error;
43      }
44  
45      public Http2Error error() {
46          return error;
47      }
48  
49      /**
50       * Use if an error has occurred which can not be isolated to a single stream, but instead applies
51       * to the entire connection.
52       * @param error The type of error as defined by the HTTP/2 specification.
53       * @param fmt String with the content and format for the additional debug data.
54       * @param args Objects which fit into the format defined by {@code fmt}.
55       * @return An exception which can be translated into a HTTP/2 error.
56       */
57      public static Http2Exception connectionError(Http2Error error, String fmt, Object... args) {
58          return new Http2Exception(error, String.format(fmt, args));
59      }
60  
61      /**
62       * Use if an error has occurred which can not be isolated to a single stream, but instead applies
63       * to the entire connection.
64       * @param error The type of error as defined by the HTTP/2 specification.
65       * @param cause The object which caused the error.
66       * @param fmt String with the content and format for the additional debug data.
67       * @param args Objects which fit into the format defined by {@code fmt}.
68       * @return An exception which can be translated into a HTTP/2 error.
69       */
70      public static Http2Exception connectionError(Http2Error error, Throwable cause,
71              String fmt, Object... args) {
72          return new Http2Exception(error, String.format(fmt, args), cause);
73      }
74  
75      /**
76       * Use if an error which can be isolated to a single stream has occurred.  If the {@code id} is not
77       * {@link Http2CodecUtil#CONNECTION_STREAM_ID} then a {@link Http2Exception.StreamException} will be returned.
78       * Otherwise the error is considered a connection error and a {@link Http2Exception} is returned.
79       * @param id The stream id for which the error is isolated to.
80       * @param error The type of error as defined by the HTTP/2 specification.
81       * @param fmt String with the content and format for the additional debug data.
82       * @param args Objects which fit into the format defined by {@code fmt}.
83       * @return If the {@code id} is not
84       * {@link Http2CodecUtil#CONNECTION_STREAM_ID} then a {@link Http2Exception.StreamException} will be returned.
85       * Otherwise the error is considered a connection error and a {@link Http2Exception} is returned.
86       */
87      public static Http2Exception streamError(int id, Http2Error error, String fmt, Object... args) {
88          return CONNECTION_STREAM_ID == id ?
89                  Http2Exception.connectionError(error, fmt, args) :
90                      new StreamException(id, error, String.format(fmt, args));
91      }
92  
93      /**
94       * Use if an error which can be isolated to a single stream has occurred.  If the {@code id} is not
95       * {@link Http2CodecUtil#CONNECTION_STREAM_ID} then a {@link Http2Exception.StreamException} will be returned.
96       * Otherwise the error is considered a connection error and a {@link Http2Exception} is returned.
97       * @param id The stream id for which the error is isolated to.
98       * @param error The type of error as defined by the HTTP/2 specification.
99       * @param cause The object which caused the error.
100      * @param fmt String with the content and format for the additional debug data.
101      * @param args Objects which fit into the format defined by {@code fmt}.
102      * @return If the {@code id} is not
103      * {@link Http2CodecUtil#CONNECTION_STREAM_ID} then a {@link Http2Exception.StreamException} will be returned.
104      * Otherwise the error is considered a connection error and a {@link Http2Exception} is returned.
105      */
106     public static Http2Exception streamError(int id, Http2Error error, Throwable cause,
107             String fmt, Object... args) {
108         return CONNECTION_STREAM_ID == id ?
109                 Http2Exception.connectionError(error, cause, fmt, args) :
110                     new StreamException(id, error, String.format(fmt, args), cause);
111     }
112 
113     /**
114      * Check if an exception is isolated to a single stream or the entire connection.
115      * @param e The exception to check.
116      * @return {@code true} if {@code e} is an instance of {@link Http2Exception.StreamException}.
117      * {@code false} otherwise.
118      */
119     public static boolean isStreamError(Http2Exception e) {
120         return e instanceof StreamException;
121     }
122 
123     /**
124      * Get the stream id associated with an exception.
125      * @param e The exception to get the stream id for.
126      * @return {@link Http2CodecUtil#CONNECTION_STREAM_ID} if {@code e} is a connection error.
127      * Otherwise the stream id associated with the stream error.
128      */
129     public static int streamId(Http2Exception e) {
130         return isStreamError(e) ? ((StreamException) e).streamId() : CONNECTION_STREAM_ID;
131     }
132 
133     /**
134      * Represents an exception that can be isolated to a single stream (as opposed to the entire connection).
135      */
136     public static final class StreamException extends Http2Exception {
137         private static final long serialVersionUID = 462766352505067095L;
138         private final int streamId;
139 
140         StreamException(int streamId, Http2Error error, String message) {
141             super(error, message);
142             this.streamId = streamId;
143         }
144 
145         StreamException(int streamId, Http2Error error, String message, Throwable cause) {
146             super(error, message, cause);
147             this.streamId = streamId;
148         }
149 
150         public int streamId() {
151             return streamId;
152         }
153     }
154 
155     /**
156      * Provides the ability to handle multiple stream exceptions with one throw statement.
157      */
158     public static final class CompositeStreamException extends Http2Exception implements Iterable<StreamException> {
159         private static final long serialVersionUID = -434398146294199889L;
160         private final List<StreamException> exceptions;
161 
162         public CompositeStreamException(Http2Error error, int initialCapacity) {
163             super(error);
164             exceptions = new ArrayList<StreamException>(initialCapacity);
165         }
166 
167         public void add(StreamException e) {
168             exceptions.add(e);
169         }
170 
171         @Override
172         public Iterator<StreamException> iterator() {
173             return exceptions.iterator();
174         }
175     }
176 }