View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.server;
20  
21  import java.util.Collections;
22  import java.util.Map;
23  
24  import org.eclipse.jetty.http.MetaData;
25  import org.eclipse.jetty.http2.ErrorCode;
26  import org.eclipse.jetty.http2.FlowControlStrategy;
27  import org.eclipse.jetty.http2.HTTP2Session;
28  import org.eclipse.jetty.http2.IStream;
29  import org.eclipse.jetty.http2.api.Session;
30  import org.eclipse.jetty.http2.api.Stream;
31  import org.eclipse.jetty.http2.api.server.ServerSessionListener;
32  import org.eclipse.jetty.http2.frames.Frame;
33  import org.eclipse.jetty.http2.frames.HeadersFrame;
34  import org.eclipse.jetty.http2.frames.PushPromiseFrame;
35  import org.eclipse.jetty.http2.frames.SettingsFrame;
36  import org.eclipse.jetty.http2.generator.Generator;
37  import org.eclipse.jetty.http2.parser.ServerParser;
38  import org.eclipse.jetty.io.EndPoint;
39  import org.eclipse.jetty.util.Callback;
40  import org.eclipse.jetty.util.log.Log;
41  import org.eclipse.jetty.util.log.Logger;
42  import org.eclipse.jetty.util.thread.Scheduler;
43  
44  public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener
45  {
46      private static final Logger LOG = Log.getLogger(HTTP2ServerSession.class);
47  
48      private final ServerSessionListener listener;
49  
50      public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControlStrategy flowControl)
51      {
52          super(scheduler, endPoint, generator, listener, flowControl, 2);
53          this.listener = listener;
54      }
55  
56      @Override
57      public void onPreface()
58      {
59          // SPEC: send a SETTINGS frame upon receiving the preface.
60          Map<Integer, Integer> settings = notifyPreface(this);
61          if (settings == null)
62              settings = Collections.emptyMap();
63          SettingsFrame frame = new SettingsFrame(settings, false);
64          // TODO: consider sending a WINDOW_UPDATE to enlarge the session send window of the client.
65          frames(null, Callback.NOOP, frame, Frame.EMPTY_ARRAY);
66      }
67  
68      @Override
69      public void onHeaders(HeadersFrame frame)
70      {
71          if (LOG.isDebugEnabled())
72              LOG.debug("Received {}", frame);
73  
74          MetaData metaData = frame.getMetaData();
75          if (metaData.isRequest())
76          {
77              IStream stream = createRemoteStream(frame.getStreamId());
78              if (stream != null)
79              {
80                  stream.process(frame, Callback.NOOP);
81                  Stream.Listener listener = notifyNewStream(stream, frame);
82                  stream.setListener(listener);
83              }
84          }
85          else
86          {
87              onConnectionFailure(ErrorCode.INTERNAL_ERROR.code, "invalid_request");
88          }
89      }
90  
91      @Override
92      public void onPushPromise(PushPromiseFrame frame)
93      {
94          onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "push_promise");
95      }
96  
97      private Map<Integer, Integer> notifyPreface(Session session)
98      {
99          try
100         {
101             return listener.onPreface(session);
102         }
103         catch (Throwable x)
104         {
105             LOG.info("Failure while notifying listener " + listener, x);
106             return null;
107         }
108     }
109 
110     @Override
111     public void onFrame(Frame frame)
112     {
113         switch (frame.getType())
114         {
115             case PREFACE:
116                 onPreface();
117                 break;
118             case SETTINGS:
119                 // SPEC: the required reply to this SETTINGS frame is the 101 response.
120                 onSettings((SettingsFrame)frame, false);
121                 break;
122             case HEADERS:
123                 onHeaders((HeadersFrame)frame);
124                 break;
125             default:
126                 super.onFrame(frame);
127                 break;
128         }
129     }
130 }