1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.fcgi.server;
20
21 import java.nio.ByteBuffer;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24
25 import org.eclipse.jetty.fcgi.FCGI;
26 import org.eclipse.jetty.fcgi.generator.Flusher;
27 import org.eclipse.jetty.fcgi.parser.ServerParser;
28 import org.eclipse.jetty.http.HttpField;
29 import org.eclipse.jetty.io.AbstractConnection;
30 import org.eclipse.jetty.io.ByteBufferPool;
31 import org.eclipse.jetty.io.EndPoint;
32 import org.eclipse.jetty.server.ByteBufferQueuedHttpInput;
33 import org.eclipse.jetty.server.Connector;
34 import org.eclipse.jetty.server.HttpConfiguration;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37
38 public class ServerFCGIConnection extends AbstractConnection
39 {
40 private static final Logger LOG = Log.getLogger(ServerFCGIConnection.class);
41
42 private final ConcurrentMap<Integer, HttpChannelOverFCGI> channels = new ConcurrentHashMap<>();
43 private final Connector connector;
44 private final Flusher flusher;
45 private final HttpConfiguration configuration;
46 private final ServerParser parser;
47
48 public ServerFCGIConnection(Connector connector, EndPoint endPoint, HttpConfiguration configuration)
49 {
50 super(endPoint, connector.getExecutor());
51 this.connector = connector;
52 this.flusher = new Flusher(endPoint);
53 this.configuration = configuration;
54 this.parser = new ServerParser(new ServerListener());
55 }
56
57 @Override
58 public void onOpen()
59 {
60 super.onOpen();
61 fillInterested();
62 }
63
64 @Override
65 public void onFillable()
66 {
67 EndPoint endPoint = getEndPoint();
68 ByteBufferPool bufferPool = connector.getByteBufferPool();
69 ByteBuffer buffer = bufferPool.acquire(configuration.getResponseHeaderSize(), true);
70 try
71 {
72 while (true)
73 {
74 int read = endPoint.fill(buffer);
75 if (LOG.isDebugEnabled())
76 LOG.debug("Read {} bytes from {}", read, endPoint);
77 if (read > 0)
78 {
79 parse(buffer);
80 }
81 else if (read == 0)
82 {
83 fillInterested();
84 break;
85 }
86 else
87 {
88 shutdown();
89 break;
90 }
91 }
92 }
93 catch (Exception x)
94 {
95 LOG.debug(x);
96
97 }
98 finally
99 {
100 bufferPool.release(buffer);
101 }
102 }
103
104 private void parse(ByteBuffer buffer)
105 {
106 while (buffer.hasRemaining())
107 parser.parse(buffer);
108 }
109
110 private void shutdown()
111 {
112 flusher.shutdown();
113 }
114
115 private class ServerListener implements ServerParser.Listener
116 {
117 @Override
118 public void onStart(int request, FCGI.Role role, int flags)
119 {
120
121 HttpChannelOverFCGI channel = new HttpChannelOverFCGI(connector, configuration, getEndPoint(),
122 new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request), new ByteBufferQueuedHttpInput());
123 HttpChannelOverFCGI existing = channels.putIfAbsent(request, channel);
124 if (existing != null)
125 throw new IllegalStateException();
126 if (LOG.isDebugEnabled())
127 LOG.debug("Request {} start on {}", request, channel);
128 }
129
130 @Override
131 public void onHeader(int request, HttpField field)
132 {
133 HttpChannelOverFCGI channel = channels.get(request);
134 if (LOG.isDebugEnabled())
135 LOG.debug("Request {} header {} on {}", request, field, channel);
136 if (channel != null)
137 channel.header(field);
138 }
139
140 @Override
141 public void onHeaders(int request)
142 {
143 HttpChannelOverFCGI channel = channels.get(request);
144 if (LOG.isDebugEnabled())
145 LOG.debug("Request {} headers on {}", request, channel);
146 if (channel != null)
147 {
148 if (channel.headerComplete())
149 channel.dispatch();
150 }
151 }
152
153 @Override
154 public boolean onContent(int request, FCGI.StreamType stream, ByteBuffer buffer)
155 {
156 HttpChannelOverFCGI channel = channels.get(request);
157 if (LOG.isDebugEnabled())
158 LOG.debug("Request {} {} content {} on {}", request, stream, buffer, channel);
159 if (channel != null)
160 {
161 if (channel.content(buffer))
162 channel.dispatch();
163 }
164 return false;
165 }
166
167 @Override
168 public void onEnd(int request)
169 {
170 HttpChannelOverFCGI channel = channels.remove(request);
171 if (LOG.isDebugEnabled())
172 LOG.debug("Request {} end on {}", request, channel);
173 if (channel != null)
174 {
175 if (channel.messageComplete())
176 channel.dispatch();
177 }
178 }
179
180 @Override
181 public void onFailure(int request, Throwable failure)
182 {
183 HttpChannelOverFCGI channel = channels.remove(request);
184 if (LOG.isDebugEnabled())
185 LOG.debug("Request {} failure on {}: {}", request, channel, failure);
186 if (channel != null)
187 {
188 channel.badMessage(400, failure.toString());
189 }
190 }
191 }
192 }