This is an automated email from the git hooks/post-receive script. sylvestre pushed a commit to branch master in repository jscover.
commit 039ad93258fb4b5304536ae5ce12bc6a052c3753 Author: Jake Cobb <[email protected]> Date: Thu Aug 14 15:16:16 2014 -0700 Persistent connection prevention fixed for POST requests. Additional unit tests. All tests now pass and coverage requirements are met. --- src/main/java/jscover/server/ProxyService.java | 68 ++++++++++++++-------- src/test/java/jscover/server/ProxyServiceTest.java | 62 +++++++++++++++++--- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/src/main/java/jscover/server/ProxyService.java b/src/main/java/jscover/server/ProxyService.java index a43f7a2..9cb7e83 100644 --- a/src/main/java/jscover/server/ProxyService.java +++ b/src/main/java/jscover/server/ProxyService.java @@ -352,6 +352,7 @@ import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.logging.Logger; +import java.util.regex.Pattern; import static java.lang.String.format; import static java.util.logging.Level.FINE; @@ -359,6 +360,7 @@ import static java.util.logging.Level.FINEST; import static java.util.logging.Level.SEVERE; public class ProxyService { + private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Logger logger = Logger.getLogger(ProxyService.class.getName()); private IoUtils ioUtils = IoUtils.getInstance(); @@ -402,7 +404,7 @@ public class ProxyService { socket = new Socket(url.getHost(), port == -1 ? 80 : port); remoteInputStream = socket.getInputStream(); remoteOutputStream = socket.getOutputStream(); - ioUtils.copyNoClose(setHttp10(request.getInputStream()), remoteOutputStream, request.getPostIndex() + request.getContentLength()); + sendMethodAndHeaders(request, request.getInputStream(), remoteOutputStream); ioUtils.copyNoClose(remoteInputStream, request.getOutputStream()); } catch (IOException e) { e.printStackTrace(); @@ -412,26 +414,44 @@ public class ProxyService { ioUtils.closeQuietly(socket); } } - - protected InputStream setHttp10(InputStream is) { - try { - logger.log(FINE, "Bytes available on stream {0}", is.available()); - int bufSize = Math.min(is.available(), 2046); - PushbackInputStream pbis = new PushbackInputStream(is, bufSize); - byte headerBytes[] = new byte[bufSize]; - int read = pbis.read(headerBytes); - int firstLineIndex = ioUtils.getNewLineIndex(headerBytes, Charset.defaultCharset()); - pbis.unread(headerBytes, firstLineIndex, read - firstLineIndex); - String header = new String(headerBytes, 0, firstLineIndex); - - logger.log(FINEST, "Header before {0}", header); - header = header.replaceFirst("HTTP/1.1", "HTTP/1.0"); - logger.log(FINEST, "Header after {0}", header); - pbis.unread(header.getBytes()); - return pbis; - } catch (IOException e) { - throw new RuntimeException(e); - } + + protected void sendMethodAndHeaders(HttpRequest request, InputStream is, OutputStream remoteOutputStream) throws IOException { + + // read ahead to see the method and headers + logger.log(FINE, "Bytes available on stream {0}", is.available()); + int bufSize = Math.min(is.available(), HttpServer.HEADER_SIZE); + ByteArrayOutputStream baos = new ByteArrayOutputStream(bufSize); + PushbackInputStream pbis = new PushbackInputStream(is, bufSize); + byte headerBytes[] = new byte[bufSize]; + int read = pbis.read(headerBytes); + int firstLineIndex = ioUtils.getNewLineIndex(headerBytes, UTF8); + int dataIndex = ioUtils.getDataIndex(headerBytes, UTF8); + + // back up to the start of data + pbis.unread(headerBytes, dataIndex, read - dataIndex); + + // read the header, drop the remote host part and change protocol to HTTP/1.0 + String header = new String(headerBytes, 0, firstLineIndex, UTF8); + logger.log(FINEST, "Header before {0}", header); + final URL url = request.getUrl(); + header = header.replaceFirst(Pattern.quote(url.toExternalForm()), getRawURI(url)); + header = header.replaceFirst("HTTP/1.1", "HTTP/1.0"); + logger.log(FINEST, "Header after {0}", header); + + // write method and filtered headers to intermediate buffer + PrintWriter remotePrintWriter = new PrintWriter(new OutputStreamWriter(baos, UTF8)); + remotePrintWriter.write(header); + remotePrintWriter.write("\r\n"); + sendHeaders(request, remotePrintWriter); + byte[] methodAndHeaderBytes = baos.toByteArray(); + + // push method and headers in front of response data + PushbackInputStream requestInputStream = new PushbackInputStream(pbis, methodAndHeaderBytes.length); + requestInputStream.unread(methodAndHeaderBytes); + + // now copy the whole thing + int toSend = methodAndHeaderBytes.length + request.getContentLength(); + ioUtils.copyNoClose(requestInputStream, remoteOutputStream, toSend); } String getRawURI(URL url) { @@ -441,7 +461,7 @@ public class ProxyService { } return uri; } - + private void sendHeaders(HttpRequest request, PrintWriter remotePrintWriter) { Map<String, List<String>> clientHeaders = request.getHeaders(); for (String header : clientHeaders.keySet()) { @@ -449,10 +469,10 @@ public class ProxyService { continue; List<String> values = clientHeaders.get(header); for (String value : values) { - remotePrintWriter.print(format("%s: %s\n", header, value)); + remotePrintWriter.print(format("%s: %s\r\n", header, value)); } } - remotePrintWriter.print("\n"); + remotePrintWriter.print("\r\n"); remotePrintWriter.flush(); } diff --git a/src/test/java/jscover/server/ProxyServiceTest.java b/src/test/java/jscover/server/ProxyServiceTest.java index d86a2d3..3cb2f5a 100644 --- a/src/test/java/jscover/server/ProxyServiceTest.java +++ b/src/test/java/jscover/server/ProxyServiceTest.java @@ -343,6 +343,8 @@ Public License instead of this License. package jscover.server; import jscover.util.IoUtils; + +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -350,20 +352,24 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.io.ByteArrayInputStream; -import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.HttpURLConnection; +import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.startsWith; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class ProxyServiceTest { + private static final Charset UTF8 = Charset.forName("UTF-8"); private ProxyService proxyService = new ProxyService(); private HttpRequest request = new HttpRequest("test.js", null, null, 0, null); @Mock private HttpURLConnection conn; @@ -417,11 +423,51 @@ public class ProxyServiceTest { } @Test - public void shouldConvertToHTTP10() { - String requestString = "POST /someURL HTTP/1.1\r\nHeaders"; - - InputStream is = proxyService.setHttp10(new ByteArrayInputStream(requestString.getBytes())); - - assertThat(ioUtils.toString(is), equalTo("POST /someURL HTTP/1.0\r\nHeaders")); + public void shouldConvertToHTTP10() throws Exception { + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + headers.put("Content-Length", Collections.singletonList("0")); + String url = "http://somehost/someURL"; + String requestString = "POST " + url + " HTTP/1.1\r\nContent-Length: 0\r\n\r\n"; + + String result = sendMethodAndHeaders(url, requestString, headers).toString("UTF-8"); + assertThat(result, startsWith("POST /someURL HTTP/1.0")); + } + + @Test + public void shouldChangeURLToPath() throws Exception { + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + headers.put("Content-Length", Collections.singletonList("0")); + String url = "http://somehost/someURL"; + String requestString = "POST " + url + " HTTP/1.1\r\nContent-Length: 0\r\n\r\n"; + + String result = sendMethodAndHeaders(url, requestString, headers).toString("UTF-8"); + assertThat(result, startsWith("POST /someURL")); + } + + @Test + public void shouldNotAddKeepAliveHeadersPost() throws Exception { + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + headers.put("Proxy-Connection", Collections.singletonList("keep-alive")); + headers.put("Connection", Collections.singletonList("keep-alive")); + headers.put("Content-Length", Collections.singletonList("0")); + + String url = "http://somehost/someURL"; + String requestString = "POST " + url + " HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n"; + String result = sendMethodAndHeaders(url, requestString, headers).toString("UTF-8"); + + assertThat(result, Matchers.not(Matchers.containsString("Connection"))); + assertThat(result, Matchers.not(Matchers.containsString("keep-alive"))); + } + + private ByteArrayOutputStream sendMethodAndHeaders(String path, String requestString, Map<String, List<String>> headers) throws IOException { + if (headers == null ) + headers = Collections.emptyMap(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayInputStream in = new ByteArrayInputStream(requestString.getBytes(UTF8)); + HttpRequest request = new HttpRequest(path, new ByteArrayInputStream(requestString.getBytes(UTF8)), out, 0, headers); + + proxyService.sendMethodAndHeaders(request, in, out); + return out; } } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jscover.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

