View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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.fcgi.parser;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.eclipse.jetty.fcgi.FCGI;
24  import org.eclipse.jetty.http.HttpField;
25  
26  public abstract class Parser
27  {
28      protected final HeaderParser headerParser = new HeaderParser();
29      private State state = State.HEADER;
30      private int padding;
31  
32      /**
33       * @param buffer the bytes to parse
34       * @return true if the caller should stop parsing, false if the caller should continue parsing
35       */
36      public boolean parse(ByteBuffer buffer)
37      {
38          while (true)
39          {
40              switch (state)
41              {
42                  case HEADER:
43                  {
44                      if (!headerParser.parse(buffer))
45                          return false;
46                      state = State.CONTENT;
47                      break;
48                  }
49                  case CONTENT:
50                  {
51                      ContentParser contentParser = findContentParser(headerParser.getFrameType());
52                      if (headerParser.getContentLength() == 0)
53                      {
54                          contentParser.noContent();
55                      }
56                      else
57                      {
58                          ContentParser.Result result = contentParser.parse(buffer);
59                          if (result == ContentParser.Result.PENDING)
60                          {
61                              // Not enough data, signal to read/parse more.
62                              return false;
63                          }
64                          if (result == ContentParser.Result.ASYNC)
65                          {
66                              // The content will be processed asynchronously, signal to stop
67                              // parsing; the async operation will eventually resume parsing.
68                              return true;
69                          }
70                      }
71                      padding = headerParser.getPaddingLength();
72                      state = State.PADDING;
73                      break;
74                  }
75                  case PADDING:
76                  {
77                      if (buffer.remaining() >= padding)
78                      {
79                          buffer.position(buffer.position() + padding);
80                          reset();
81                          break;
82                      }
83                      else
84                      {
85                          padding -= buffer.remaining();
86                          buffer.position(buffer.limit());
87                          return false;
88                      }
89                  }
90                  default:
91                  {
92                      throw new IllegalStateException();
93                  }
94              }
95          }
96      }
97  
98      protected abstract ContentParser findContentParser(FCGI.FrameType frameType);
99  
100     private void reset()
101     {
102         headerParser.reset();
103         state = State.HEADER;
104         padding = 0;
105     }
106 
107     public interface Listener
108     {
109         public void onHeader(int request, HttpField field);
110 
111         public void onHeaders(int request);
112 
113         /**
114          * @param request the request id
115          * @param stream the stream type
116          * @param buffer the content bytes
117          * @return true to signal to the parser to stop parsing, false to continue parsing
118          * @see Parser#parse(java.nio.ByteBuffer)
119          */
120         public boolean onContent(int request, FCGI.StreamType stream, ByteBuffer buffer);
121 
122         public void onEnd(int request);
123 
124         public void onFailure(int request, Throwable failure);
125 
126         public static class Adapter implements Listener
127         {
128             @Override
129             public void onHeader(int request, HttpField field)
130             {
131             }
132 
133             @Override
134             public void onHeaders(int request)
135             {
136             }
137 
138             @Override
139             public boolean onContent(int request, FCGI.StreamType stream, ByteBuffer buffer)
140             {
141                 return false;
142             }
143 
144             @Override
145             public void onEnd(int request)
146             {
147             }
148 
149             @Override
150             public void onFailure(int request, Throwable failure)
151             {
152 
153             }
154         }
155     }
156 
157     private enum State
158     {
159         HEADER, CONTENT, PADDING
160     }
161 }