Skip to content
This repository was archived by the owner on Mar 20, 2021. It is now read-only.

Commit 57c98b2

Browse files
committed
[2.3.x] Changes for https://java.net/jira/browse/GRIZZLY-1846 (Verify steam dependency/hierarchy as defined by RFC is implemented).
1 parent 758efd6 commit 57c98b2

File tree

4 files changed

+909
-2
lines changed

4 files changed

+909
-2
lines changed

modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Connection.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
*
104104
* @author Alexey Stashok
105105
*/
106-
public class Http2Connection {
106+
public class Http2Connection extends Node {
107107
private static final Logger LOGGER = Grizzly.logger(Http2Connection.class);
108108

109109
private final boolean isServer;
@@ -189,6 +189,7 @@ static void bind(final Connection connection,
189189
public Http2Connection(final Connection<?> connection,
190190
final boolean isServer,
191191
final Http2BaseFilter handlerFilter) {
192+
super(0);
192193
this.connection = connection;
193194
final FilterChain chain = (FilterChain) connection.getProcessor();
194195
final int sslIdx = chain.indexOfType(SSLBaseFilter.class);

modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Stream.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
*
7575
* @author Grizzly team
7676
*/
77-
public class Http2Stream implements AttributeStorage, OutputSink, Closeable {
77+
public class Http2Stream extends Node implements AttributeStorage, OutputSink, Closeable {
7878

7979
private static final Logger LOGGER = Grizzly.logger(Http2Stream.class);
8080

@@ -169,13 +169,17 @@ protected Http2Stream(final Http2Connection http2Connection,
169169
final int streamId, final int refStreamId,
170170
final boolean exclusive, final int priority,
171171
final Http2StreamState initState) {
172+
super(streamId);
172173
this.http2Connection = http2Connection;
173174
this.request = request;
174175
this.streamId = streamId;
175176
this.refStreamId = refStreamId;
176177
this.exclusive = exclusive;
177178
this.priority = priority;
178179
this.state = initState;
180+
181+
final Node parent = http2Connection.find(refStreamId);
182+
parent.addChild(this);
179183

180184
inputBuffer = new DefaultInputBuffer(this);
181185
outputSink = new DefaultOutputSink(this);
@@ -194,13 +198,15 @@ protected Http2Stream(final Http2Connection http2Connection,
194198
protected Http2Stream(final Http2Connection http2Connection,
195199
final HttpRequestPacket request,
196200
final int priority, final Http2StreamState initState) {
201+
super(UPGRADE_STREAM_ID);
197202
this.http2Connection = http2Connection;
198203
this.request = request;
199204
this.streamId = UPGRADE_STREAM_ID;
200205
this.refStreamId = 0;
201206
this.priority = priority;
202207
this.state = initState;
203208

209+
http2Connection.addChild(this);
204210
exclusive = false;
205211
inputBuffer = http2Connection.isServer()
206212
? new UpgradeInputBuffer()
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
41+
package org.glassfish.grizzly.http2;
42+
43+
44+
import java.util.concurrent.locks.ReentrantReadWriteLock;
45+
46+
/**
47+
* N-ary tree node implementation to support HTTP/2 stream hierarchies.
48+
* @since 2.3.29
49+
*/
50+
public abstract class Node {
51+
52+
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
53+
protected static final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
54+
protected static final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
55+
56+
protected final int id;
57+
protected Node next;
58+
protected Node prev;
59+
protected Node parent;
60+
protected Node firstChild;
61+
protected boolean exclusive;
62+
63+
64+
// ----------------------------------------------------------- Constructors
65+
66+
67+
protected Node(final int id) {
68+
this.id = id;
69+
}
70+
71+
72+
// ------------------------------------------------------ Protected Methods
73+
74+
75+
/**
76+
* Mark this {@link Node} as exclusive. Any siblings will be migrated
77+
* to the children list.
78+
*/
79+
protected void exclusive() {
80+
writeLock.lock();
81+
try {
82+
final Node p = parent;
83+
p.detach(id);
84+
p.addChild(this, true);
85+
} finally {
86+
writeLock.unlock();
87+
}
88+
}
89+
90+
/**
91+
* Add a sibling to this {@link Node}.
92+
*/
93+
protected void addSibling(final Node sibling) {
94+
writeLock.lock();
95+
try {
96+
sibling.next = this;
97+
this.prev = sibling;
98+
sibling.parent = this.parent;
99+
parent.firstChild = sibling;
100+
} finally {
101+
writeLock.unlock();
102+
}
103+
}
104+
105+
/**
106+
* Add a child to this {@link Node}.
107+
*/
108+
protected void addChild(final Node n) {
109+
addChild(n, false);
110+
}
111+
112+
/**
113+
* Add a new exclusive child. Any other children will be moved to
114+
* children of this exclusive child.
115+
*/
116+
protected void addChild(final Node n, final boolean exclusive) {
117+
writeLock.lock();
118+
try {
119+
if (exclusive) {
120+
n.exclusive = true;
121+
if (n.firstChild != null && firstChild != null) {
122+
Node tail = firstChild;
123+
while (tail.next != null) {
124+
tail = tail.next;
125+
}
126+
tail.next = n.firstChild;
127+
n.firstChild.prev = tail;
128+
129+
}
130+
n.firstChild = firstChild;
131+
firstChild = null;
132+
if (n.firstChild != null) {
133+
Node t = n.firstChild;
134+
do {
135+
t.parent = n;
136+
} while ((t = t.next) != null);
137+
}
138+
}
139+
if (firstChild == null) {
140+
firstChild = n;
141+
firstChild.parent = this;
142+
} else {
143+
firstChild.addSibling(n);
144+
}
145+
} finally {
146+
writeLock.unlock();
147+
}
148+
}
149+
150+
/**
151+
* Detail this {@link Node} from the tree maintaining any children.
152+
*/
153+
protected Node detach(final int id) {
154+
return remove(id, true);
155+
}
156+
157+
/**
158+
* Remove this {@link Node} from the tree. Any children will be moved up
159+
* as a child of the remove {@link Node}'s parent.
160+
*/
161+
protected Node remove(final int id) {
162+
return remove(id, false);
163+
}
164+
165+
/**
166+
* Top down search from this {@link Node} and any children (recursively)
167+
* returning the node with a matching <code>id</code>.
168+
*/
169+
protected Node find(final int id) {
170+
if (this.id == id) {
171+
return this;
172+
}
173+
readLock.lock();
174+
try {
175+
if (firstChild != null) {
176+
Node n = firstChild;
177+
do {
178+
if (n.id == id) {
179+
return n;
180+
}
181+
Node result = n.find(id);
182+
if (result != null) {
183+
return result;
184+
}
185+
} while ((n = n.next) != null);
186+
}
187+
return null;
188+
} finally {
189+
readLock.unlock();
190+
}
191+
}
192+
193+
194+
// -------------------------------------------------------- Private Methods
195+
196+
197+
private boolean isFirstSibling() {
198+
return (next != null && prev == null);
199+
}
200+
201+
private boolean isLastSibling() {
202+
return (next == null && prev != null);
203+
}
204+
205+
private boolean hasSiblings() {
206+
return (next != null || prev != null);
207+
}
208+
209+
private Node remove(final int id, final boolean retainChildren) {
210+
final Node n = find(id);
211+
if (n != null) {
212+
writeLock.lock();
213+
try {
214+
// remove this node from sibling pointer chains
215+
if (n.hasSiblings()) {
216+
final Node left = n.prev;
217+
final Node right = n.next;
218+
if (n.isFirstSibling()) {
219+
right.parent.firstChild = right;
220+
right.prev = null;
221+
} else if (n.isLastSibling()) {
222+
left.next = null;
223+
} else {
224+
// Middle child!
225+
left.next = right;
226+
right.prev = left;
227+
}
228+
}
229+
230+
// re-parent the children to this node's parent and
231+
// push these children to the front of the child new parent child list
232+
if (!retainChildren) {
233+
final Node np = n.parent;
234+
if (n.firstChild != null) {
235+
Node t = n.firstChild;
236+
Node last = null;
237+
do {
238+
t.parent = np;
239+
// quick look ahead to see if this node will be the last
240+
if (t.next == null) {
241+
last = t;
242+
}
243+
} while ((t = t.next) != null);
244+
245+
// 'push' the current child to the 'end' of children of the removed node
246+
last.next = np.firstChild;
247+
np.firstChild.prev = last;
248+
249+
// Set the new pointer to the new first child.
250+
np.firstChild = n.firstChild;
251+
}
252+
}
253+
254+
// clear pointers and return
255+
n.parent = null;
256+
n.next = null;
257+
n.prev = null;
258+
if (!retainChildren) {
259+
n.firstChild = null;
260+
}
261+
return n;
262+
} finally {
263+
writeLock.unlock();
264+
}
265+
}
266+
return null;
267+
}
268+
}

0 commit comments

Comments
 (0)