1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
25 public class HeaderParser
26 {
27 private State state = State.VERSION;
28 private int cursor;
29 private int version;
30 private int type;
31 private int request;
32 private int length;
33 private int padding;
34
35
36
37
38
39
40
41 public boolean parse(ByteBuffer buffer)
42 {
43 while (buffer.hasRemaining())
44 {
45 switch (state)
46 {
47 case VERSION:
48 {
49 version = buffer.get() & 0xFF;
50 state = State.TYPE;
51 break;
52 }
53 case TYPE:
54 {
55 type = buffer.get() & 0xFF;
56 state = State.REQUEST;
57 break;
58 }
59 case REQUEST:
60 {
61 if (buffer.remaining() >= 2)
62 {
63 request = buffer.getShort() & 0xFF_FF;
64 state = State.LENGTH;
65 }
66 else
67 {
68 state = State.REQUEST_BYTES;
69 cursor = 0;
70 }
71 break;
72 }
73 case REQUEST_BYTES:
74 {
75 int halfShort = buffer.get() & 0xFF;
76 request = (request << 8) + halfShort;
77 if (++cursor == 2)
78 state = State.LENGTH;
79 break;
80 }
81 case LENGTH:
82 {
83 if (buffer.remaining() >= 2)
84 {
85 length = buffer.getShort() & 0xFF_FF;
86 state = State.PADDING;
87 }
88 else
89 {
90 state = State.LENGTH_BYTES;
91 cursor = 0;
92 }
93 break;
94 }
95 case LENGTH_BYTES:
96 {
97 int halfShort = buffer.get() & 0xFF;
98 length = (length << 8) + halfShort;
99 if (++cursor == 2)
100 state = State.PADDING;
101 break;
102 }
103 case PADDING:
104 {
105 padding = buffer.get() & 0xFF;
106 state = State.RESERVED;
107 break;
108 }
109 case RESERVED:
110 {
111 buffer.get();
112 return true;
113 }
114 default:
115 {
116 throw new IllegalStateException();
117 }
118 }
119 }
120 return false;
121 }
122
123 public FCGI.FrameType getFrameType()
124 {
125 return FCGI.FrameType.from(type);
126 }
127
128 public int getRequest()
129 {
130 return request;
131 }
132
133 public int getContentLength()
134 {
135 return length;
136 }
137
138 public int getPaddingLength()
139 {
140 return padding;
141 }
142
143 protected void reset()
144 {
145 state = State.VERSION;
146 cursor = 0;
147 version = 0;
148 type = 0;
149 request = 0;
150 length = 0;
151 padding = 0;
152 }
153
154 private enum State
155 {
156 VERSION, TYPE, REQUEST, REQUEST_BYTES, LENGTH, LENGTH_BYTES, PADDING, RESERVED
157 }
158 }