View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.spdy.parser;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.eclipse.jetty.spdy.CompressionFactory;
24  import org.eclipse.jetty.spdy.api.ReplyInfo;
25  import org.eclipse.jetty.spdy.api.SPDY;
26  import org.eclipse.jetty.spdy.frames.ControlFrameType;
27  import org.eclipse.jetty.spdy.frames.SynReplyFrame;
28  import org.eclipse.jetty.util.Fields;
29  
30  public class SynReplyBodyParser extends ControlFrameBodyParser
31  {
32      private final Fields headers = new Fields();
33      private final ControlFrameParser controlFrameParser;
34      private final HeadersBlockParser headersBlockParser;
35      private State state = State.STREAM_ID;
36      private int cursor;
37      private int streamId;
38  
39      public SynReplyBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
40      {
41          this.controlFrameParser = controlFrameParser;
42          this.headersBlockParser = new SynReplyHeadersBlockParser(decompressor);
43      }
44  
45      @Override
46      public boolean parse(ByteBuffer buffer)
47      {
48          while (buffer.hasRemaining())
49          {
50              switch (state)
51              {
52                  case STREAM_ID:
53                  {
54                      if (buffer.remaining() >= 4)
55                      {
56                          streamId = buffer.getInt() & 0x7F_FF_FF_FF;
57                          state = State.ADDITIONAL;
58                      }
59                      else
60                      {
61                          state = State.STREAM_ID_BYTES;
62                          cursor = 4;
63                      }
64                      break;
65                  }
66                  case STREAM_ID_BYTES:
67                  {
68                      byte currByte = buffer.get();
69                      --cursor;
70                      streamId += (currByte & 0xFF) << 8 * cursor;
71                      if (cursor == 0)
72                      {
73                          streamId &= 0x7F_FF_FF_FF;
74                          state = State.ADDITIONAL;
75                      }
76                      break;
77                  }
78                  case ADDITIONAL:
79                  {
80                      switch (controlFrameParser.getVersion())
81                      {
82                          case SPDY.V2:
83                          {
84                              if (buffer.remaining() >= 2)
85                              {
86                                  buffer.getShort();
87                                  state = State.HEADERS;
88                              }
89                              else
90                              {
91                                  state = State.ADDITIONAL_BYTES;
92                                  cursor = 2;
93                              }
94                              break;
95                          }
96                          case SPDY.V3:
97                          {
98                              state = State.HEADERS;
99                              break;
100                         }
101                         default:
102                         {
103                             throw new IllegalStateException();
104                         }
105                     }
106                     break;
107                 }
108                 case ADDITIONAL_BYTES:
109                 {
110                     assert controlFrameParser.getVersion() == SPDY.V2;
111                     buffer.get();
112                     --cursor;
113                     if (cursor == 0)
114                         state = State.HEADERS;
115                     break;
116                 }
117                 case HEADERS:
118                 {
119                     short version = controlFrameParser.getVersion();
120                     int length = controlFrameParser.getLength() - getSynReplyDataLength(version);
121                     if (headersBlockParser.parse(streamId, version, length, buffer))
122                     {
123                         byte flags = controlFrameParser.getFlags();
124                         if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
125                             throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
126 
127                         SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Fields(headers, true));
128                         controlFrameParser.onControlFrame(frame);
129 
130                         reset();
131                         return true;
132                     }
133                     break;
134                 }
135                 default:
136                 {
137                     throw new IllegalStateException();
138                 }
139             }
140         }
141         return false;
142     }
143 
144     private int getSynReplyDataLength(short version)
145     {
146         switch (version)
147         {
148             case 2:
149                 return 6;
150             case 3:
151                 return 4;
152             default:
153                 throw new IllegalStateException();
154         }
155     }
156 
157     private void reset()
158     {
159         headers.clear();
160         state = State.STREAM_ID;
161         cursor = 0;
162         streamId = 0;
163     }
164 
165     private enum State
166     {
167         STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
168     }
169 
170     private class SynReplyHeadersBlockParser extends HeadersBlockParser
171     {
172         public SynReplyHeadersBlockParser(CompressionFactory.Decompressor decompressor)
173         {
174             super(decompressor);
175         }
176 
177         @Override
178         protected void onHeader(String name, String[] values)
179         {
180             for (String value : values)
181                 headers.add(name, value);
182         }
183     }
184 }