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.HeadersInfo;
25  import org.eclipse.jetty.spdy.api.SPDY;
26  import org.eclipse.jetty.spdy.frames.ControlFrameType;
27  import org.eclipse.jetty.spdy.frames.HeadersFrame;
28  import org.eclipse.jetty.util.Fields;
29  
30  public class HeadersBodyParser 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 HeadersBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
40      {
41          this.controlFrameParser = controlFrameParser;
42          this.headersBlockParser = new HeadersHeadersBlockParser(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() - 4;
121                     if (version == SPDY.V2)
122                         length -= 2;
123                     if (headersBlockParser.parse(streamId, version, length, buffer))
124                     {
125                         byte flags = controlFrameParser.getFlags();
126                         if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
127                             throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS);
128 
129                         HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Fields(headers, true));
130                         controlFrameParser.onControlFrame(frame);
131 
132                         reset();
133                         return true;
134                     }
135                     break;
136                 }
137                 default:
138                 {
139                     throw new IllegalStateException();
140                 }
141             }
142         }
143         return false;
144     }
145 
146     private void reset()
147     {
148         headers.clear();
149         state = State.STREAM_ID;
150         cursor = 0;
151         streamId = 0;
152     }
153 
154     private enum State
155     {
156         STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
157     }
158 
159     private class HeadersHeadersBlockParser extends HeadersBlockParser
160     {
161         public HeadersHeadersBlockParser(CompressionFactory.Decompressor decompressor)
162         {
163             super(decompressor);
164         }
165 
166         @Override
167         protected void onHeader(String name, String[] values)
168         {
169             for (String value : values)
170                 headers.add(name, value);
171         }
172     }
173 }