diff --git a/okhttp-sse/pom.xml b/okhttp-sse/pom.xml index fac7188b2..fda1f3b11 100644 --- a/okhttp-sse/pom.xml +++ b/okhttp-sse/pom.xml @@ -55,6 +55,18 @@ + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + okhttp3.sse + + + + diff --git a/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java b/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java index f200eaa87..e379bf074 100644 --- a/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java +++ b/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.java @@ -20,12 +20,13 @@ import javax.annotation.Nullable; import okhttp3.Call; import okhttp3.Callback; import okhttp3.EventListener; -import okhttp3.EventSource; -import okhttp3.EventSourceListener; +import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.internal.Util; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSourceListener; import okio.BufferedSource; public final class RealEventSource @@ -50,24 +51,43 @@ public final class RealEventSource } @Override public void onResponse(Call call, Response response) { - //noinspection ConstantConditions main body is never null - BufferedSource source = response.body().source(); - ServerSentEventReader reader = new ServerSentEventReader(source, this); - - response = response.newBuilder() - .body(Util.EMPTY_RESPONSE) - .build(); - try { - listener.onOpen(this, response); - while (reader.processNextEvent()) { - } - } catch (Exception e) { - listener.onFailure(this, e, response); - return; - } + //noinspection ConstantConditions main body is never null + BufferedSource source = response.body().source(); + ServerSentEventReader reader = new ServerSentEventReader(source, this); - listener.onClosed(this); + if (!response.isSuccessful()) { + listener.onFailure(this, null, response); + return; + } + + MediaType contentType = response.body().contentType(); + if (!isEventStream(contentType)) { + listener.onFailure(this, + new IllegalStateException("Invalid content-type: " + contentType), response); + return; + } + + response = response.newBuilder().body(Util.EMPTY_RESPONSE).build(); + + try { + listener.onOpen(this, response); + while (reader.processNextEvent()) { + } + } catch (Exception e) { + listener.onFailure(this, e, response); + return; + } + + listener.onClosed(this); + } finally { + response.close(); + } + } + + private static boolean isEventStream(@Nullable MediaType contentType) { + return contentType != null && contentType.type().equals("text") && contentType.subtype() + .equals("event-stream"); } @Override public void onFailure(Call call, IOException e) { diff --git a/okhttp-sse/src/main/java/okhttp3/internal/sse/package-info.java b/okhttp-sse/src/main/java/okhttp3/internal/sse/package-info.java new file mode 100644 index 000000000..5993b09cd --- /dev/null +++ b/okhttp-sse/src/main/java/okhttp3/internal/sse/package-info.java @@ -0,0 +1,3 @@ +/** Private support classes for server-sent events. */ +@javax.annotation.ParametersAreNonnullByDefault +package okhttp3.internal.sse; diff --git a/okhttp-sse/src/main/java/okhttp3/EventSource.java b/okhttp-sse/src/main/java/okhttp3/sse/EventSource.java similarity index 96% rename from okhttp-sse/src/main/java/okhttp3/EventSource.java rename to okhttp-sse/src/main/java/okhttp3/sse/EventSource.java index 84533d3ad..fe703dc8c 100644 --- a/okhttp-sse/src/main/java/okhttp3/EventSource.java +++ b/okhttp-sse/src/main/java/okhttp3/sse/EventSource.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3; +package okhttp3.sse; + +import okhttp3.Request; public interface EventSource { /** Returns the original request that initiated this event source. */ diff --git a/okhttp-sse/src/main/java/okhttp3/EventSourceListener.java b/okhttp-sse/src/main/java/okhttp3/sse/EventSourceListener.java similarity index 89% rename from okhttp-sse/src/main/java/okhttp3/EventSourceListener.java rename to okhttp-sse/src/main/java/okhttp3/sse/EventSourceListener.java index 65defd52a..4246625ec 100644 --- a/okhttp-sse/src/main/java/okhttp3/EventSourceListener.java +++ b/okhttp-sse/src/main/java/okhttp3/sse/EventSourceListener.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3; +package okhttp3.sse; import javax.annotation.Nullable; +import okhttp3.Response; public abstract class EventSourceListener { /** @@ -43,6 +44,7 @@ public abstract class EventSourceListener { * Invoked when an event source has been closed due to an error reading from or writing to the * network. Incoming events may have been lost. No further calls to this listener will be made. */ - public void onFailure(EventSource eventSource, Throwable t, @Nullable Response response) { + public void onFailure(EventSource eventSource, @Nullable Throwable t, + @Nullable Response response) { } } diff --git a/okhttp-sse/src/main/java/okhttp3/EventSources.java b/okhttp-sse/src/main/java/okhttp3/sse/EventSources.java similarity index 93% rename from okhttp-sse/src/main/java/okhttp3/EventSources.java rename to okhttp-sse/src/main/java/okhttp3/sse/EventSources.java index 923ecab14..04a5f1501 100644 --- a/okhttp-sse/src/main/java/okhttp3/EventSources.java +++ b/okhttp-sse/src/main/java/okhttp3/sse/EventSources.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3; +package okhttp3.sse; +import okhttp3.OkHttpClient; +import okhttp3.Request; import okhttp3.internal.sse.RealEventSource; public final class EventSources { diff --git a/okhttp-sse/src/main/java/okhttp3/sse/package-info.java b/okhttp-sse/src/main/java/okhttp3/sse/package-info.java new file mode 100644 index 000000000..6777492c9 --- /dev/null +++ b/okhttp-sse/src/main/java/okhttp3/sse/package-info.java @@ -0,0 +1,3 @@ +/** Support for server-sent events. */ +@javax.annotation.ParametersAreNonnullByDefault +package okhttp3.sse; diff --git a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java index 162c04616..ffdabbcd1 100644 --- a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java +++ b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceHttpTest.java @@ -15,16 +15,18 @@ */ package okhttp3.internal.sse; -import okhttp3.EventSource; -import okhttp3.EventSources; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSources; import org.junit.After; import org.junit.Rule; import org.junit.Test; +import static org.junit.Assert.assertEquals; + public final class EventSourceHttpTest { @Rule public final MockWebServer server = new MockWebServer(); @@ -38,14 +40,35 @@ public final class EventSourceHttpTest { @Test public void event() { server.enqueue(new MockResponse().setBody("" + "data: hey\n" - + "\n")); + + "\n").setHeader("content-type", "text/event-stream")); EventSource source = newEventSource(); + + assertEquals("/", source.request().url().encodedPath()); + listener.assertOpen(); listener.assertEvent(null, null, "hey"); listener.assertClose(); } + @Test public void badContentType() { + server.enqueue(new MockResponse().setBody("" + + "data: hey\n" + + "\n").setHeader("content-type", "text/plain")); + + EventSource source = newEventSource(); + listener.assertFailure("Invalid content-type: text/plain"); + } + + @Test public void badResponseCode() { + server.enqueue(new MockResponse().setBody("" + + "data: hey\n" + + "\n").setHeader("content-type", "text/event-stream").setResponseCode(401)); + + EventSource source = newEventSource(); + listener.assertFailure(null); + } + private EventSource newEventSource() { Request request = new Request.Builder() .url(server.url("/")) diff --git a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceRecorder.java b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceRecorder.java index 81fa38654..2d2c8afce 100644 --- a/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceRecorder.java +++ b/okhttp-sse/src/test/java/okhttp3/internal/sse/EventSourceRecorder.java @@ -19,13 +19,14 @@ import java.io.IOException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; import javax.annotation.Nullable; -import okhttp3.EventSource; -import okhttp3.EventSourceListener; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSourceListener; import okhttp3.Response; import okhttp3.internal.platform.Platform; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public final class EventSourceRecorder extends EventSourceListener { @@ -89,6 +90,18 @@ public final class EventSourceRecorder extends EventSourceListener { } } + public void assertFailure(@Nullable String message) { + Object event = nextEvent(); + if (!(event instanceof Failure)) { + throw new AssertionError("Expected Failure but was " + event); + } + if (message != null) { + assertEquals(message, ((Failure) event).t.getMessage()); + } else { + assertNull(((Failure) event).t); + } + } + static final class Open { final EventSource eventSource; final Response response;