View Javadoc

1   //========================================================================
2   //Copyright 2011-2012 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //All rights reserved. This program and the accompanying materials
5   //are made available under the terms of the Eclipse Public License v1.0
6   //and Apache License v2.0 which accompanies this distribution.
7   //The Eclipse Public License is available at
8   //http://www.eclipse.org/legal/epl-v10.html
9   //The Apache License v2.0 is available at
10  //http://www.opensource.org/licenses/apache2.0.php
11  //You may elect to redistribute this code under either of these licenses.
12  //========================================================================
13  
14  package org.eclipse.jetty.spdy.parser;
15  
16  import java.nio.ByteBuffer;
17  
18  import org.eclipse.jetty.spdy.CompressionFactory;
19  import org.eclipse.jetty.spdy.api.Headers;
20  import org.eclipse.jetty.spdy.api.HeadersInfo;
21  import org.eclipse.jetty.spdy.api.SPDY;
22  import org.eclipse.jetty.spdy.frames.ControlFrameType;
23  import org.eclipse.jetty.spdy.frames.HeadersFrame;
24  
25  public class HeadersBodyParser extends ControlFrameBodyParser
26  {
27      private final Headers headers = new Headers();
28      private final ControlFrameParser controlFrameParser;
29      private final HeadersBlockParser headersBlockParser;
30      private State state = State.STREAM_ID;
31      private int cursor;
32      private int streamId;
33  
34      public HeadersBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
35      {
36          this.controlFrameParser = controlFrameParser;
37          this.headersBlockParser = new HeadersHeadersBlockParser(decompressor);
38      }
39  
40      @Override
41      public boolean parse(ByteBuffer buffer)
42      {
43          while (buffer.hasRemaining())
44          {
45              switch (state)
46              {
47                  case STREAM_ID:
48                  {
49                      if (buffer.remaining() >= 4)
50                      {
51                          streamId = buffer.getInt() & 0x7F_FF_FF_FF;
52                          state = State.ADDITIONAL;
53                      }
54                      else
55                      {
56                          state = State.STREAM_ID_BYTES;
57                          cursor = 4;
58                      }
59                      break;
60                  }
61                  case STREAM_ID_BYTES:
62                  {
63                      byte currByte = buffer.get();
64                      --cursor;
65                      streamId += (currByte & 0xFF) << 8 * cursor;
66                      if (cursor == 0)
67                      {
68                          streamId &= 0x7F_FF_FF_FF;
69                          state = State.ADDITIONAL;
70                      }
71                      break;
72                  }
73                  case ADDITIONAL:
74                  {
75                      switch (controlFrameParser.getVersion())
76                      {
77                          case SPDY.V2:
78                          {
79                              if (buffer.remaining() >= 2)
80                              {
81                                  buffer.getShort();
82                                  state = State.HEADERS;
83                              }
84                              else
85                              {
86                                  state = State.ADDITIONAL_BYTES;
87                                  cursor = 2;
88                              }
89                              break;
90                          }
91                          case SPDY.V3:
92                          {
93                              state = State.HEADERS;
94                              break;
95                          }
96                          default:
97                          {
98                              throw new IllegalStateException();
99                          }
100                     }
101                     break;
102                 }
103                 case ADDITIONAL_BYTES:
104                 {
105                     assert controlFrameParser.getVersion() == SPDY.V2;
106                     buffer.get();
107                     --cursor;
108                     if (cursor == 0)
109                         state = State.HEADERS;
110                     break;
111                 }
112                 case HEADERS:
113                 {
114                     short version = controlFrameParser.getVersion();
115                     int length = controlFrameParser.getLength() - 4;
116                     if (version == SPDY.V2)
117                         length -= 2;
118                     if (headersBlockParser.parse(streamId, version, length, buffer))
119                     {
120                         byte flags = controlFrameParser.getFlags();
121                         if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
122                             throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS);
123 
124                         HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Headers(headers, true));
125                         controlFrameParser.onControlFrame(frame);
126 
127                         reset();
128                         return true;
129                     }
130                     break;
131                 }
132                 default:
133                 {
134                     throw new IllegalStateException();
135                 }
136             }
137         }
138         return false;
139     }
140 
141     private void reset()
142     {
143         headers.clear();
144         state = State.STREAM_ID;
145         cursor = 0;
146         streamId = 0;
147     }
148 
149     private enum State
150     {
151         STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
152     }
153 
154     private class HeadersHeadersBlockParser extends HeadersBlockParser
155     {
156         public HeadersHeadersBlockParser(CompressionFactory.Decompressor decompressor)
157         {
158             super(decompressor);
159         }
160 
161         @Override
162         protected void onHeader(String name, String[] values)
163         {
164             for (String value : values)
165                 headers.add(name, value);
166         }
167     }
168 }