1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-24 04:02:07 +03:00

Permit status lines like 'ICY 200 OK'

This commit is contained in:
jwilson
2014-01-19 11:25:02 -05:00
parent 35b30f943f
commit 9c15cba43d
3 changed files with 120 additions and 12 deletions

View File

@@ -18,26 +18,48 @@ public final class StatusLine {
// H T T P / 1 . 1 2 0 0 T e m p o r a r y R e d i r e c t
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
// We allow empty message without leading white space since some servers
// do not send the white space when the message is empty.
boolean hasMessage = statusLine.length() > 13;
if (!statusLine.startsWith("HTTP/1.")
|| statusLine.length() < 12
|| statusLine.charAt(8) != ' '
|| (hasMessage && statusLine.charAt(12) != ' ')) {
// Parse protocol like "HTTP/1.1" followed by a space.
int codeStart;
int httpMinorVersion;
if (statusLine.startsWith("HTTP/1.")) {
if (statusLine.length() < 9 || statusLine.charAt(8) != ' ') {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
httpMinorVersion = statusLine.charAt(7) - '0';
codeStart = 9;
if (httpMinorVersion < 0 || httpMinorVersion > 9) {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
} else if (statusLine.startsWith("ICY ")) {
// Shoutcast uses ICY instead of "HTTP/1.0".
httpMinorVersion = 0;
codeStart = 4;
} else {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
int httpMinorVersion = statusLine.charAt(7) - '0';
if (httpMinorVersion < 0 || httpMinorVersion > 9) {
// Parse response code like "200". Always 3 digits.
if (statusLine.length() < codeStart + 3) {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
int responseCode;
try {
responseCode = Integer.parseInt(statusLine.substring(9, 12));
responseCode = Integer.parseInt(statusLine.substring(codeStart, codeStart + 3));
} catch (NumberFormatException e) {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
this.responseMessage = hasMessage ? statusLine.substring(13) : "";
// Parse an optional response message like "OK" or "Not Modified". If it
// exists, it is separated from the response code by a space.
String responseMessage = "";
if (statusLine.length() > codeStart + 3) {
if (statusLine.charAt(codeStart + 3) != ' ') {
throw new ProtocolException("Unexpected status line: " + statusLine);
}
responseMessage = statusLine.substring(codeStart + 4);
}
this.responseMessage = responseMessage;
this.responseCode = responseCode;
this.statusLine = statusLine;
this.httpMinorVersion = httpMinorVersion;
@@ -64,5 +86,4 @@ public final class StatusLine {
public String message() {
return responseMessage;
}
}

View File

@@ -16,8 +16,10 @@
package com.squareup.okhttp.internal.http;
import java.io.IOException;
import java.net.ProtocolException;
import org.junit.Test;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertEquals;
public final class StatusLineTest {
@@ -53,4 +55,63 @@ public final class StatusLineTest {
assertEquals(version, statusLine.httpMinorVersion());
assertEquals(code, statusLine.code());
}
// https://github.com/square/okhttp/issues/386
@Test public void shoutcast() throws IOException {
StatusLine statusLine = new StatusLine("ICY 200 OK");
assertEquals("OK", statusLine.message());
assertEquals(0, statusLine.httpMinorVersion());
assertEquals(200, statusLine.code());
}
@Test public void missingProtocol() throws IOException {
assertInvalid("");
assertInvalid(" ");
assertInvalid("200 OK");
assertInvalid(" 200 OK");
}
@Test public void protocolVersions() throws IOException {
assertInvalid("HTTP/2.0 200 OK");
assertInvalid("HTTP/2.1 200 OK");
assertInvalid("HTTP/-.1 200 OK");
assertInvalid("HTTP/1.- 200 OK");
assertInvalid("HTTP/0.1 200 OK");
assertInvalid("HTTP/101 200 OK");
assertInvalid("HTTP/1.1_200 OK");
}
@Test public void nonThreeDigitCode() throws IOException {
assertInvalid("HTTP/1.1 OK");
assertInvalid("HTTP/1.1 2 OK");
assertInvalid("HTTP/1.1 20 OK");
assertInvalid("HTTP/1.1 2000 OK");
assertInvalid("HTTP/1.1 two OK");
assertInvalid("HTTP/1.1 2");
assertInvalid("HTTP/1.1 2000");
assertInvalid("HTTP/1.1 two");
}
@Test public void truncated() throws IOException {
assertInvalid("");
assertInvalid("H");
assertInvalid("HTTP/1");
assertInvalid("HTTP/1.");
assertInvalid("HTTP/1.1");
assertInvalid("HTTP/1.1 ");
assertInvalid("HTTP/1.1 2");
assertInvalid("HTTP/1.1 20");
}
@Test public void wrongMessageDelimiter() throws IOException {
assertInvalid("HTTP/1.1 200_");
}
private void assertInvalid(String statusLine) throws IOException {
try {
new StatusLine(statusLine);
fail();
} catch (ProtocolException expected) {
}
}
}

View File

@@ -1324,6 +1324,32 @@ public final class URLConnectionTest {
}
}
@Test public void shoutcast() throws Exception {
server.enqueue(new MockResponse().setStatus("ICY 200 OK")
// .addHeader("HTTP/1.0 200 OK")
.addHeader("Accept-Ranges: none")
.addHeader("Content-Type: audio/mpeg")
.addHeader("icy-br:128")
.addHeader("ice-audio-info: bitrate=128;samplerate=44100;channels=2")
.addHeader("icy-br:128")
.addHeader("icy-description:Rock")
.addHeader("icy-genre:riders")
.addHeader("icy-name:A2RRock")
.addHeader("icy-pub:1")
.addHeader("icy-url:http://www.A2Rradio.com")
.addHeader("Server: Icecast 2.3.3-kh8")
.addHeader("Cache-Control: no-cache")
.addHeader("Pragma: no-cache")
.addHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT")
.addHeader("icy-metaint:16000")
.setBody("mp3 data"));
server.play();
HttpURLConnection connection = client.open(server.getUrl("/"));
assertEquals(200, connection.getResponseCode());
assertEquals("OK", connection.getResponseMessage());
assertContent("mp3 data", connection);
}
@Test public void cannotSetNegativeFixedLengthStreamingMode() throws Exception {
server.play();
HttpURLConnection connection = client.open(server.getUrl("/"));