Fixed code and tests, first clean build.
This commit is contained in:
parent
b08e415ca0
commit
24d4a971d2
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue