1 //
2 // ========================================================================
3 // Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.http2.parser;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.http2.ErrorCode;
24 import org.eclipse.jetty.io.ByteBufferPool;
25 import org.eclipse.jetty.util.BufferUtil;
26 import org.eclipse.jetty.util.log.Log;
27 import org.eclipse.jetty.util.log.Logger;
28
29 public class ServerParser extends Parser
30 {
31 private static final Logger LOG = Log.getLogger(ServerParser.class);
32
33 private final Listener listener;
34 private final PrefaceParser prefaceParser;
35 private State state = State.PREFACE;
36
37 public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
38 {
39 super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize);
40 this.listener = listener;
41 this.prefaceParser = new PrefaceParser(listener);
42 }
43
44 /**
45 * <p>A direct upgrade is an unofficial upgrade from HTTP/1.1 to HTTP/2.0.</p>
46 * <p>A direct upgrade is initiated when {@code org.eclipse.jetty.server.HttpConnection}
47 * sees a request with these bytes:</p>
48 * <pre>
49 * PRI * HTTP/2.0\r\n
50 * \r\n
51 * </pre>
52 * <p>This request is part of the HTTP/2.0 preface, indicating that a
53 * HTTP/2.0 client is attempting a h2c direct connection.</p>
54 * <p>This is not a standard HTTP/1.1 Upgrade path.</p>
55 */
56 public void directUpgrade()
57 {
58 if (state != State.PREFACE)
59 throw new IllegalStateException();
60 prefaceParser.directUpgrade();
61 }
62
63 @Override
64 public void parse(ByteBuffer buffer)
65 {
66 try
67 {
68 if (LOG.isDebugEnabled())
69 LOG.debug("Parsing {}", buffer);
70
71 while (true)
72 {
73 switch (state)
74 {
75 case PREFACE:
76 {
77 if (!prefaceParser.parse(buffer))
78 return;
79 onPreface();
80 state = State.FRAMES;
81 break;
82 }
83 case FRAMES:
84 {
85 // Stay forever in the FRAMES state.
86 super.parse(buffer);
87 return;
88 }
89 default:
90 {
91 throw new IllegalStateException();
92 }
93 }
94 }
95 }
96 catch (Throwable x)
97 {
98 LOG.debug(x);
99 BufferUtil.clear(buffer);
100 notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "parser_error");
101 }
102 }
103
104 protected void onPreface()
105 {
106 notifyPreface();
107 }
108
109 private void notifyPreface()
110 {
111 try
112 {
113 listener.onPreface();
114 }
115 catch (Throwable x)
116 {
117 LOG.info("Failure while notifying listener " + listener, x);
118 }
119 }
120
121 public interface Listener extends Parser.Listener
122 {
123 public void onPreface();
124
125 public static class Adapter extends Parser.Listener.Adapter implements Listener
126 {
127 @Override
128 public void onPreface()
129 {
130 }
131 }
132 }
133
134 private enum State
135 {
136 PREFACE, FRAMES
137 }
138 }