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 }