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 boolean headerComplete()
57 {
58 headersComplete = true;
59 return super.headerComplete();
60 }
61
62 private void dispatch()
63 {
64 synchronized (this)
65 {
66 if (dispatched)
67 redispatch=true;
68 else
69 {
70 LOG.debug("Dispatch {}", this);
71 dispatched=true;
72 execute(this);
73 }
74 }
75 }
76
77 @Override
78 public void run()
79 {
80 boolean execute=true;
81
82 while(execute)
83 {
84 try
85 {
86 LOG.debug("Executing {}",this);
87 super.run();
88 }
89 finally
90 {
91 LOG.debug("Completing {}", this);
92 synchronized (this)
93 {
94 dispatched = redispatch;
95 redispatch=false;
96 execute=dispatched;
97 }
98 }
99 }
100 }
101
102
103 public void requestStart(final Fields headers, final boolean endRequest)
104 {
105 if (!headers.isEmpty())
106 requestHeaders(headers, endRequest);
107 }
108
109 public void requestHeaders(Fields headers, boolean endRequest)
110 {
111 boolean proceed = performBeginRequest(headers);
112 if (!proceed)
113 return;
114
115 performHeaders(headers);
116
117 if (endRequest)
118 {
119 boolean dispatch = headerComplete();
120 if (messageComplete())
121 dispatch=true;
122 if (dispatch)
123 dispatch();
124 }
125 }
126
127 public void requestContent(final DataInfo dataInfo, boolean endRequest)
128 {
129 boolean dispatch=false;
130 if (!headersComplete && headerComplete())
131 dispatch=true;
132
133 LOG.debug("HTTP > {} bytes of content", dataInfo.length());
134
135
136
137
138 ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false);
139 ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose())
140 {
141 @Override
142 public void consume(int delta)
143 {
144 super.consume(delta);
145 dataInfo.consume(delta);
146 }
147 };
148 LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo);
149
150 if (content(copyDataInfo))
151 dispatch=true;
152
153 if (endRequest && messageComplete())
154 dispatch=true;
155
156 if (dispatch)
157 dispatch();
158 }
159
160 private boolean performBeginRequest(Fields headers)
161 {
162 short version = stream.getSession().getVersion();
163 Fields.Field methodHeader = headers.get(HTTPSPDYHeader.METHOD.name(version));
164 Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version));
165 Fields.Field versionHeader = headers.get(HTTPSPDYHeader.VERSION.name(version));
166
167 if (methodHeader == null || uriHeader == null || versionHeader == null)
168 {
169 badMessage(400, "Missing required request line elements");
170 return false;
171 }
172
173 HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue());
174 HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue());
175
176
177
178 ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue());
179
180 LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion);
181 startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
182
183 Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
184 if (schemeHeader != null)
185 getRequest().setScheme(schemeHeader.getValue());
186 return true;
187 }
188
189 private void performHeaders(Fields headers)
190 {
191 for (Fields.Field header : headers)
192 {
193 String name = header.getName();
194
195
196 HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(stream.getSession().getVersion(), name);
197 if (specialHeader != null)
198 {
199 if (specialHeader == HTTPSPDYHeader.HOST)
200 name = "host";
201 else
202 continue;
203 }
204
205 switch (name)
206 {
207 case "connection":
208 case "keep-alive":
209 case "proxy-connection":
210 case "transfer-encoding":
211 {
212
213 continue;
214 }
215 default:
216 {
217
218 String value = header.getValue();
219 LOG.debug("HTTP > {}: {}", name, value);
220 parsedHeader(new HttpField(name,value));
221 break;
222 }
223 }
224 }
225 }
226 }