View Javadoc

1   /*
2    * Copyright (c) 2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.eclipse.jetty.spdy.parser;
18  
19  import java.nio.ByteBuffer;
20  
21  import org.eclipse.jetty.spdy.CompressionFactory;
22  import org.eclipse.jetty.spdy.api.Headers;
23  import org.eclipse.jetty.spdy.api.ReplyInfo;
24  import org.eclipse.jetty.spdy.api.SPDY;
25  import org.eclipse.jetty.spdy.frames.ControlFrameType;
26  import org.eclipse.jetty.spdy.frames.SynReplyFrame;
27  
28  public class SynReplyBodyParser extends ControlFrameBodyParser
29  {
30      private final Headers headers = new Headers();
31      private final ControlFrameParser controlFrameParser;
32      private final HeadersBlockParser headersBlockParser;
33      private State state = State.STREAM_ID;
34      private int cursor;
35      private int streamId;
36  
37      public SynReplyBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
38      {
39          this.controlFrameParser = controlFrameParser;
40          this.headersBlockParser = new SynReplyHeadersBlockParser(decompressor);
41      }
42  
43      @Override
44      public boolean parse(ByteBuffer buffer)
45      {
46          while (buffer.hasRemaining())
47          {
48              switch (state)
49              {
50                  case STREAM_ID:
51                  {
52                      if (buffer.remaining() >= 4)
53                      {
54                          streamId = buffer.getInt() & 0x7F_FF_FF_FF;
55                          state = State.ADDITIONAL;
56                      }
57                      else
58                      {
59                          state = State.STREAM_ID_BYTES;
60                          cursor = 4;
61                      }
62                      break;
63                  }
64                  case STREAM_ID_BYTES:
65                  {
66                      byte currByte = buffer.get();
67                      --cursor;
68                      streamId += (currByte & 0xFF) << 8 * cursor;
69                      if (cursor == 0)
70                      {
71                          streamId &= 0x7F_FF_FF_FF;
72                          state = State.ADDITIONAL;
73                      }
74                      break;
75                  }
76                  case ADDITIONAL:
77                  {
78                      switch (controlFrameParser.getVersion())
79                      {
80                          case SPDY.V2:
81                          {
82                              if (buffer.remaining() >= 2)
83                              {
84                                  buffer.getShort();
85                                  state = State.HEADERS;
86                              }
87                              else
88                              {
89                                  state = State.ADDITIONAL_BYTES;
90                                  cursor = 2;
91                              }
92                              break;
93                          }
94                          case SPDY.V3:
95                          {
96                              state = State.HEADERS;
97                              break;
98                          }
99                          default:
100                         {
101                             throw new IllegalStateException();
102                         }
103                     }
104                     break;
105                 }
106                 case ADDITIONAL_BYTES:
107                 {
108                     assert controlFrameParser.getVersion() == SPDY.V2;
109                     buffer.get();
110                     --cursor;
111                     if (cursor == 0)
112                         state = State.HEADERS;
113                     break;
114                 }
115                 case HEADERS:
116                 {
117                     short version = controlFrameParser.getVersion();
118                     int length = controlFrameParser.getLength() - getSynReplyDataLength(version);
119                     if (headersBlockParser.parse(streamId, version, length, buffer))
120                     {
121                         byte flags = controlFrameParser.getFlags();
122                         if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
123                             throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
124 
125                         SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Headers(headers, true));
126                         controlFrameParser.onControlFrame(frame);
127 
128                         reset();
129                         return true;
130                     }
131                     break;
132                 }
133                 default:
134                 {
135                     throw new IllegalStateException();
136                 }
137             }
138         }
139         return false;
140     }
141 
142     private int getSynReplyDataLength(short version)
143     {
144         switch (version)
145         {
146             case 2:
147                 return 6;
148             case 3:
149                 return 4;
150             default:
151                 throw new IllegalStateException();
152         }
153     }
154 
155     private void reset()
156     {
157         headers.clear();
158         state = State.STREAM_ID;
159         cursor = 0;
160         streamId = 0;
161     }
162 
163     private enum State
164     {
165         STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
166     }
167 
168     private class SynReplyHeadersBlockParser extends HeadersBlockParser
169     {
170         public SynReplyHeadersBlockParser(CompressionFactory.Decompressor decompressor)
171         {
172             super(decompressor);
173         }
174 
175         @Override
176         protected void onHeader(String name, String[] values)
177         {
178             for (String value : values)
179                 headers.add(name, value);
180         }
181     }
182 }