diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java index 22bbfc765..db84d4d36 100644 --- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java +++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedHttpResponseGenerator.java @@ -168,4 +168,35 @@ class CachedHttpResponseGenerator { return request.getMethod().equals(HeaderConstants.GET_METHOD) && cacheEntry.getResource() != null; } + /** + * Extract error information about the {@link HttpRequest} telling the 'caller' + * that a problem occured. + * + * @param errorCheck What type of error should I get + * @return The {@link ClassicHttpResponse} that is the error generated + */ + public ClassicHttpResponse getErrorForRequest(final RequestProtocolError errorCheck) { + switch (errorCheck) { + case BODY_BUT_NO_LENGTH_ERROR: + return new BasicClassicHttpResponse(HttpStatus.SC_LENGTH_REQUIRED, ""); + + case WEAK_ETAG_AND_RANGE_ERROR: + return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, + "Weak eTag not compatible with byte range"); + + case WEAK_ETAG_ON_PUTDELETE_METHOD_ERROR: + return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, + "Weak eTag not compatible with PUT or DELETE requests"); + + case NO_CACHE_DIRECTIVE_WITH_FIELD_NAME: + return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, + "No-Cache directive MUST NOT include a field name"); + + default: + throw new IllegalStateException( + "The request was compliant, therefore no error can be generated for it."); + + } + } + } diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java index df951a79a..d6e930de9 100644 --- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java +++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExec.java @@ -360,7 +360,7 @@ public class CachingExec implements ExecChainHandler { for (final RequestProtocolError error : fatalError) { setResponseStatus(context, CacheResponseStatus.CACHE_MODULE_RESPONSE); - fatalErrorResponse = requestCompliance.getErrorForRequest(error); + fatalErrorResponse = responseGenerator.getErrorForRequest(error); } return fatalErrorResponse; } diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/RequestProtocolCompliance.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/RequestProtocolCompliance.java index c21b80dec..99affcb3b 100644 --- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/RequestProtocolCompliance.java +++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/RequestProtocolCompliance.java @@ -31,25 +31,14 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; -import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.cache.HeaderConstants; import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.ThreadingBehavior; -import org.apache.hc.core5.http.ClassicHttpRequest; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HeaderElement; -import org.apache.hc.core5.http.HeaderElements; -import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpRequest; -import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.ProtocolVersion; -import org.apache.hc.core5.http.io.entity.HttpEntityWrapper; -import org.apache.hc.core5.http.message.BasicClassicHttpResponse; -import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.message.MessageSupport; /** @@ -107,17 +96,8 @@ class RequestProtocolCompliance { * fix the request here. * * @param request the request to check for compliance - * @throws ClientProtocolException when we have trouble making the request compliant */ - public void makeRequestCompliant(final ClassicHttpRequest request) - throws ClientProtocolException { - - if (requestMustNotHaveEntity(request)) { - request.setEntity(null); - } - - verifyRequestWithExpectContinueFlagHas100continueHeader(request); - verifyOPTIONSRequestWithBodyHasContentType(request); + public void makeRequestCompliant(final HttpRequest request) { decrementOPTIONSMaxForwardsIfGreaterThen0(request); stripOtherFreshnessDirectivesWithNoCache(request); @@ -160,10 +140,6 @@ class RequestProtocolCompliance { return newHdr.toString(); } - private boolean requestMustNotHaveEntity(final HttpRequest request) { - return HeaderConstants.TRACE_METHOD.equals(request.getMethod()); - } - private void decrementOPTIONSMaxForwardsIfGreaterThen0(final HttpRequest request) { if (!HeaderConstants.OPTIONS_METHOD.equals(request.getMethod())) { return; @@ -180,81 +156,6 @@ class RequestProtocolCompliance { request.setHeader(HeaderConstants.MAX_FORWARDS, Integer.toString(currentMaxForwards - 1)); } - private void verifyOPTIONSRequestWithBodyHasContentType(final ClassicHttpRequest request) { - if (!HeaderConstants.OPTIONS_METHOD.equals(request.getMethod())) { - return; - } - - addContentTypeHeaderIfMissing(request); - } - - private void addContentTypeHeaderIfMissing(final ClassicHttpRequest request) { - final HttpEntity entity = request.getEntity(); - if (entity != null && entity.getContentType() == null) { - final HttpEntityWrapper entityWrapper = new HttpEntityWrapper(entity) { - - @Override - public String getContentType() { - return ContentType.APPLICATION_OCTET_STREAM.getMimeType(); - } - - }; - request.setEntity(entityWrapper); - } - } - - private void verifyRequestWithExpectContinueFlagHas100continueHeader(final ClassicHttpRequest request) { - if (request.containsHeader(HttpHeaders.EXPECT) && request.getEntity() != null) { - add100ContinueHeaderIfMissing(request); - } else { - remove100ContinueHeaderIfExists(request); - } - } - - private void remove100ContinueHeaderIfExists(final HttpRequest request) { - boolean hasHeader = false; - - final Header[] expectHeaders = request.getHeaders(HttpHeaders.EXPECT); - List expectElementsThatAreNot100Continue = new ArrayList<>(); - - for (final Header h : expectHeaders) { - for (final HeaderElement elt : MessageSupport.parse(h)) { - if (!(HeaderElements.CONTINUE.equalsIgnoreCase(elt.getName()))) { - expectElementsThatAreNot100Continue.add(elt); - } else { - hasHeader = true; - } - } - - if (hasHeader) { - request.removeHeader(h); - for (final HeaderElement elt : expectElementsThatAreNot100Continue) { - final BasicHeader newHeader = new BasicHeader(HeaderElements.CONTINUE, elt.getName()); - request.addHeader(newHeader); - } - return; - } else { - expectElementsThatAreNot100Continue = new ArrayList<>(); - } - } - } - - private void add100ContinueHeaderIfMissing(final HttpRequest request) { - boolean hasHeader = false; - - final Iterator it = MessageSupport.iterate(request, HttpHeaders.EXPECT); - while (it.hasNext()) { - final HeaderElement elt = it.next(); - if (HeaderElements.CONTINUE.equalsIgnoreCase(elt.getName())) { - hasHeader = true; - } - } - - if (!hasHeader) { - request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE); - } - } - protected boolean requestMinorVersionIsTooHighMajorVersionsMatch(final HttpRequest request) { final ProtocolVersion requestProtocol = request.getVersion(); if (requestProtocol == null) { @@ -276,37 +177,6 @@ class RequestProtocolCompliance { return requestProtocol != null && requestProtocol.compareToVersion(HttpVersion.HTTP_1_1) < 0; } - /** - * Extract error information about the {@link HttpRequest} telling the 'caller' - * that a problem occured. - * - * @param errorCheck What type of error should I get - * @return The {@link ClassicHttpResponse} that is the error generated - */ - public ClassicHttpResponse getErrorForRequest(final RequestProtocolError errorCheck) { - switch (errorCheck) { - case BODY_BUT_NO_LENGTH_ERROR: - return new BasicClassicHttpResponse(HttpStatus.SC_LENGTH_REQUIRED, ""); - - case WEAK_ETAG_AND_RANGE_ERROR: - return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, - "Weak eTag not compatible with byte range"); - - case WEAK_ETAG_ON_PUTDELETE_METHOD_ERROR: - return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, - "Weak eTag not compatible with PUT or DELETE requests"); - - case NO_CACHE_DIRECTIVE_WITH_FIELD_NAME: - return new BasicClassicHttpResponse(HttpStatus.SC_BAD_REQUEST, - "No-Cache directive MUST NOT include a field name"); - - default: - throw new IllegalStateException( - "The request was compliant, therefore no error can be generated for it."); - - } - } - private RequestProtocolError requestHasWeakETagAndRange(final HttpRequest request) { // TODO: Should these be looking at all the headers marked as Range? final String method = request.getMethod(); diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java index b1340c133..0d618bee7 100644 --- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java +++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java @@ -36,12 +36,9 @@ import org.apache.hc.client5.http.cache.HeaderConstants; import org.apache.hc.client5.http.utils.DateUtils; import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.ThreadingBehavior; -import org.apache.hc.core5.http.ClassicHttpRequest; -import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HeaderElement; import org.apache.hc.core5.http.HeaderElements; -import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; @@ -72,14 +69,9 @@ class ResponseProtocolCompliance { * @throws IOException Bad things happened */ public void ensureProtocolCompliance( - final ClassicHttpRequest originalRequest, - final ClassicHttpRequest request, - final ClassicHttpResponse response) throws IOException { - if (backendResponseMustNotHaveBody(request, response)) { - consumeBody(response); - response.setEntity(null); - } - + final HttpRequest originalRequest, + final HttpRequest request, + final HttpResponse response) throws IOException { requestDidNotExpect100ContinueButResponseIsOne(originalRequest, response); transferEncodingIsNotReturnedTo1_0Client(originalRequest, response); @@ -97,13 +89,6 @@ class ResponseProtocolCompliance { warningsWithNonMatchingWarnDatesAreRemoved(response); } - private void consumeBody(final ClassicHttpResponse response) throws IOException { - final HttpEntity body = response.getEntity(); - if (body != null) { - IOUtils.consume(body); - } - } - private void warningsWithNonMatchingWarnDatesAreRemoved( final HttpResponse response) { final Date responseDate = DateUtils.parseDate(response.getFirstHeader(HttpHeaders.DATE).getValue()); @@ -180,13 +165,11 @@ class ResponseProtocolCompliance { } private void ensurePartialContentIsNotSentToAClientThatDidNotRequestIt(final HttpRequest request, - final ClassicHttpResponse response) throws IOException { + final HttpResponse response) throws IOException { if (request.getFirstHeader(HeaderConstants.RANGE) != null || response.getCode() != HttpStatus.SC_PARTIAL_CONTENT) { return; } - - consumeBody(response); throw new ClientProtocolException(UNEXPECTED_PARTIAL_CONTENT); } @@ -217,15 +200,8 @@ class ResponseProtocolCompliance { } } - private boolean backendResponseMustNotHaveBody(final HttpRequest request, final HttpResponse backendResponse) { - return HeaderConstants.HEAD_METHOD.equals(request.getMethod()) - || backendResponse.getCode() == HttpStatus.SC_NO_CONTENT - || backendResponse.getCode() == HttpStatus.SC_RESET_CONTENT - || backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED; - } - private void requestDidNotExpect100ContinueButResponseIsOne( - final ClassicHttpRequest originalRequest, final ClassicHttpResponse response) throws IOException { + final HttpRequest originalRequest, final HttpResponse response) throws IOException { if (response.getCode() != HttpStatus.SC_CONTINUE) { return; } @@ -234,12 +210,11 @@ class ResponseProtocolCompliance { if (header != null && header.getValue().equalsIgnoreCase(HeaderElements.CONTINUE)) { return; } - consumeBody(response); throw new ClientProtocolException(UNEXPECTED_100_CONTINUE); } private void transferEncodingIsNotReturnedTo1_0Client( - final ClassicHttpRequest originalRequest, final HttpResponse response) { + final HttpRequest originalRequest, final HttpResponse response) { final ProtocolVersion version = originalRequest.getVersion() != null ? originalRequest.getVersion() : HttpVersion.DEFAULT; if (version.compareToVersion(HttpVersion.HTTP_1_1) >= 0) { return; diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java index 9669193e9..14a030f33 100644 --- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java +++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCachingExecChain.java @@ -49,7 +49,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.cache.CacheResponseStatus; import org.apache.hc.client5.http.cache.HttpCacheContext; @@ -359,27 +358,6 @@ public abstract class TestCachingExecChain { verifyMocks(); } - @Test - public void testNonCompliantRequestWrapsAndReThrowsProtocolException() throws Exception { - - final ClientProtocolException expected = new ClientProtocolException("ouch"); - - requestIsFatallyNonCompliant(null); - mockRequestProtocolCompliance.makeRequestCompliant((ClassicHttpRequest) anyObject()); - expectLastCall().andThrow(expected); - - boolean gotException = false; - replayMocks(); - try { - execute(request); - } catch (final ClientProtocolException ex) { - Assert.assertSame(expected, ex); - gotException = true; - } - verifyMocks(); - Assert.assertTrue(gotException); - } - @Test public void testSetsModuleGeneratedResponseContextForCacheOptionsResponse() throws Exception { impl = createCachingExecChain(new BasicHttpCache(), CacheConfig.DEFAULT); diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolDeviations.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolDeviations.java index 48c5f6a47..5f56ff163 100644 --- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolDeviations.java +++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolDeviations.java @@ -254,36 +254,6 @@ public class TestProtocolDeviations { } } - /* - * "If the OPTIONS request includes an entity-body (as indicated by the - * presence of Content-Length or Transfer-Encoding), then the media type - * MUST be indicated by a Content-Type field." - * - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2 - */ - @Test - public void testOPTIONSRequestsWithBodiesAndNoContentTypeHaveOneSupplied() throws Exception { - final ClassicHttpRequest options = new BasicClassicHttpRequest("OPTIONS", "/"); - options.setEntity(body); - options.setHeader("Content-Length", "1"); - - final Capture reqCap = new Capture<>(); - EasyMock.expect( - mockExecChain.proceed( - EasyMock.capture(reqCap), - EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse); - replayMocks(); - - execute(options); - - verifyMocks(); - - final ClassicHttpRequest reqWithBody = reqCap.getValue(); - final HttpEntity reqBody = reqWithBody.getEntity(); - Assert.assertNotNull(reqBody); - Assert.assertNotNull(reqBody.getContentType()); - } - /* * "10.2.7 206 Partial Content ... The request MUST have included a Range * header field (section 14.35) indicating the desired range, and MAY have diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolRequirements.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolRequirements.java index 6eb3436c7..5751cc211 100644 --- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolRequirements.java +++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestProtocolRequirements.java @@ -641,39 +641,6 @@ public class TestProtocolRequirements extends AbstractProtocolTest { Assert.assertFalse(foundExpect); } - /* - * "A client MUST NOT send an Expect request-header field (section 14.20) - * with the '100-continue' expectation if it does not intend to send a - * request body." - * - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 - */ - @Test - public void testExpect100ContinueIsNotSentIfThereIsNoRequestBody() throws Exception { - request.addHeader("Expect", "100-continue"); - final Capture reqCap = new Capture<>(); - EasyMock.expect( - mockExecChain.proceed( - EasyMock.capture(reqCap), - EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse); - - replayMocks(); - execute(request); - verifyMocks(); - final ClassicHttpRequest forwarded = reqCap.getValue(); - boolean foundExpectContinue = false; - - final Iterator it = MessageSupport.iterate(forwarded, HttpHeaders.EXPECT); - while (it.hasNext()) { - final HeaderElement elt = it.next(); - if ("100-continue".equalsIgnoreCase(elt.getName())) { - foundExpectContinue = true; - break; - } - } - Assert.assertFalse(foundExpectContinue); - } - /* * "If a proxy receives a request that includes an Expect request- header * field with the '100-continue' expectation, and the proxy either knows @@ -1030,32 +997,6 @@ public class TestProtocolRequirements extends AbstractProtocolTest { verifyMocks(); } - /* - * "A TRACE request MUST NOT include an entity." - * - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8 - */ - @Test - public void testForwardedTRACERequestsDoNotIncludeAnEntity() throws Exception { - final BasicClassicHttpRequest trace = new BasicClassicHttpRequest("TRACE", "/"); - trace.setEntity(HttpTestUtils.makeBody(entityLength)); - trace.setHeader("Content-Length", Integer.toString(entityLength)); - - final Capture reqCap = new Capture<>(); - - EasyMock.expect( - mockExecChain.proceed( - EasyMock.capture(reqCap), - EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse); - - replayMocks(); - execute(trace); - verifyMocks(); - - final ClassicHttpRequest bodyReq = reqCap.getValue(); - Assert.assertTrue(bodyReq.getEntity() == null || bodyReq.getEntity().getContentLength() == 0); - } - /* * "9.8 TRACE ... Responses to this method MUST NOT be cached." * @@ -1101,32 +1042,6 @@ public class TestProtocolRequirements extends AbstractProtocolTest { final ClassicHttpResponse result = execute(request); verifyMocks(); - - Assert.assertTrue(result.getEntity() == null || result.getEntity().getContentLength() == 0); - } - - /* - * "10.2.6 205 Reset Content ... The response MUST NOT include an entity." - * - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.6 - */ - @Test - public void test205ResponsesDoNotContainMessageBodies() throws Exception { - originResponse = new BasicClassicHttpResponse(HttpStatus.SC_RESET_CONTENT, "Reset Content"); - originResponse.setEntity(HttpTestUtils.makeBody(entityLength)); - - EasyMock.expect( - mockExecChain.proceed( - EasyMock.isA(ClassicHttpRequest.class), - EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse); - - replayMocks(); - - final ClassicHttpResponse result = execute(request); - - verifyMocks(); - - Assert.assertTrue(result.getEntity() == null || result.getEntity().getContentLength() == 0); } /* @@ -1704,8 +1619,6 @@ public class TestProtocolRequirements extends AbstractProtocolTest { final ClassicHttpResponse result = execute(request); verifyMocks(); - - Assert.assertTrue(result.getEntity() == null || result.getEntity().getContentLength() == 0); } /* diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestRequestProtocolCompliance.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestRequestProtocolCompliance.java index a538229c6..b602b895f 100644 --- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestRequestProtocolCompliance.java +++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestRequestProtocolCompliance.java @@ -27,33 +27,30 @@ package org.apache.hc.client5.http.impl.cache; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Arrays; -import org.apache.hc.client5.http.classic.methods.HttpPut; -import org.apache.hc.client5.http.impl.classic.ClassicRequestCopier; -import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.client5.http.impl.RequestCopier; +import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.ProtocolVersion; -import org.apache.hc.core5.http.message.BasicClassicHttpRequest; +import org.apache.hc.core5.http.message.BasicHttpRequest; import org.junit.Before; import org.junit.Test; public class TestRequestProtocolCompliance { private RequestProtocolCompliance impl; - private ClassicHttpRequest req; @Before public void setUp() { - req = HttpTestUtils.makeDefaultRequest(); impl = new RequestProtocolCompliance(false); } @Test public void testRequestWithWeakETagAndRange() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Range", "bytes=0-499"); req.setHeader("If-Range", "W/\"weak\""); assertEquals(1, impl.requestIsFatallyNonCompliant(req).size()); @@ -61,14 +58,14 @@ public class TestRequestProtocolCompliance { @Test public void testRequestWithWeekETagForPUTOrDELETEIfMatch() throws Exception { - req = new HttpPut("http://example.com/"); + final HttpRequest req = new BasicHttpRequest("PUT", "http://example.com/"); req.setHeader("If-Match", "W/\"weak\""); assertEquals(1, impl.requestIsFatallyNonCompliant(req).size()); } @Test public void testRequestWithWeekETagForPUTOrDELETEIfMatchAllowed() throws Exception { - req = new HttpPut("http://example.com/"); + final HttpRequest req = new BasicHttpRequest("PUT", "http://example.com/"); req.setHeader("If-Match", "W/\"weak\""); impl = new RequestProtocolCompliance(true); assertEquals(Arrays.asList(), impl.requestIsFatallyNonCompliant(req)); @@ -76,41 +73,33 @@ public class TestRequestProtocolCompliance { @Test public void testRequestContainsNoCacheDirectiveWithFieldName() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "no-cache=false"); assertEquals(1, impl.requestIsFatallyNonCompliant(req).size()); } @Test public void doesNotModifyACompliantRequest() throws Exception { - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest req = new BasicHttpRequest("GET", "/"); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertTrue(HttpTestUtils.equivalent(req, wrapper)); } - @Test - public void removesEntityFromTRACERequest() throws Exception { - final ClassicHttpRequest request = new BasicClassicHttpRequest("TRACE", "/"); - request.setVersion(HttpVersion.HTTP_1_1); - request.setEntity(HttpTestUtils.makeBody(50)); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(request); - impl.makeRequestCompliant(wrapper); - assertNull(wrapper.getEntity()); - } - @Test public void upgrades1_0RequestTo1_1() throws Exception { - req = new BasicClassicHttpRequest("GET", "/"); + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setVersion(HttpVersion.HTTP_1_0); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals(HttpVersion.HTTP_1_1, wrapper.getVersion()); } @Test public void downgrades1_2RequestTo1_1() throws Exception { - req = new BasicClassicHttpRequest("GET", "/"); + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setVersion(new ProtocolVersion("HTTP", 1, 2)); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals(HttpVersion.HTTP_1_1, wrapper.getVersion()); } @@ -118,8 +107,9 @@ public class TestRequestProtocolCompliance { @Test public void stripsMinFreshFromRequestIfNoCachePresent() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "no-cache, min-fresh=10"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals("no-cache", wrapper.getFirstHeader("Cache-Control").getValue()); @@ -128,8 +118,9 @@ public class TestRequestProtocolCompliance { @Test public void stripsMaxFreshFromRequestIfNoCachePresent() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "no-cache, max-stale=10"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals("no-cache", wrapper.getFirstHeader("Cache-Control").getValue()); @@ -138,8 +129,9 @@ public class TestRequestProtocolCompliance { @Test public void stripsMaxAgeFromRequestIfNoCachePresent() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "no-cache, max-age=10"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals("no-cache", wrapper.getFirstHeader("Cache-Control").getValue()); @@ -148,8 +140,9 @@ public class TestRequestProtocolCompliance { @Test public void doesNotStripMinFreshFromRequestWithoutNoCache() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "min-fresh=10"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals("min-fresh=10", wrapper.getFirstHeader("Cache-Control").getValue()); @@ -158,8 +151,9 @@ public class TestRequestProtocolCompliance { @Test public void correctlyStripsMinFreshFromMiddleIfNoCache() throws Exception { + final HttpRequest req = new BasicHttpRequest("GET", "/"); req.setHeader("Cache-Control", "no-cache,min-fresh=10,no-store"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = RequestCopier.INSTANCE.copy(req); impl.makeRequestCompliant(wrapper); assertEquals("no-cache,no-store", wrapper.getFirstHeader("Cache-Control").getValue()); diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseProtocolCompliance.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseProtocolCompliance.java index 7410c1bad..c8cf2d7d6 100644 --- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseProtocolCompliance.java +++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestResponseProtocolCompliance.java @@ -26,136 +26,49 @@ */ package org.apache.hc.client5.http.impl.cache; -import static junit.framework.TestCase.assertNull; -import static junit.framework.TestCase.assertTrue; - -import java.io.ByteArrayInputStream; import java.util.Date; import org.apache.hc.client5.http.ClientProtocolException; -import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.classic.methods.HttpHead; import org.apache.hc.client5.http.impl.classic.ClassicRequestCopier; import org.apache.hc.client5.http.utils.DateUtils; -import org.apache.hc.core5.http.ClassicHttpRequest; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; -import org.apache.hc.core5.http.io.entity.ByteArrayEntity; -import org.apache.hc.core5.http.io.entity.InputStreamEntity; -import org.apache.hc.core5.http.message.BasicClassicHttpRequest; -import org.apache.hc.core5.http.message.BasicClassicHttpResponse; +import org.apache.hc.core5.http.message.BasicHttpResponse; import org.junit.Before; import org.junit.Test; public class TestResponseProtocolCompliance { - private HttpRoute route; private ResponseProtocolCompliance impl; @Before public void setUp() { - route = new HttpRoute(new HttpHost("foo.example.com", 80)); impl = new ResponseProtocolCompliance(); } - private static class Flag { - public boolean set; - } - - private void setMinimalResponseHeaders(final ClassicHttpResponse resp) { + private void setMinimalResponseHeaders(final HttpResponse resp) { resp.setHeader("Date", DateUtils.formatDate(new Date())); resp.setHeader("Server", "MyServer/1.0"); } - private ByteArrayInputStream makeTrackableBody(final int nbytes, final Flag closed) { - final byte[] buf = HttpTestUtils.getRandomBytes(nbytes); - final ByteArrayInputStream bais = new ByteArrayInputStream(buf) { - @Override - public void close() { - closed.set = true; - } - }; - return bais; - } - - private ClassicHttpResponse makePartialResponse(final int nbytes) { - final ClassicHttpResponse resp = new BasicClassicHttpResponse(HttpStatus.SC_PARTIAL_CONTENT, "Partial Content"); + private HttpResponse makePartialResponse(final int nbytes) { + final HttpResponse resp = new BasicHttpResponse(HttpStatus.SC_PARTIAL_CONTENT, "Partial Content"); setMinimalResponseHeaders(resp); resp.setHeader("Content-Length","" + nbytes); resp.setHeader("Content-Range","0-127/256"); return resp; } - @Test - public void consumesBodyIfOriginSendsOneInResponseToHEAD() throws Exception { - final HttpHead req = new HttpHead("http://foo.example.com/"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); - final int nbytes = 128; - final ClassicHttpResponse resp = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK"); - setMinimalResponseHeaders(resp); - resp.setHeader("Content-Length","" + nbytes); - - final Flag closed = new Flag(); - final ByteArrayInputStream bais = makeTrackableBody(nbytes, closed); - resp.setEntity(new InputStreamEntity(bais, -1)); - - impl.ensureProtocolCompliance(wrapper, req, resp); - assertNull(resp.getEntity()); - assertTrue(closed.set || bais.read() == -1); - } - @Test(expected=ClientProtocolException.class) public void throwsExceptionIfOriginReturnsPartialResponseWhenNotRequested() throws Exception { final HttpGet req = new HttpGet("http://foo.example.com/"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); + final HttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); final int nbytes = 128; - final ClassicHttpResponse resp = makePartialResponse(nbytes); - resp.setEntity(HttpTestUtils.makeBody(nbytes)); + final HttpResponse resp = makePartialResponse(nbytes); impl.ensureProtocolCompliance(wrapper, req, resp); } - @Test - public void consumesPartialContentFromOriginEvenIfNotRequested() throws Exception { - final HttpGet req = new HttpGet("http://foo.example.com/"); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); - final int nbytes = 128; - final ClassicHttpResponse resp = makePartialResponse(nbytes); - - final Flag closed = new Flag(); - final ByteArrayInputStream bais = makeTrackableBody(nbytes, closed); - resp.setEntity(new InputStreamEntity(bais, -1)); - - try { - impl.ensureProtocolCompliance(wrapper, req, resp); - } catch (final ClientProtocolException expected) { - } - assertTrue(closed.set || bais.read() == -1); - } - - @Test - public void consumesBodyOf100ContinueResponseIfItArrives() throws Exception { - final ClassicHttpRequest req = new BasicClassicHttpRequest("POST", "/"); - final int nbytes = 128; - req.setHeader("Content-Length","" + nbytes); - req.setHeader("Content-Type", "application/octet-stream"); - final HttpEntity postBody = new ByteArrayEntity(HttpTestUtils.getRandomBytes(nbytes)); - req.setEntity(postBody); - final ClassicHttpRequest wrapper = ClassicRequestCopier.INSTANCE.copy(req); - - final ClassicHttpResponse resp = new BasicClassicHttpResponse(HttpStatus.SC_CONTINUE, "Continue"); - final Flag closed = new Flag(); - final ByteArrayInputStream bais = makeTrackableBody(nbytes, closed); - resp.setEntity(new InputStreamEntity(bais, -1)); - - try { - impl.ensureProtocolCompliance(wrapper, req, resp); - } catch (final ClientProtocolException expected) { - } - assertTrue(closed.set || bais.read() == -1); - } - }