View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  /**
24   * <p>Parser for the END_REQUEST frame body.</p>
25   * <pre>
26   * struct end_request_body {
27   *     uint applicationStatus;
28   *     ubyte protocolStatus;
29   *     ubyte[3] reserved;
30   * }
31   * </pre>
32   */
33  public class EndRequestContentParser extends ContentParser
34  {
35      private final Parser.Listener listener;
36      private State state = State.APPLICATION;
37      private int cursor;
38      private int application;
39      private int protocol;
40  
41      public EndRequestContentParser(HeaderParser headerParser, Parser.Listener listener)
42      {
43          super(headerParser);
44          this.listener = listener;
45      }
46  
47      @Override
48      public Result parse(ByteBuffer buffer)
49      {
50          while (buffer.hasRemaining())
51          {
52              switch (state)
53              {
54                  case APPLICATION:
55                  {
56                      if (buffer.remaining() >= 4)
57                      {
58                          application = buffer.getInt();
59                          state = State.PROTOCOL;
60                      }
61                      else
62                      {
63                          state = State.APPLICATION_BYTES;
64                          cursor = 0;
65                      }
66                      break;
67                  }
68                  case APPLICATION_BYTES:
69                  {
70                      int quarterInt = buffer.get() & 0xFF;
71                      application = (application << 8) + quarterInt;
72                      if (++cursor == 4)
73                          state = State.PROTOCOL;
74                      break;
75                  }
76                  case PROTOCOL:
77                  {
78                      protocol = buffer.get() & 0xFF;
79                      state = State.RESERVED;
80                      break;
81                  }
82                  case RESERVED:
83                  {
84                      if (buffer.remaining() >= 3)
85                      {
86                          buffer.position(buffer.position() + 3);
87                          onEnd();
88                          reset();
89                          return Result.COMPLETE;
90                      }
91                      else
92                      {
93                          state = State.RESERVED_BYTES;
94                          cursor = 0;
95                          break;
96                      }
97                  }
98                  case RESERVED_BYTES:
99                  {
100                     buffer.get();
101                     if (++cursor == 3)
102                     {
103                         onEnd();
104                         reset();
105                         return Result.COMPLETE;
106                     }
107                     break;
108                 }
109                 default:
110                 {
111                     throw new IllegalStateException();
112                 }
113             }
114         }
115         return Result.PENDING;
116     }
117 
118     private void onEnd()
119     {
120         if (application != 0)
121             listener.onFailure(getRequest(), new Exception("FastCGI application returned code " + application));
122         else if (protocol != 0)
123             listener.onFailure(getRequest(), new Exception("FastCGI server returned code " + protocol));
124         else
125             listener.onEnd(getRequest());
126     }
127 
128     private void reset()
129     {
130         state = State.APPLICATION;
131         cursor = 0;
132         application = 0;
133         protocol = 0;
134     }
135 
136     private enum State
137     {
138         APPLICATION, APPLICATION_BYTES, PROTOCOL, RESERVED, RESERVED_BYTES
139     }
140 }