use of org.eclipse.jetty.http.HttpField in project jetty.project by eclipse.
the class GzipHandler method handle.
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
ServletContext context = baseRequest.getServletContext();
String path = context == null ? baseRequest.getRequestURI() : URIUtil.addPaths(baseRequest.getServletPath(), baseRequest.getPathInfo());
LOG.debug("{} handle {} in {}", this, baseRequest, context);
if (!_dispatchers.contains(baseRequest.getDispatcherType())) {
LOG.debug("{} excluded by dispatcherType {}", this, baseRequest.getDispatcherType());
_handler.handle(target, baseRequest, request, response);
return;
}
// Handle request inflation
if (_inflateBufferSize > 0) {
HttpField ce = baseRequest.getHttpFields().getField(HttpHeader.CONTENT_ENCODING);
if (ce != null && "gzip".equalsIgnoreCase(ce.getValue())) {
// TODO should check ce.contains and then remove just the gzip encoding
baseRequest.getHttpFields().remove(HttpHeader.CONTENT_ENCODING);
baseRequest.getHttpFields().add(new HttpField("X-Content-Encoding", ce.getValue()));
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize));
}
}
// Are we already being gzipped?
HttpOutput out = baseRequest.getResponse().getHttpOutput();
HttpOutput.Interceptor interceptor = out.getInterceptor();
while (interceptor != null) {
if (interceptor instanceof GzipHttpOutputInterceptor) {
LOG.debug("{} already intercepting {}", this, request);
_handler.handle(target, baseRequest, request, response);
return;
}
interceptor = interceptor.getNextInterceptor();
}
// If not a supported method - no Vary because no matter what client, this URI is always excluded
if (!_methods.test(baseRequest.getMethod())) {
LOG.debug("{} excluded by method {}", this, request);
_handler.handle(target, baseRequest, request, response);
return;
}
// Use pathInfo because this is be
if (!isPathGzipable(path)) {
LOG.debug("{} excluded by path {}", this, request);
_handler.handle(target, baseRequest, request, response);
return;
}
// Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
String mimeType = context == null ? MimeTypes.getDefaultMimeByExtension(path) : context.getMimeType(path);
if (mimeType != null) {
mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);
if (!isMimeTypeGzipable(mimeType)) {
LOG.debug("{} excluded by path suffix mime type {}", this, request);
// handle normally without setting vary header
_handler.handle(target, baseRequest, request, response);
return;
}
}
if (_checkGzExists && context != null) {
String realpath = request.getServletContext().getRealPath(path);
if (realpath != null) {
File gz = new File(realpath + ".gz");
if (gz.exists()) {
LOG.debug("{} gzip exists {}", this, request);
// allow default servlet to handle
_handler.handle(target, baseRequest, request, response);
return;
}
}
}
// Special handling for etags
String etag = baseRequest.getHttpFields().get(HttpHeader.IF_NONE_MATCH);
if (etag != null) {
int i = etag.indexOf(CompressedContentFormat.GZIP._etagQuote);
if (i > 0) {
baseRequest.setAttribute("o.e.j.s.h.gzip.GzipHandler.etag", etag);
while (i >= 0) {
etag = etag.substring(0, i) + etag.substring(i + CompressedContentFormat.GZIP._etag.length());
i = etag.indexOf(CompressedContentFormat.GZIP._etagQuote, i);
}
baseRequest.getHttpFields().put(new HttpField(HttpHeader.IF_NONE_MATCH, etag));
}
}
HttpOutput.Interceptor orig_interceptor = out.getInterceptor();
try {
// install interceptor and handle
out.setInterceptor(new GzipHttpOutputInterceptor(this, getVaryField(), baseRequest.getHttpChannel(), orig_interceptor, isSyncFlush()));
if (_handler != null)
_handler.handle(target, baseRequest, request, response);
} finally {
// reset interceptor if request not handled
if (!baseRequest.isHandled() && !baseRequest.isAsyncStarted())
out.setInterceptor(orig_interceptor);
}
}
use of org.eclipse.jetty.http.HttpField in project jetty.project by eclipse.
the class HttpClientTest method testAllHeadersDiscarded.
@Test
public void testAllHeadersDiscarded() throws Exception {
start(new EmptyServerHandler());
int count = 10;
final CountDownLatch latch = new CountDownLatch(count);
for (int i = 0; i < count; ++i) {
client.newRequest("localhost", connector.getLocalPort()).scheme(scheme).send(new Response.Listener.Adapter() {
@Override
public boolean onHeader(Response response, HttpField field) {
return false;
}
@Override
public void onComplete(Result result) {
if (result.isSucceeded())
latch.countDown();
}
});
}
Assert.assertTrue(latch.await(10, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.http.HttpField in project jetty.project by eclipse.
the class HttpClientURITest method testIDNRedirect.
@Test
public void testIDNRedirect() throws Exception {
// Internationalized Domain Name.
// String exampleHost = scheme + "://пример.рф";
String exampleHost = scheme + "://킿톀킸킼킵톀.톀톄";
String incorrectlyDecoded = new String(exampleHost.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
// Simple server that only parses clear-text HTTP/1.1.
IDNRedirectServer server = new IDNRedirectServer(exampleHost);
server.start();
try {
startClient();
ContentResponse response = client.newRequest("localhost", server.getLocalPort()).timeout(5, TimeUnit.SECONDS).followRedirects(false).send();
HttpField location = response.getHeaders().getField(HttpHeader.LOCATION);
Assert.assertEquals(incorrectlyDecoded, location.getValue());
expectedException.expect(ExecutionException.class);
expectedException.expectCause(instanceOf(IllegalArgumentException.class));
client.newRequest("localhost", server.getLocalPort()).timeout(5, TimeUnit.SECONDS).followRedirects(true).send();
} finally {
server.stop();
}
}
use of org.eclipse.jetty.http.HttpField in project jetty.project by eclipse.
the class PushCacheFilter method doFilter.
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
Request jettyRequest = Request.getBaseRequest(request);
if (HttpVersion.fromString(request.getProtocol()).getVersion() < 20 || !HttpMethod.GET.is(request.getMethod()) || !jettyRequest.isPushSupported()) {
chain.doFilter(req, resp);
return;
}
long now = System.nanoTime();
// Iterating over fields is more efficient than multiple gets
HttpFields fields = jettyRequest.getHttpFields();
boolean conditional = false;
String referrer = null;
loop: for (int i = 0; i < fields.size(); i++) {
HttpField field = fields.getField(i);
HttpHeader header = field.getHeader();
if (header == null)
continue;
switch(header) {
case IF_MATCH:
case IF_MODIFIED_SINCE:
case IF_NONE_MATCH:
case IF_UNMODIFIED_SINCE:
conditional = true;
break loop;
case REFERER:
referrer = field.getValue();
break;
default:
break;
}
}
if (LOG.isDebugEnabled())
LOG.debug("{} {} referrer={} conditional={}", request.getMethod(), request.getRequestURI(), referrer, conditional);
String path = request.getRequestURI();
String query = request.getQueryString();
if (_useQueryInKey && query != null)
path += "?" + query;
if (referrer != null) {
HttpURI referrerURI = new HttpURI(referrer);
String host = referrerURI.getHost();
int port = referrerURI.getPort();
if (port <= 0)
port = request.isSecure() ? 443 : 80;
boolean referredFromHere = _hosts.size() > 0 ? _hosts.contains(host) : host.equals(request.getServerName());
referredFromHere &= _ports.size() > 0 ? _ports.contains(port) : port == request.getServerPort();
if (referredFromHere) {
if (HttpMethod.GET.is(request.getMethod())) {
String referrerPath = _useQueryInKey ? referrerURI.getPathQuery() : referrerURI.getPath();
if (referrerPath == null)
referrerPath = "/";
if (referrerPath.startsWith(request.getContextPath() + "/")) {
if (!referrerPath.equals(path)) {
PrimaryResource primaryResource = _cache.get(referrerPath);
if (primaryResource != null) {
long primaryTimestamp = primaryResource._timestamp.get();
if (primaryTimestamp != 0) {
if (now - primaryTimestamp < TimeUnit.MILLISECONDS.toNanos(_associatePeriod)) {
Set<String> associated = primaryResource._associated;
// Not strictly concurrent-safe, just best effort to limit associations.
if (associated.size() <= _maxAssociations) {
if (associated.add(path)) {
if (LOG.isDebugEnabled())
LOG.debug("Associated {} to {}", path, referrerPath);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, exceeded max associations of {}", path, referrerPath, _maxAssociations);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, outside associate period of {}ms", path, referrerPath, _associatePeriod);
}
}
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, referring to self", path, referrerPath);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, different context", path, referrerPath);
}
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("External referrer {}", referrer);
}
}
PrimaryResource primaryResource = _cache.get(path);
if (primaryResource == null) {
PrimaryResource r = new PrimaryResource();
primaryResource = _cache.putIfAbsent(path, r);
primaryResource = primaryResource == null ? r : primaryResource;
primaryResource._timestamp.compareAndSet(0, now);
if (LOG.isDebugEnabled())
LOG.debug("Cached primary resource {}", path);
} else {
long last = primaryResource._timestamp.get();
if (last < _renew && primaryResource._timestamp.compareAndSet(last, now)) {
primaryResource._associated.clear();
if (LOG.isDebugEnabled())
LOG.debug("Clear associated resources for {}", path);
}
}
// Push associated resources.
if (!conditional && !primaryResource._associated.isEmpty()) {
PushBuilder pushBuilder = jettyRequest.getPushBuilder();
// Breadth-first push of associated resources.
Queue<PrimaryResource> queue = new ArrayDeque<>();
queue.offer(primaryResource);
while (!queue.isEmpty()) {
PrimaryResource parent = queue.poll();
for (String childPath : parent._associated) {
PrimaryResource child = _cache.get(childPath);
if (child != null)
queue.offer(child);
if (LOG.isDebugEnabled())
LOG.debug("Pushing {} for {}", childPath, path);
pushBuilder.path(childPath).push();
}
}
}
chain.doFilter(request, resp);
}
use of org.eclipse.jetty.http.HttpField in project jetty.project by eclipse.
the class ClientGenerator method generateRequestHeaders.
public Result generateRequestHeaders(int request, HttpFields fields, Callback callback) {
request &= 0xFF_FF;
final Charset utf8 = StandardCharsets.UTF_8;
List<byte[]> bytes = new ArrayList<>(fields.size() * 2);
int fieldsLength = 0;
for (HttpField field : fields) {
String name = field.getName();
byte[] nameBytes = name.getBytes(utf8);
if (nameBytes.length > MAX_PARAM_LENGTH)
throw new IllegalArgumentException("Field name " + name + " exceeds max length " + MAX_PARAM_LENGTH);
bytes.add(nameBytes);
String value = field.getValue();
byte[] valueBytes = value.getBytes(utf8);
if (valueBytes.length > MAX_PARAM_LENGTH)
throw new IllegalArgumentException("Field value " + value + " exceeds max length " + MAX_PARAM_LENGTH);
bytes.add(valueBytes);
int nameLength = nameBytes.length;
fieldsLength += bytesForLength(nameLength);
int valueLength = valueBytes.length;
fieldsLength += bytesForLength(valueLength);
fieldsLength += nameLength;
fieldsLength += valueLength;
}
// Worst case FCGI_PARAMS frame: long name + long value - both of MAX_PARAM_LENGTH
int maxCapacity = 4 + 4 + 2 * MAX_PARAM_LENGTH;
// One FCGI_BEGIN_REQUEST + N FCGI_PARAMS + one last FCGI_PARAMS
ByteBuffer beginRequestBuffer = byteBufferPool.acquire(16, false);
BufferUtil.clearToFill(beginRequestBuffer);
Result result = new Result(byteBufferPool, callback);
result = result.append(beginRequestBuffer, true);
// Generate the FCGI_BEGIN_REQUEST frame
beginRequestBuffer.putInt(0x01_01_00_00 + request);
beginRequestBuffer.putInt(0x00_08_00_00);
// Hardcode RESPONDER role and KEEP_ALIVE flag
beginRequestBuffer.putLong(0x00_01_01_00_00_00_00_00L);
BufferUtil.flipToFlush(beginRequestBuffer, 0);
int index = 0;
while (fieldsLength > 0) {
int capacity = 8 + Math.min(maxCapacity, fieldsLength);
ByteBuffer buffer = byteBufferPool.acquire(capacity, true);
BufferUtil.clearToFill(buffer);
result = result.append(buffer, true);
// Generate the FCGI_PARAMS frame
buffer.putInt(0x01_04_00_00 + request);
buffer.putShort((short) 0);
buffer.putShort((short) 0);
capacity -= 8;
int length = 0;
while (index < bytes.size()) {
byte[] nameBytes = bytes.get(index);
int nameLength = nameBytes.length;
byte[] valueBytes = bytes.get(index + 1);
int valueLength = valueBytes.length;
int required = bytesForLength(nameLength) + bytesForLength(valueLength) + nameLength + valueLength;
if (required > capacity)
break;
putParamLength(buffer, nameLength);
putParamLength(buffer, valueLength);
buffer.put(nameBytes);
buffer.put(valueBytes);
length += required;
fieldsLength -= required;
capacity -= required;
index += 2;
}
buffer.putShort(4, (short) length);
BufferUtil.flipToFlush(buffer, 0);
}
ByteBuffer lastParamsBuffer = byteBufferPool.acquire(8, false);
BufferUtil.clearToFill(lastParamsBuffer);
result = result.append(lastParamsBuffer, true);
// Generate the last FCGI_PARAMS frame
lastParamsBuffer.putInt(0x01_04_00_00 + request);
lastParamsBuffer.putInt(0x00_00_00_00);
BufferUtil.flipToFlush(lastParamsBuffer, 0);
return result;
}
Aggregations