1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.spdy.server.http;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.http.HttpField;
24 import org.eclipse.jetty.http.HttpMethod;
25 import org.eclipse.jetty.http.HttpVersion;
26 import org.eclipse.jetty.io.EndPoint;
27 import org.eclipse.jetty.server.Connector;
28 import org.eclipse.jetty.server.HttpChannel;
29 import org.eclipse.jetty.server.HttpConfiguration;
30 import org.eclipse.jetty.server.HttpTransport;
31 import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
32 import org.eclipse.jetty.spdy.api.DataInfo;
33 import org.eclipse.jetty.spdy.api.Stream;
34 import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
35 import org.eclipse.jetty.util.BufferUtil;
36 import org.eclipse.jetty.util.Fields;
37 import org.eclipse.jetty.util.log.Log;
38 import org.eclipse.jetty.util.log.Logger;
39
40 public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
41 {
42 private static final Logger LOG = Log.getLogger(HttpChannelOverSPDY.class);
43
44 private final Stream stream;
45 private boolean dispatched;
46 private boolean redispatch;
47 private boolean headersComplete;
48
49 public HttpChannelOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInputOverSPDY input, Stream stream)
50 {
51 super(connector, configuration, endPoint, transport, input);
52 this.stream = stream;
53 }
54
55 @Override
56 public long getIdleTimeout()
57 {
58 return stream.getIdleTimeout();
59 }
60
61 @Override
62 public boolean headerComplete()
63 {
64 headersComplete = true;
65 return super.headerComplete();
66 }
67
68 private void dispatch()
69 {
70 synchronized (this)
71 {
72 if (dispatched)
73 redispatch=true;
74 else
75 {
76 if (LOG.isDebugEnabled())
77 LOG.debug("Dispatch {}", this);
78 dispatched=true;
79 execute(this);
80 }
81 }
82 }
83
84 @Override
85 public void run()
86 {
87 boolean execute=true;
88
89 while(execute)
90 {
91 try
92 {
93 if (LOG.isDebugEnabled())
94 LOG.debug("Executing {}",this);
95 super.run();
96 }
97 finally
98 {
99 if (LOG.isDebugEnabled())
100 LOG.debug("Completing {}", this);
101 synchronized (this)
102 {
103 dispatched = redispatch;
104 redispatch=false;
105 execute=dispatched;
106 }
107 }
108 }
109 }
110
111
112 public void requestStart(final Fields headers, final boolean endRequest)
113 {
114 if (!headers.isEmpty())
115 requestHeaders(headers, endRequest);
116 }
117
118 public void requestHeaders(Fields headers, boolean endRequest)
119 {
120 boolean proceed = performBeginRequest(headers);
121 if (!proceed)
122 return;
123
124 performHeaders(headers);
125
126 if (endRequest)
127 {
128 boolean dispatch = headerComplete();
129 if (messageComplete())
130 dispatch=true;
131 if (dispatch)
132 dispatch();
133 }
134 }
135
136 public void requestContent(final DataInfo dataInfo, boolean endRequest)
137 {
138 boolean dispatch=false;
139 if (!headersComplete && headerComplete())
140 dispatch=true;
141
142 if (LOG.isDebugEnabled())
143 LOG.debug("HTTP > {} bytes of content", dataInfo.length());
144
145
146
147
148 ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false);
149 ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose())
150 {
151 @Override
152 public void consume(int delta)
153 {
154 super.consume(delta);
155 dataInfo.consume(delta);
156 }
157 };
158 if (LOG.isDebugEnabled())
159 LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo);
160
161 if (content(copyDataInfo))
162 dispatch=true;
163
164 if (endRequest && messageComplete())
165 dispatch=true;
166
167 if (dispatch)
168 dispatch();
169 }
170
171 @Override
172 public boolean messageComplete()
173 {
174 super.messageComplete();
175 return false;
176 }
177
178 private boolean performBeginRequest(Fields headers)
179 {
180 short version = stream.getSession().getVersion();
181 Fields.Field methodHeader = headers.get(HTTPSPDYHeader.METHOD.name(version));
182 Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version));
183 Fields.Field versionHeader = headers.get(HTTPSPDYHeader.VERSION.name(version));
184
185 if (methodHeader == null || uriHeader == null || versionHeader == null)
186 {
187 badMessage(400, "Missing required request line elements");
188 return false;
189 }
190
191 HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue());
192 HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue());
193
194
195
196 ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue());
197
198 if (LOG.isDebugEnabled())
199 LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion);
200 startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
201
202 Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
203 if (schemeHeader != null)
204 getRequest().setScheme(schemeHeader.getValue());
205 return true;
206 }
207
208 private void performHeaders(Fields headers)
209 {
210 for (Fields.Field header : headers)
211 {
212 String name = header.getName();
213
214
215 HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(stream.getSession().getVersion(), name);
216 if (specialHeader != null)
217 {
218 if (specialHeader == HTTPSPDYHeader.HOST)
219 name = "host";
220 else
221 continue;
222 }
223
224 switch (name)
225 {
226 case "connection":
227 case "keep-alive":
228 case "proxy-connection":
229 case "transfer-encoding":
230 {
231
232 continue;
233 }
234 default:
235 {
236
237 String value = header.getValue();
238 if (LOG.isDebugEnabled())
239 LOG.debug("HTTP > {}: {}", name, value);
240 parsedHeader(new HttpField(name,value));
241 break;
242 }
243 }
244 }
245 }
246 }