View Javadoc
1   /*
2    * Copyright 2019 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a 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
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http.websocketx;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.Unpooled;
20  import io.netty.util.CharsetUtil;
21  import io.netty.util.internal.StringUtil;
22  
23  /**
24   * Web Socket Frame for closing the connection.
25   */
26  public class CloseWebSocketFrame extends WebSocketFrame {
27  
28      /**
29       * Creates a new empty close frame.
30       */
31      public CloseWebSocketFrame() {
32          super(Unpooled.buffer(0));
33      }
34  
35      /**
36       * Creates a new empty close frame with closing status code and reason text
37       *
38       * @param status
39       *            Status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
40       *            example, <tt>1000</tt> indicates normal closure.
41       */
42      public CloseWebSocketFrame(WebSocketCloseStatus status) {
43          this(status.code(), status.reasonText());
44      }
45  
46      /**
47       * Creates a new empty close frame with closing status code and reason text
48       *
49       * @param status
50       *            Status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
51       *            example, <tt>1000</tt> indicates normal closure.
52       * @param reasonText
53       *            Reason text. Set to null if no text.
54       */
55      public CloseWebSocketFrame(WebSocketCloseStatus status, String reasonText) {
56          this(status.code(), reasonText);
57      }
58  
59      /**
60       * Creates a new empty close frame with closing status code and reason text
61       *
62       * @param statusCode
63       *            Integer status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
64       *            example, <tt>1000</tt> indicates normal closure.
65       * @param reasonText
66       *            Reason text. Set to null if no text.
67       */
68      public CloseWebSocketFrame(int statusCode, String reasonText) {
69          this(true, 0, statusCode, reasonText);
70      }
71  
72      /**
73       * Creates a new close frame with no losing status code and no reason text
74       *
75       * @param finalFragment
76       *            flag indicating if this frame is the final fragment
77       * @param rsv
78       *            reserved bits used for protocol extensions.
79       */
80      public CloseWebSocketFrame(boolean finalFragment, int rsv) {
81          this(finalFragment, rsv, Unpooled.buffer(0));
82      }
83  
84      /**
85       * Creates a new close frame with closing status code and reason text
86       *
87       * @param finalFragment
88       *            flag indicating if this frame is the final fragment
89       * @param rsv
90       *            reserved bits used for protocol extensions
91       * @param statusCode
92       *            Integer status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
93       *            example, <tt>1000</tt> indicates normal closure.
94       * @param reasonText
95       *            Reason text. Set to null if no text.
96       */
97      public CloseWebSocketFrame(boolean finalFragment, int rsv, int statusCode, String reasonText) {
98          super(finalFragment, rsv, newBinaryData(statusCode, reasonText));
99      }
100 
101     private static ByteBuf newBinaryData(int statusCode, String reasonText) {
102         if (reasonText == null) {
103             reasonText = StringUtil.EMPTY_STRING;
104         }
105 
106         ByteBuf binaryData = Unpooled.buffer(2 + reasonText.length());
107         binaryData.writeShort(statusCode);
108         if (!reasonText.isEmpty()) {
109             binaryData.writeCharSequence(reasonText, CharsetUtil.UTF_8);
110         }
111 
112         binaryData.readerIndex(0);
113         return binaryData;
114     }
115 
116     /**
117      * Creates a new close frame
118      *
119      * @param finalFragment
120      *            flag indicating if this frame is the final fragment
121      * @param rsv
122      *            reserved bits used for protocol extensions
123      * @param binaryData
124      *            the content of the frame. Must be 2 byte integer followed by optional UTF-8 encoded string.
125      */
126     public CloseWebSocketFrame(boolean finalFragment, int rsv, ByteBuf binaryData) {
127         super(finalFragment, rsv, binaryData);
128     }
129 
130     /**
131      * Returns the closing status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. If
132      * a status code is set, -1 is returned.
133      */
134     public int statusCode() {
135         ByteBuf binaryData = content();
136         if (binaryData == null || binaryData.capacity() == 0) {
137             return -1;
138         }
139 
140         binaryData.readerIndex(0);
141         return binaryData.getShort(0);
142     }
143 
144     /**
145      * Returns the reason text as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a> If a reason
146      * text is not supplied, an empty string is returned.
147      */
148     public String reasonText() {
149         ByteBuf binaryData = content();
150         if (binaryData == null || binaryData.capacity() <= 2) {
151             return "";
152         }
153 
154         binaryData.readerIndex(2);
155         String reasonText = binaryData.toString(CharsetUtil.UTF_8);
156         binaryData.readerIndex(0);
157 
158         return reasonText;
159     }
160 
161     @Override
162     public CloseWebSocketFrame copy() {
163         return (CloseWebSocketFrame) super.copy();
164     }
165 
166     @Override
167     public CloseWebSocketFrame duplicate() {
168         return (CloseWebSocketFrame) super.duplicate();
169     }
170 
171     @Override
172     public CloseWebSocketFrame retainedDuplicate() {
173         return (CloseWebSocketFrame) super.retainedDuplicate();
174     }
175 
176     @Override
177     public CloseWebSocketFrame replace(ByteBuf content) {
178         return new CloseWebSocketFrame(isFinalFragment(), rsv(), content);
179     }
180 
181     @Override
182     public CloseWebSocketFrame retain() {
183         super.retain();
184         return this;
185     }
186 
187     @Override
188     public CloseWebSocketFrame retain(int increment) {
189         super.retain(increment);
190         return this;
191     }
192 
193     @Override
194     public CloseWebSocketFrame touch() {
195         super.touch();
196         return this;
197     }
198 
199     @Override
200     public CloseWebSocketFrame touch(Object hint) {
201         super.touch(hint);
202         return this;
203     }
204 }