Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
ec143aa0c5
|
@ -17,7 +17,7 @@
|
|||
:revdate: {localdate}
|
||||
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:toclevels: 5
|
||||
|
||||
:idseparator: -
|
||||
:sectlinks:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<link rel="stylesheet" href="../toc.css">
|
||||
<script src="../toc.js"></script>
|
|
@ -15,6 +15,7 @@
|
|||
:toc-title: Operations Guide
|
||||
:breadcrumb: Home:../index.html | Operations Guide:./index.html
|
||||
:idprefix: og-
|
||||
:docinfo: private-head
|
||||
|
||||
include::../config.adoc[]
|
||||
include::.asciidoctorconfig[]
|
||||
|
|
|
@ -136,7 +136,11 @@ Jetty supports ALPN and encrypted HTTP/2 with this configuration:
|
|||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=tlsALPNHTTP]
|
||||
----
|
||||
|
||||
Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: TLS, ALPN, HTTP/1.1, HTTP/2.
|
||||
Note how the ``ConnectionFactory``s passed to `ServerConnector` are in order: TLS, ALPN, HTTP/2, HTTP/1.1.
|
||||
|
||||
Jetty starts parsing TLS bytes so that it can obtain the ALPN extension.
|
||||
With the ALPN extension information, Jetty can negotiate a protocol and pick, among the ``ConnectionFactory``s supported by the `ServerConnector`, the `ConnectionFactory` correspondent to the negotiated protocol.
|
||||
|
||||
The fact that the HTTP/2 protocol comes before the HTTP/1.1 protocol indicates that HTTP/2 is the preferred protocol for the server.
|
||||
|
||||
Note also that the default protocol set in the ALPN ``ConnectionFactory``, which is used in case ALPN is not supported by the client, is HTTP/1.1 -- if the client does not support ALPN is probably an old client so HTTP/1.1 is the safest choice.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* ========================================================================
|
||||
* Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.toc-current {
|
||||
font-weight: bold;
|
||||
}
|
||||
.toc-item {
|
||||
padding-right: 0.4em;
|
||||
}
|
||||
.toc-toggle {
|
||||
padding-right: 0.4em;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => dynamicTOC());
|
||||
|
||||
function dynamicTOC() {
|
||||
// Bind a click listener to all section titles.
|
||||
const content = document.getElementById('content');
|
||||
const sectionTitles = content.querySelectorAll('a.link');
|
||||
for (const sectionTitle of sectionTitles) {
|
||||
sectionTitle.addEventListener('click', event => collapseThenExpand(event.target.hash));
|
||||
}
|
||||
|
||||
// Bind a click listener to all TOC titles.
|
||||
const toc = document.getElementById('toc');
|
||||
const tocTitles = toc.querySelectorAll('a');
|
||||
for (const tocTitle of tocTitles) {
|
||||
tocTitle.addEventListener('click', event => collapseThenExpand(event.target.hash));
|
||||
}
|
||||
|
||||
// Add the icons to TOC nodes.
|
||||
const nodes = toc.querySelectorAll('li');
|
||||
for (const node of nodes) {
|
||||
const span = document.createElement('span');
|
||||
const css = span.classList;
|
||||
if (node.querySelector(':scope > ul')) {
|
||||
css.add('toc-toggle');
|
||||
// Font-Awesome classes.
|
||||
css.add('fa');
|
||||
css.add('fa-caret-right');
|
||||
span.addEventListener('click', event => toggle(event.target));
|
||||
} else {
|
||||
css.add('toc-item');
|
||||
// The "icon" is the • HTML entity.
|
||||
span.appendChild(document.createTextNode('•'));
|
||||
}
|
||||
node.prepend(span);
|
||||
}
|
||||
|
||||
collapseThenExpand(document.location.hash);
|
||||
}
|
||||
|
||||
function collapseThenExpand(hash) {
|
||||
const toc = document.getElementById('toc');
|
||||
if (hash) {
|
||||
const current = toc.querySelector('a.toc-current');
|
||||
if (current) {
|
||||
current.classList.remove('toc-current');
|
||||
}
|
||||
const anchor = toc.querySelector('a[href="' + hash + '"');
|
||||
if (anchor) {
|
||||
anchor.classList.add('toc-current');
|
||||
collapse(toc);
|
||||
expand(anchor.parentNode);
|
||||
}
|
||||
} else {
|
||||
collapse(toc);
|
||||
}
|
||||
}
|
||||
|
||||
function collapse(node) {
|
||||
const sections = node.querySelectorAll('ul');
|
||||
for (const section of sections) {
|
||||
const css = section.classList;
|
||||
// Always show first levels TOC titles.
|
||||
const alwaysShow = css.contains('sectlevel1') || css.contains('sectlevel2');
|
||||
if (!alwaysShow) {
|
||||
css.add('hidden');
|
||||
}
|
||||
}
|
||||
// Show the collapsed icon.
|
||||
const spans = node.querySelectorAll('span.toc-toggle');
|
||||
for (const span of spans) {
|
||||
const css = span.classList;
|
||||
css.remove('fa-caret-down');
|
||||
css.add('fa-caret-right');
|
||||
}
|
||||
}
|
||||
|
||||
function expand(node) {
|
||||
const root = document.getElementById('toc').querySelector('ul');
|
||||
// Show the current node and its ancestors.
|
||||
let parent = node;
|
||||
while (parent !== root) {
|
||||
// Show the node.
|
||||
parent.classList.remove('hidden');
|
||||
// Show the expanded icon.
|
||||
const span = parent.querySelector(':scope > span.toc-toggle');
|
||||
if (span) {
|
||||
const css = span.classList;
|
||||
css.remove('fa-caret-right');
|
||||
css.add('fa-caret-down');
|
||||
}
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
// Show the children.
|
||||
const children = node.querySelector(':scope > ul');
|
||||
if (children) {
|
||||
children.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(span) {
|
||||
const css = span.classList;
|
||||
const expanded = css.contains('fa-caret-down');
|
||||
if (expanded) {
|
||||
collapse(span.parentNode);
|
||||
} else {
|
||||
expand(span.parentNode);
|
||||
}
|
||||
}
|
|
@ -331,7 +331,7 @@ public class HTTPServerDocs
|
|||
SslConnectionFactory tls = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
|
||||
|
||||
// The ServerConnector instance.
|
||||
ServerConnector connector = new ServerConnector(server, tls, alpn, http11, h2);
|
||||
ServerConnector connector = new ServerConnector(server, tls, alpn, h2, http11);
|
||||
connector.setPort(8443);
|
||||
|
||||
server.addConnector(connector);
|
||||
|
|
|
@ -36,7 +36,7 @@ public class RoleInfo
|
|||
/**
|
||||
* List of permitted roles
|
||||
*/
|
||||
private final Set<String> _roles = new CopyOnWriteArraySet<String>();
|
||||
private final Set<String> _roles = new CopyOnWriteArraySet<>();
|
||||
|
||||
public RoleInfo()
|
||||
{
|
||||
|
@ -135,26 +135,28 @@ public class RoleInfo
|
|||
{
|
||||
if (other._forbidden)
|
||||
setForbidden(true);
|
||||
else if (!other._checked) // TODO is this the right way around???
|
||||
else if (other._checked)
|
||||
{
|
||||
setChecked(true);
|
||||
else if (other._isAnyRole)
|
||||
setAnyRole(true);
|
||||
else if (other._isAnyAuth)
|
||||
if (other._isAnyAuth)
|
||||
setAnyAuth(true);
|
||||
else if (!_isAnyRole)
|
||||
{
|
||||
for (String r : other._roles)
|
||||
{
|
||||
_roles.add(r);
|
||||
}
|
||||
}
|
||||
if (other._isAnyRole)
|
||||
setAnyRole(true);
|
||||
|
||||
_roles.addAll(other._roles);
|
||||
}
|
||||
setUserDataConstraint(other._userDataConstraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{RoleInfo" + (_forbidden ? ",F" : "") + (_checked ? ",C" : "") + (_isAnyRole ? ",*" : _roles) + (_userDataConstraint != null ? "," + _userDataConstraint : "") + "}";
|
||||
return String.format("RoleInfo@%x{%s%s%s%s,%s}",
|
||||
hashCode(),
|
||||
(_forbidden ? "Forbidden," : ""),
|
||||
(_checked ? "Checked," : ""),
|
||||
(_isAnyAuth ? "AnyAuth," : ""),
|
||||
(_isAnyRole ? "*" : _roles),
|
||||
_userDataConstraint);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -69,6 +70,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
|||
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.in;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -87,9 +89,17 @@ public class ConstraintTest
|
|||
private LocalConnector _connector;
|
||||
private ConstraintSecurityHandler _security;
|
||||
private HttpConfiguration _config;
|
||||
private Constraint _forbidConstraint;
|
||||
private Constraint _authAnyRoleConstraint;
|
||||
private Constraint _authAdminConstraint;
|
||||
private Constraint _relaxConstraint;
|
||||
private Constraint _loginPageConstraint;
|
||||
private Constraint _noAuthConstraint;
|
||||
private Constraint _confidentialDataConstraint;
|
||||
private Constraint _anyUserAuthConstraint;
|
||||
|
||||
@BeforeEach
|
||||
public void startServer()
|
||||
public void setupServer()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector(_server);
|
||||
|
@ -138,98 +148,80 @@ public class ConstraintTest
|
|||
|
||||
private List<ConstraintMapping> getConstraintMappings()
|
||||
{
|
||||
Constraint constraint0 = new Constraint();
|
||||
constraint0.setAuthenticate(true);
|
||||
constraint0.setName("forbid");
|
||||
_forbidConstraint = new Constraint();
|
||||
_forbidConstraint.setAuthenticate(true);
|
||||
_forbidConstraint.setName("forbid");
|
||||
ConstraintMapping mapping0 = new ConstraintMapping();
|
||||
mapping0.setPathSpec("/forbid/*");
|
||||
mapping0.setConstraint(constraint0);
|
||||
mapping0.setConstraint(_forbidConstraint);
|
||||
|
||||
Constraint constraint1 = new Constraint();
|
||||
constraint1.setAuthenticate(true);
|
||||
constraint1.setName("auth");
|
||||
constraint1.setRoles(new String[]{Constraint.ANY_ROLE});
|
||||
_authAnyRoleConstraint = new Constraint();
|
||||
_authAnyRoleConstraint.setAuthenticate(true);
|
||||
_authAnyRoleConstraint.setName("auth");
|
||||
_authAnyRoleConstraint.setRoles(new String[]{Constraint.ANY_ROLE});
|
||||
ConstraintMapping mapping1 = new ConstraintMapping();
|
||||
mapping1.setPathSpec("/auth/*");
|
||||
mapping1.setConstraint(constraint1);
|
||||
mapping1.setConstraint(_authAnyRoleConstraint);
|
||||
|
||||
Constraint constraint2 = new Constraint();
|
||||
constraint2.setAuthenticate(true);
|
||||
constraint2.setName("admin");
|
||||
constraint2.setRoles(new String[]{"administrator"});
|
||||
_authAdminConstraint = new Constraint();
|
||||
_authAdminConstraint.setAuthenticate(true);
|
||||
_authAdminConstraint.setName("admin");
|
||||
_authAdminConstraint.setRoles(new String[]{"administrator"});
|
||||
ConstraintMapping mapping2 = new ConstraintMapping();
|
||||
mapping2.setPathSpec("/admin/*");
|
||||
mapping2.setConstraint(constraint2);
|
||||
mapping2.setConstraint(_authAdminConstraint);
|
||||
mapping2.setMethod("GET");
|
||||
ConstraintMapping mapping2o = new ConstraintMapping();
|
||||
mapping2o.setPathSpec("/admin/*");
|
||||
mapping2o.setConstraint(_forbidConstraint);
|
||||
mapping2o.setMethodOmissions(new String[]{"GET"});
|
||||
|
||||
Constraint constraint3 = new Constraint();
|
||||
constraint3.setAuthenticate(false);
|
||||
constraint3.setName("relax");
|
||||
_relaxConstraint = new Constraint();
|
||||
_relaxConstraint.setAuthenticate(false);
|
||||
_relaxConstraint.setName("relax");
|
||||
ConstraintMapping mapping3 = new ConstraintMapping();
|
||||
mapping3.setPathSpec("/admin/relax/*");
|
||||
mapping3.setConstraint(constraint3);
|
||||
mapping3.setConstraint(_relaxConstraint);
|
||||
|
||||
Constraint constraint4 = new Constraint();
|
||||
constraint4.setAuthenticate(true);
|
||||
constraint4.setName("loginpage");
|
||||
constraint4.setRoles(new String[]{"administrator"});
|
||||
_loginPageConstraint = new Constraint();
|
||||
_loginPageConstraint.setAuthenticate(true);
|
||||
_loginPageConstraint.setName("loginpage");
|
||||
_loginPageConstraint.setRoles(new String[]{"administrator"});
|
||||
ConstraintMapping mapping4 = new ConstraintMapping();
|
||||
mapping4.setPathSpec("/testLoginPage");
|
||||
mapping4.setConstraint(constraint4);
|
||||
mapping4.setConstraint(_loginPageConstraint);
|
||||
|
||||
Constraint constraint5 = new Constraint();
|
||||
constraint5.setAuthenticate(false);
|
||||
constraint5.setName("allow forbidden POST");
|
||||
_noAuthConstraint = new Constraint();
|
||||
_noAuthConstraint.setAuthenticate(false);
|
||||
_noAuthConstraint.setName("allow forbidden");
|
||||
ConstraintMapping mapping5 = new ConstraintMapping();
|
||||
mapping5.setPathSpec("/forbid/post");
|
||||
mapping5.setConstraint(constraint5);
|
||||
mapping5.setConstraint(_noAuthConstraint);
|
||||
mapping5.setMethod("POST");
|
||||
ConstraintMapping mapping5o = new ConstraintMapping();
|
||||
mapping5o.setPathSpec("/forbid/post");
|
||||
mapping5o.setConstraint(_forbidConstraint);
|
||||
mapping5o.setMethodOmissions(new String[]{"POST"});
|
||||
|
||||
Constraint constraint6 = new Constraint();
|
||||
constraint6.setAuthenticate(false);
|
||||
constraint6.setName("data constraint");
|
||||
constraint6.setDataConstraint(2);
|
||||
_confidentialDataConstraint = new Constraint();
|
||||
_confidentialDataConstraint.setAuthenticate(false);
|
||||
_confidentialDataConstraint.setName("data constraint");
|
||||
_confidentialDataConstraint.setDataConstraint(Constraint.DC_CONFIDENTIAL);
|
||||
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||
mapping6.setPathSpec("/data/*");
|
||||
mapping6.setConstraint(constraint6);
|
||||
mapping6.setConstraint(_confidentialDataConstraint);
|
||||
|
||||
Constraint constraint7 = new Constraint();
|
||||
constraint7.setAuthenticate(true);
|
||||
constraint7.setName("** constraint");
|
||||
constraint7.setRoles(new String[]{
|
||||
_anyUserAuthConstraint = new Constraint();
|
||||
_anyUserAuthConstraint.setAuthenticate(true);
|
||||
_anyUserAuthConstraint.setName("** constraint");
|
||||
_anyUserAuthConstraint.setRoles(new String[]{
|
||||
Constraint.ANY_AUTH, "user"
|
||||
}); //the "user" role is superfluous once ** has been defined
|
||||
ConstraintMapping mapping7 = new ConstraintMapping();
|
||||
mapping7.setPathSpec("/starstar/*");
|
||||
mapping7.setConstraint(constraint7);
|
||||
mapping7.setConstraint(_anyUserAuthConstraint);
|
||||
|
||||
return Arrays.asList(mapping0, mapping1, mapping2, mapping3, mapping4, mapping5, mapping6, mapping7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstraints() throws Exception
|
||||
{
|
||||
List<ConstraintMapping> mappings = new ArrayList<>(_security.getConstraintMappings());
|
||||
|
||||
assertTrue(mappings.get(0).getConstraint().isForbidden());
|
||||
assertFalse(mappings.get(1).getConstraint().isForbidden());
|
||||
assertFalse(mappings.get(2).getConstraint().isForbidden());
|
||||
assertFalse(mappings.get(3).getConstraint().isForbidden());
|
||||
|
||||
assertFalse(mappings.get(0).getConstraint().isAnyRole());
|
||||
assertTrue(mappings.get(1).getConstraint().isAnyRole());
|
||||
assertFalse(mappings.get(2).getConstraint().isAnyRole());
|
||||
assertFalse(mappings.get(3).getConstraint().isAnyRole());
|
||||
|
||||
assertFalse(mappings.get(0).getConstraint().hasRole("administrator"));
|
||||
assertTrue(mappings.get(1).getConstraint().hasRole("administrator"));
|
||||
assertTrue(mappings.get(2).getConstraint().hasRole("administrator"));
|
||||
assertFalse(mappings.get(3).getConstraint().hasRole("administrator"));
|
||||
|
||||
assertTrue(mappings.get(0).getConstraint().getAuthenticate());
|
||||
assertTrue(mappings.get(1).getConstraint().getAuthenticate());
|
||||
assertTrue(mappings.get(2).getConstraint().getAuthenticate());
|
||||
assertFalse(mappings.get(3).getConstraint().getAuthenticate());
|
||||
return Arrays.asList(mapping0, mapping1, mapping2, mapping2o, mapping3, mapping4, mapping5, mapping5o, mapping6, mapping7);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1803,9 +1795,80 @@ public class ConstraintTest
|
|||
assertThat(response, startsWith("HTTP/1.1 200 "));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/forbid/post HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 403 "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncoveredMethod() throws Exception
|
||||
{
|
||||
ConstraintMapping specificMethod = new ConstraintMapping();
|
||||
specificMethod.setMethod("GET");
|
||||
specificMethod.setPathSpec("/specific/method");
|
||||
specificMethod.setConstraint(_forbidConstraint);
|
||||
_security.addConstraintMapping(specificMethod);
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
Logger.getAnonymousLogger().info("Uncovered method for /specific/method is expected");
|
||||
_server.start();
|
||||
|
||||
assertThat(_security.getPathsWithUncoveredHttpMethods(), contains("/specific/method"));
|
||||
|
||||
String response;
|
||||
response = _connector.getResponse("GET /ctx/specific/method HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 403 "));
|
||||
|
||||
response = _connector.getResponse("POST /ctx/specific/method HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 ")); // This is so stupid, but it is the S P E C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForbidTraceAndOptions() throws Exception
|
||||
{
|
||||
ConstraintMapping forbidTrace = new ConstraintMapping();
|
||||
forbidTrace.setMethod("TRACE");
|
||||
forbidTrace.setPathSpec("/");
|
||||
forbidTrace.setConstraint(_forbidConstraint);
|
||||
ConstraintMapping allowOmitTrace = new ConstraintMapping();
|
||||
allowOmitTrace.setMethodOmissions(new String[] {"TRACE"});
|
||||
allowOmitTrace.setPathSpec("/");
|
||||
allowOmitTrace.setConstraint(_relaxConstraint);
|
||||
|
||||
ConstraintMapping forbidOptions = new ConstraintMapping();
|
||||
forbidOptions.setMethod("OPTIONS");
|
||||
forbidOptions.setPathSpec("/");
|
||||
forbidOptions.setConstraint(_forbidConstraint);
|
||||
ConstraintMapping allowOmitOptions = new ConstraintMapping();
|
||||
allowOmitOptions.setMethodOmissions(new String[] {"OPTIONS"});
|
||||
allowOmitOptions.setPathSpec("/");
|
||||
allowOmitOptions.setConstraint(_relaxConstraint);
|
||||
|
||||
ConstraintMapping someConstraint = new ConstraintMapping();
|
||||
someConstraint.setPathSpec("/some/constaint/*");
|
||||
someConstraint.setConstraint(_noAuthConstraint);
|
||||
|
||||
_security.setConstraintMappings(new ConstraintMapping[] {forbidTrace, allowOmitTrace, forbidOptions, allowOmitOptions, someConstraint});
|
||||
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_server.start();
|
||||
|
||||
assertThat(_security.getPathsWithUncoveredHttpMethods(), Matchers.empty());
|
||||
|
||||
String response;
|
||||
response = _connector.getResponse("TRACE /ctx/some/path HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 403 "));
|
||||
|
||||
response = _connector.getResponse("OPTIONS /ctx/some/path HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 403 "));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/some/path HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 "));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/some/constraint/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 "));
|
||||
|
||||
response = _connector.getResponse("OPTIONS /ctx/some/constraint/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 403 "));
|
||||
}
|
||||
|
||||
private static String authBase64(String authorization)
|
||||
{
|
||||
byte[] raw = authorization.getBytes(ISO_8859_1);
|
||||
|
|
|
@ -684,7 +684,7 @@ public class ResourceService
|
|||
putHeaders(response, content, Response.USE_KNOWN_CONTENT_LENGTH);
|
||||
|
||||
// write the content asynchronously if supported
|
||||
if (request.isAsyncSupported() && content.getContentLengthValue() > response.getBufferSize())
|
||||
if (request.isAsyncSupported())
|
||||
{
|
||||
final AsyncContext context = request.startAsync();
|
||||
context.setTimeout(0);
|
||||
|
|
Loading…
Reference in New Issue