/* * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.hc.core5.http.impl.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; 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.HttpEntity; import org.apache.hc.core5.http.NotImplementedException; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.config.H1Config; import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicClassicHttpResponse; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; public class TestDefaultBHttpServerConnection { @Mock private Socket socket; private DefaultBHttpServerConnection conn; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); conn = new DefaultBHttpServerConnection("http", H1Config.DEFAULT, null, null, DefaultContentLengthStrategy.INSTANCE, DefaultContentLengthStrategy.INSTANCE, DefaultHttpRequestParserFactory.INSTANCE, DefaultHttpResponseWriterFactory.INSTANCE); } @Test public void testBasics() throws Exception { Assert.assertFalse(conn.isOpen()); Assert.assertEquals("[Not bound]", conn.toString()); } @Test public void testReadRequestHead() throws Exception { final String s = "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n"; final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)); Mockito.when(socket.getInputStream()).thenReturn(instream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount()); final ClassicHttpRequest request = conn.receiveRequestHeader(); Assert.assertNotNull(request); Assert.assertEquals("/", request.getPath()); Assert.assertEquals("GET", request.getMethod()); Assert.assertTrue(request.containsHeader("User-Agent")); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); } @Test public void testReadRequestEntityWithContentLength() throws Exception { final String s = "POST / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 3\r\n\r\n123"; final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)); Mockito.when(socket.getInputStream()).thenReturn(instream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount()); final ClassicHttpRequest request = conn.receiveRequestHeader(); Assert.assertNotNull(request); Assert.assertEquals("/", request.getPath()); Assert.assertEquals("POST", request.getMethod()); Assert.assertTrue(request.containsHeader("User-Agent")); Assert.assertNull(request.getEntity()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); conn.receiveRequestEntity(request); final HttpEntity entity = request.getEntity(); Assert.assertNotNull(entity); Assert.assertEquals(3, entity.getContentLength()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); final InputStream content = entity.getContent(); Assert.assertNotNull(content); Assert.assertTrue(content instanceof ContentLengthInputStream); } @Test public void testReadRequestEntityChunckCoded() throws Exception { final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " + "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n"; final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)); Mockito.when(socket.getInputStream()).thenReturn(instream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount()); final ClassicHttpRequest request = conn.receiveRequestHeader(); Assert.assertNotNull(request); Assert.assertEquals("/stuff", request.getPath()); Assert.assertEquals("POST", request.getMethod()); Assert.assertTrue(request.containsHeader("User-Agent")); Assert.assertNull(request.getEntity()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); conn.receiveRequestEntity(request); final HttpEntity entity = request.getEntity(); Assert.assertNotNull(entity); Assert.assertEquals(-1, entity.getContentLength()); Assert.assertEquals(true, entity.isChunked()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); final InputStream content = entity.getContent(); Assert.assertNotNull(content); Assert.assertTrue(content instanceof ChunkedInputStream); } @Test(expected = ProtocolException.class) public void testReadRequestEntityIdentity() throws Exception { final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " + "identity\r\n\r\n123"; final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)); Mockito.when(socket.getInputStream()).thenReturn(instream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount()); final ClassicHttpRequest request = conn.receiveRequestHeader(); Assert.assertNotNull(request); Assert.assertEquals("/stuff", request.getPath()); Assert.assertEquals("POST", request.getMethod()); Assert.assertTrue(request.containsHeader("User-Agent")); Assert.assertNull(request.getEntity()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); conn.receiveRequestEntity(request); } @Test public void testReadRequestNoEntity() throws Exception { final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\n\r\n"; final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)); Mockito.when(socket.getInputStream()).thenReturn(instream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount()); final ClassicHttpRequest request = conn.receiveRequestHeader(); Assert.assertNotNull(request); Assert.assertEquals("/stuff", request.getPath()); Assert.assertEquals("POST", request.getMethod()); Assert.assertTrue(request.containsHeader("User-Agent")); Assert.assertNull(request.getEntity()); Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount()); conn.receiveRequestEntity(request); final HttpEntity entity = request.getEntity(); Assert.assertNull(entity); } @Test public void testWriteResponseHead() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK"); response.addHeader("User-Agent", "test"); conn.sendResponseHeader(response); conn.flush(); Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount()); final String s = new String(outstream.toByteArray(), "ASCII"); Assert.assertEquals("HTTP/1.1 200 OK\r\nUser-Agent: test\r\n\r\n", s); } @Test public void testWriteResponse100Head() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(100, "Go on"); conn.sendResponseHeader(response); conn.flush(); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final String s = new String(outstream.toByteArray(), "ASCII"); Assert.assertEquals("HTTP/1.1 100 Go on\r\n\r\n", s); } @Test public void testWriteResponseEntityWithContentLength() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK"); response.addHeader("Server", "test"); response.addHeader("Content-Length", "3"); response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN)); conn.sendResponseHeader(response); conn.sendResponseEntity(response); conn.flush(); Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount()); final String s = new String(outstream.toByteArray(), "ASCII"); Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\nContent-Length: 3\r\n\r\n123", s); } @Test public void testWriteResponseEntityChunkCoded() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK"); response.addHeader("Server", "test"); response.addHeader("Transfer-Encoding", "chunked"); response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN)); conn.sendResponseHeader(response); conn.sendResponseEntity(response); conn.flush(); Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount()); final String s = new String(outstream.toByteArray(), "ASCII"); Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\nTransfer-Encoding: " + "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n", s); } @Test(expected = NotImplementedException.class) public void testWriteResponseEntityIdentity() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK"); response.addHeader("Server", "test"); response.addHeader("Transfer-Encoding", "identity"); response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN)); conn.sendResponseHeader(response); conn.sendResponseEntity(response); conn.flush(); } @Test public void testWriteResponseNoEntity() throws Exception { final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); Mockito.when(socket.getOutputStream()).thenReturn(outstream); conn.bind(socket); Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount()); final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK"); response.addHeader("Server", "test"); conn.sendResponseHeader(response); conn.sendResponseEntity(response); conn.flush(); Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount()); final String s = new String(outstream.toByteArray(), "ASCII"); Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\n\r\n", s); } }