Fixed code and tests, first clean build.

This commit is contained in:
Simone Bordet 2013-10-23 16:00:43 +02:00
parent b08e415ca0
commit 24d4a971d2
6 changed files with 96 additions and 74 deletions

View File

@ -45,6 +45,12 @@ public class ResponseContentParser extends StreamContentParser
this.listener = listener; this.listener = listener;
} }
@Override
public void noContent()
{
// Does nothing, since for responses the end of content is signaled via a FCGI_END_REQUEST frame
}
@Override @Override
protected void onContent(ByteBuffer buffer) protected void onContent(ByteBuffer buffer)
{ {

View File

@ -40,15 +40,15 @@ public class ClientParserTest
final int id = 13; final int id = 13;
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
final String statusName = "Status"; final int statusCode = 200;
final int code = 200; final String statusMessage = "OK";
final String contentTypeName = "Content-Type"; final String contentTypeName = "Content-Type";
final String contentTypeValue = "text/html;charset=utf-8"; final String contentTypeValue = "text/html;charset=utf-8";
fields.put(contentTypeName, contentTypeValue); fields.put(contentTypeName, contentTypeValue);
ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool); ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result = generator.generateResponseHeaders(id, code, "OK", fields, null); Generator.Result result = generator.generateResponseHeaders(id, statusCode, statusMessage, fields, null);
// Use the fundamental theorem of arithmetic to test the results. // Use the fundamental theorem of arithmetic to test the results.
// This way we know onHeader() has been called the right number of // This way we know onHeader() has been called the right number of
@ -61,20 +61,26 @@ public class ClientParserTest
final AtomicInteger params = new AtomicInteger(1); final AtomicInteger params = new AtomicInteger(1);
ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter() ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter()
{ {
@Override
public void onBegin(int request, int code, String reason)
{
Assert.assertEquals(statusCode, code);
Assert.assertEquals(statusMessage, reason);
params.set(params.get() * primes[0]);
}
@Override @Override
public void onHeader(int request, HttpField field) public void onHeader(int request, HttpField field)
{ {
Assert.assertEquals(id, request); Assert.assertEquals(id, request);
switch (field.getName()) switch (field.getName())
{ {
case statusName:
Assert.assertTrue(field.getValue().startsWith(String.valueOf(code)));
params.set(params.get() * primes[0]);
break;
case contentTypeName: case contentTypeName:
Assert.assertEquals(contentTypeValue, field.getValue()); Assert.assertEquals(contentTypeValue, field.getValue());
params.set(params.get() * primes[1]); params.set(params.get() * primes[1]);
break; break;
default:
break;
} }
} }
@ -100,15 +106,11 @@ public class ClientParserTest
{ {
final int id = 13; final int id = 13;
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
fields.put("Content-Length", "0");
final int code = 200;
final String contentTypeName = "Content-Length";
final String contentTypeValue = "0";
fields.put(contentTypeName, contentTypeValue);
ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ByteBufferPool byteBufferPool = new MappedByteBufferPool();
ServerGenerator generator = new ServerGenerator(byteBufferPool); ServerGenerator generator = new ServerGenerator(byteBufferPool);
Generator.Result result1 = generator.generateResponseHeaders(id, code, "OK", fields, null); Generator.Result result1 = generator.generateResponseHeaders(id, 200, "OK", fields, null);
Generator.Result result2 = generator.generateResponseContent(id, null, true, null); Generator.Result result2 = generator.generateResponseContent(id, null, true, null);
final AtomicInteger verifier = new AtomicInteger(); final AtomicInteger verifier = new AtomicInteger();

View File

@ -136,9 +136,12 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
private void shutdown() private void shutdown()
{ {
// First close then abort, to be sure that the
// connection cannot be reused from an onFailure()
// handler or by blocking code waiting for completion.
close();
for (HttpChannelOverFCGI channel : channels.values()) for (HttpChannelOverFCGI channel : channels.values())
channel.abort(new EOFException()); channel.abort(new EOFException());
close();
} }
@Override @Override

View File

@ -45,9 +45,9 @@ public class HttpSenderOverFCGI extends HttpSender
// FastCGI headers based on the URI // FastCGI headers based on the URI
URI uri = request.getURI(); URI uri = request.getURI();
String path = uri.getPath(); String path = uri.getRawPath();
fcgiHeaders.put(FCGI.Headers.REQUEST_URI, path); fcgiHeaders.put(FCGI.Headers.REQUEST_URI, path);
String query = uri.getQuery(); String query = uri.getRawQuery();
fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query); fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query);
int lastSegment = path.lastIndexOf('/'); int lastSegment = path.lastIndexOf('/');
String scriptName = lastSegment < 0 ? path : path.substring(lastSegment); String scriptName = lastSegment < 0 ? path : path.substring(lastSegment);

View File

@ -19,7 +19,7 @@
package org.eclipse.jetty.fcgi.server; package org.eclipse.jetty.fcgi.server;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.FCGI;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
@ -42,12 +43,12 @@ public class HttpChannelOverFCGI extends HttpChannel<ByteBuffer>
{ {
private static final Logger LOG = Log.getLogger(HttpChannelOverFCGI.class); private static final Logger LOG = Log.getLogger(HttpChannelOverFCGI.class);
private final List<HttpField> fields = new ArrayList<>();
private final Dispatcher dispatcher; private final Dispatcher dispatcher;
private String method; private String method;
private String uri; private String path;
private String query;
private String version; private String version;
private boolean started;
private List<HttpField> fields;
public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input) public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input)
{ {
@ -58,57 +59,37 @@ public class HttpChannelOverFCGI extends HttpChannel<ByteBuffer>
protected void header(HttpField field) protected void header(HttpField field)
{ {
if (FCGI.Headers.REQUEST_METHOD.equalsIgnoreCase(field.getName())) if (FCGI.Headers.REQUEST_METHOD.equalsIgnoreCase(field.getName()))
{
method = field.getValue(); method = field.getValue();
if (uri != null && version != null)
startRequest();
}
else if (FCGI.Headers.REQUEST_URI.equalsIgnoreCase(field.getName())) else if (FCGI.Headers.REQUEST_URI.equalsIgnoreCase(field.getName()))
{ path = field.getValue();
uri = field.getValue(); else if (FCGI.Headers.QUERY_STRING.equalsIgnoreCase(field.getName()))
if (method != null && version != null) query = field.getValue();
startRequest();
}
else if (FCGI.Headers.SERVER_PROTOCOL.equalsIgnoreCase(field.getName())) else if (FCGI.Headers.SERVER_PROTOCOL.equalsIgnoreCase(field.getName()))
{
version = field.getValue(); version = field.getValue();
if (method != null && uri != null)
startRequest();
}
else else
{ fields.add(field);
if (started)
{
resumeHeaders();
convertHeader(field);
}
else
{
if (fields == null)
fields = new ArrayList<>();
fields.add(field);
}
}
} }
private void startRequest() @Override
public boolean headerComplete()
{ {
started = true; String uri = path;
startRequest(null, method, ByteBuffer.wrap(uri.getBytes(Charset.forName("UTF-8"))), HttpVersion.fromString(version)); if (query != null && query.length() > 0)
resumeHeaders(); uri += "?" + query;
} startRequest(HttpMethod.fromString(method), method, ByteBuffer.wrap(uri.getBytes(StandardCharsets.UTF_8)),
HttpVersion.fromString(version));
private void resumeHeaders() for (HttpField fcgiField : fields)
{
if (fields != null)
{ {
for (HttpField field : fields) HttpField httpField = convertHeader(fcgiField);
convertHeader(field); if (httpField != null)
fields = null; parsedHeader(httpField);
} }
return super.headerComplete();
} }
private void convertHeader(HttpField field) private HttpField convertHeader(HttpField field)
{ {
String name = field.getName(); String name = field.getName();
if (name.startsWith("HTTP_")) if (name.startsWith("HTTP_"))
@ -124,17 +105,9 @@ public class HttpChannelOverFCGI extends HttpChannel<ByteBuffer>
httpName.append(Character.toUpperCase(part.charAt(0))); httpName.append(Character.toUpperCase(part.charAt(0)));
httpName.append(part.substring(1).toLowerCase(Locale.ENGLISH)); httpName.append(part.substring(1).toLowerCase(Locale.ENGLISH));
} }
field = new HttpField(httpName.toString(), field.getValue()); return new HttpField(httpName.toString(), field.getValue());
} }
parsedHeader(field); return null;
}
@Override
public boolean headerComplete()
{
boolean result = super.headerComplete();
started = false;
return result;
} }
protected void dispatch() protected void dispatch()

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.fcgi.generator.ServerGenerator;
import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
public class HttpTransportOverFCGI implements HttpTransport public class HttpTransportOverFCGI implements HttpTransport
@ -33,6 +34,7 @@ public class HttpTransportOverFCGI implements HttpTransport
private final ServerGenerator generator; private final ServerGenerator generator;
private final Flusher flusher; private final Flusher flusher;
private final int request; private final int request;
private volatile boolean head;
public HttpTransportOverFCGI(ByteBufferPool byteBufferPool, Flusher flusher, int request) public HttpTransportOverFCGI(ByteBufferPool byteBufferPool, Flusher flusher, int request)
{ {
@ -44,17 +46,53 @@ public class HttpTransportOverFCGI implements HttpTransport
@Override @Override
public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
{ {
Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), boolean head = this.head = info.isHead();
info.getHttpFields(), new Callback.Adapter()); if (head)
Generator.Result contentResult = generator.generateResponseContent(request, content, lastContent, callback); {
flusher.flush(headersResult, contentResult); if (lastContent)
{
Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(),
info.getHttpFields(), new Callback.Adapter());
Generator.Result contentResult = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, callback);
flusher.flush(headersResult, contentResult);
}
else
{
Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(),
info.getHttpFields(), callback);
flusher.flush(headersResult);
}
}
else
{
Generator.Result headersResult = generator.generateResponseHeaders(request, info.getStatus(), info.getReason(),
info.getHttpFields(), new Callback.Adapter());
Generator.Result contentResult = generator.generateResponseContent(request, content, lastContent, callback);
flusher.flush(headersResult, contentResult);
}
} }
@Override @Override
public void send(ByteBuffer content, boolean lastContent, Callback callback) public void send(ByteBuffer content, boolean lastContent, Callback callback)
{ {
Generator.Result result = generator.generateResponseContent(request, content, lastContent, callback); if (head)
flusher.flush(result); {
if (lastContent)
{
Generator.Result result = generator.generateResponseContent(request, BufferUtil.EMPTY_BUFFER, lastContent, callback);
flusher.flush(result);
}
else
{
// Skip content generation
callback.succeeded();
}
}
else
{
Generator.Result result = generator.generateResponseContent(request, content, lastContent, callback);
flusher.flush(result);
}
} }
@Override @Override