Merge branch 'TINKERPOP-2947' into 3.6-dev
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index fd2f856..7437037 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -22,9 +22,11 @@
 
 [[release-3-6-5]]
 === TinkerPop 3.6.5 (Release Date: NOT OFFICIALLY RELEASED YET)
+
 This release also includes changes from <<release-3-5-7, 3.5.7>>.
 
-
+* Added `text/plain` MIME type to the HTTP endpoint to return a Gremlin Console-like representation of the data.
+* Added GraphBinary serialization option to the HTTP endpoint.
 
 [[release-3-6-4]]
 === TinkerPop 3.6.4 (Release Date: May 12, 2023)
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index 8db0b6b..2ee5c21 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -901,6 +901,21 @@
 types are preserved or to pass complex objects such as lists or maps, use `POST` which will at least support the
 allowed JSON data types.
 
+Passing the `Accept` header with a valid MIME type will trigger the server to return the result in a particular format.
+Note that in addition to the formats available given the server's `serializers` configuration, there is also a basic
+`text/plain` format which produces a text representation of results similar to the Gremlin Console:
+
+[source,text]
+----
+$ curl -H "Accept:text/plain" -X POST -d "{\"gremlin\":\"g.V()\"}" "http://localhost:8182"
+==>v[1]
+==>v[2]
+==>v[3]
+==>v[4]
+==>v[5]
+==>v[6]
+----
+
 Finally, as Gremlin Server can host multiple `ScriptEngine` instances (e.g. `gremlin-groovy`, `nashorn`), it is
 possible to define the language to utilize to process the request:
 
diff --git a/docs/src/upgrade/release-3.6.x.asciidoc b/docs/src/upgrade/release-3.6.x.asciidoc
index e416aa2..d54ad7a 100644
--- a/docs/src/upgrade/release-3.6.x.asciidoc
+++ b/docs/src/upgrade/release-3.6.x.asciidoc
@@ -29,7 +29,24 @@
 
 === Upgrading for Users
 
+==== HTTP Plain Text
 
+A `text/plain` MIME type has been added to the HTTP endpoint to return Gremlin Console formatted results in plain text.
+This format can be helpful for a variety of reasons. Reading JSON formatted results can be difficult sometimes and
+`text/plain` is a more simple, readable representation for when that is helpful.
+
+[source,text]
+----
+$ curl -H "Accept:text/plain" -X POST -d "{\"gremlin\":\"g.V()\"}" "http://localhost:8182"
+==>v[1]
+==>v[2]
+==>v[3]
+==>v[4]
+==>v[5]
+==>v[6]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2947[TINKERPOP-2947]
 
 == TinkerPop 3.6.4
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
index 92dedab..8bb8173 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketGremlinRequestEncoder.java
@@ -54,7 +54,7 @@
                 objects.add(new BinaryWebSocketFrame(encodedMessage));
             } else {
                 final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
-                objects.add(new TextWebSocketFrame(textSerializer.serializeRequestAsString(requestMessage)));
+                objects.add(new TextWebSocketFrame(textSerializer.serializeRequestAsString(requestMessage, channelHandlerContext.alloc())));
             }
         } catch (Exception ex) {
             throw new ResponseException(ResponseStatusCode.REQUEST_ERROR_SERIALIZATION, String.format(
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
index 2eea896..1c7a69a 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphBinaryMessageSerializerV1.java
@@ -20,6 +20,7 @@
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.Unpooled;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryIo;
@@ -36,6 +37,7 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
+import java.util.Base64;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -43,7 +45,7 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-public class GraphBinaryMessageSerializerV1 extends AbstractMessageSerializer<GraphBinaryMapper> {
+public class GraphBinaryMessageSerializerV1 extends AbstractMessageSerializer<GraphBinaryMapper> implements MessageTextSerializer<GraphBinaryMapper> {
 
     public static final String TOKEN_CUSTOM = "custom";
     public static final String TOKEN_BUILDER = "builder";
@@ -52,6 +54,9 @@
     private static final String MIME_TYPE = SerTokens.MIME_GRAPHBINARY_V1D0;
     private static final String MIME_TYPE_STRINGD = SerTokens.MIME_GRAPHBINARY_V1D0 + "-stringd";
 
+    private static final Base64.Encoder base64Encoder = Base64.getEncoder();
+    private static final Base64.Decoder base64Decoder = Base64.getDecoder();
+
     private byte[] header = MIME_TYPE.getBytes(UTF_8);
     private boolean serializeToString = false;
     private GraphBinaryReader reader;
@@ -185,6 +190,41 @@
         return new String[]{serializeToString ? MIME_TYPE_STRINGD : MIME_TYPE};
     }
 
+    @Override
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+        final ByteBuf bb = serializeResponseAsBinary(responseMessage, allocator);
+        return base64Encoder.encodeToString(convertToBytes(bb));
+    }
+
+    @Override
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+        final ByteBuf bb = serializeRequestAsBinary(requestMessage, allocator);
+        return base64Encoder.encodeToString(convertToBytes(bb));
+    }
+
+    @Override
+    public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+        return deserializeRequest(convertToByteBuf(msg));
+    }
+
+    @Override
+    public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+        return deserializeResponse(convertToByteBuf(msg));
+    }
+
+    private byte[] convertToBytes(final ByteBuf bb) {
+        byte[] bytes = new byte[bb.readableBytes()];
+        bb.getBytes(bb.readerIndex(), bytes);
+        return bytes;
+    }
+
+    private ByteBuf convertToByteBuf(final String msg) {
+        final byte[] b = base64Decoder.decode(msg);
+        final ByteBuf bb = Unpooled.buffer(b.length);
+        bb.writeBytes(b);
+        return bb;
+    }
+
     private void addCustomClasses(final Map<String, Object> config, final TypeSerializerRegistry.Builder builder) {
         final List<String> classNameList = getListStringFromConfig(TOKEN_CUSTOM, config);
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
index d3a15f5..60a2486 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
+import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
@@ -95,7 +96,7 @@
     }
 
     @Override
-    public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException {
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(responseMessage);
         } catch (Exception ex) {
@@ -115,7 +116,7 @@
     }
 
     @Override
-    public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException {
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(requestMessage);
         } catch (Exception ex) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
index 6717a00..3442205 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
+import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
@@ -110,7 +111,7 @@
     }
 
     @Override
-    public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException {
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(responseMessage);
         } catch (Exception ex) {
@@ -130,7 +131,7 @@
     }
 
     @Override
-    public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException {
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(requestMessage);
         } catch (Exception ex) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
index da3eea7..5aebf77 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV3d0.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
+import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
@@ -106,7 +107,7 @@
     }
 
     @Override
-    public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException {
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(responseMessage);
         } catch (Exception ex) {
@@ -126,7 +127,7 @@
     }
 
     @Override
-    public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException {
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
         try {
             return mapper.writeValueAsString(requestMessage);
         } catch (Exception ex) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
index 289d56d..6ef0885 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/MessageTextSerializer.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
+import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -31,9 +32,9 @@
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public interface MessageTextSerializer<M> extends MessageSerializer<M> {
-    public String serializeResponseAsString(final ResponseMessage responseMessage) throws SerializationException;
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException;
 
-    public String serializeRequestAsString(final RequestMessage requestMessage) throws SerializationException;
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException;
 
     public RequestMessage deserializeRequest(final String msg) throws SerializationException;
 
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/TestWSGremlinInitializer.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/TestWSGremlinInitializer.java
index b9e9b52..eda187c 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/TestWSGremlinInitializer.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/TestWSGremlinInitializer.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
+import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.UnpooledByteBufAllocator;
 import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
 import org.slf4j.Logger;
@@ -82,6 +84,7 @@
      * Gremlin serializer used for serializing/deserializing the request/response. This should be same as client.
      */
     private static final GraphSONMessageSerializerV2d0 SERIALIZER = new GraphSONMessageSerializerV2d0();
+    private final static ByteBufAllocator allocator = UnpooledByteBufAllocator.DEFAULT;
 
     @Override
     public void postInit(ChannelPipeline pipeline) {
@@ -128,7 +131,7 @@
                 final ResponseMessage responseMessage = ResponseMessage.build(msg)
                         .code(ResponseStatusCode.SERVER_ERROR)
                         .statusAttributeException(new RuntimeException()).create();
-                ctx.channel().writeAndFlush(new TextWebSocketFrame(SERIALIZER.serializeResponseAsString(responseMessage)));
+                ctx.channel().writeAndFlush(new TextWebSocketFrame(SERIALIZER.serializeResponseAsString(responseMessage, allocator)));
             } else if (msg.getRequestId().equals(CLOSE_CONNECTION_REQUEST_ID)) {
                 Thread.sleep(1000);
                 ctx.channel().writeAndFlush(new CloseWebSocketFrame());
@@ -152,7 +155,7 @@
             final GraphTraversalSource g = graph.traversal();
             final Vertex t = g.V().limit(1).next();
 
-            return SERIALIZER.serializeResponseAsString(ResponseMessage.build(requestID).result(t).create());
+            return SERIALIZER.serializeResponseAsString(ResponseMessage.build(requestID).result(t).create(), allocator);
         }
 
         /**
@@ -160,7 +163,7 @@
          * @throws SerializationException
          */
         private String returnSimpleStringResponse(final UUID requestID, String message) throws SerializationException {
-            return SERIALIZER.serializeResponseAsString(ResponseMessage.build(requestID).result(message).create());
+            return SERIALIZER.serializeResponseAsString(ResponseMessage.build(requestID).result(message).create(), allocator);
         }
 
         /**
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
index 4c4b7a2..001ce7e 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0Test.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
+import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
@@ -74,6 +75,7 @@
     private static final RequestMessage msg = RequestMessage.build("op")
             .overrideRequestId(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595")).create();
     private static final ObjectMapper mapper = new ObjectMapper();
+    private static final ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
 
     @Test
     public void shouldConfigureIoRegistry() throws Exception {
@@ -86,7 +88,7 @@
 
         final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
                 .result(Color.RED).create();
-        final String results = serializer.serializeResponseAsString(toSerialize);
+        final String results = serializer.serializeResponseAsString(toSerialize, allocator);
         final JsonNode json = mapper.readTree(results);
         assertNotNull(json);
         assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
@@ -95,7 +97,7 @@
     @Test
     public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
         final ResponseMessage message = ResponseMessage.build(msg).create();
-        final String results = SERIALIZER.serializeResponseAsString(message);
+        final String results = SERIALIZER.serializeResponseAsString(message, allocator);
         final JsonNode json = mapper.readTree(results);
         assertNotNull(json);
         assertEquals(msg.getRequestId().toString(), json.path(SerTokens.TOKEN_REQUEST).asText());
@@ -108,7 +110,7 @@
         funList.add(new FunObject("x"));
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -127,7 +129,7 @@
         funList.add(new FunObject("x"));
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -148,7 +150,7 @@
         funList.add(null);
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -172,7 +174,7 @@
         map.put("y", "some");
         map.put("z", innerMap);
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -199,7 +201,7 @@
         map.put(v1, 100);
         map.put(d, "test");
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -226,7 +228,7 @@
         e.property("abc", 123);
 
         final Iterable<Edge> iterable = IteratorUtils.list(g.edges());
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
@@ -260,7 +262,7 @@
         e.property("abc", 123);
 
         final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
@@ -293,7 +295,7 @@
         v.property(VertexProperty.Cardinality.single, "friends", friends);
 
         final Iterable iterable = IteratorUtils.list(g.vertices());
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -334,7 +336,7 @@
         final Map<Vertex, Integer> map = new HashMap<>();
         map.put(g.V().has("name", "marko").next(), 1000);
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -393,7 +395,7 @@
                 .statusMessage("worked")
                 .create();
 
-        final String results = SERIALIZER.serializeResponseAsString(response);
+        final String results = SERIALIZER.serializeResponseAsString(response, allocator);
         final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
 
         assertEquals(id, deserialized.getRequestId());
@@ -423,7 +425,7 @@
                 .statusMessage(null)
                 .create();
 
-        final String results = SERIALIZER.serializeResponseAsString(response);
+        final String results = SERIALIZER.serializeResponseAsString(response, allocator);
         final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
         Assert.assertNotNull(SERIALIZER.getClass().getSimpleName() + " should be able to deserialize ResponseMessage "
                         + "with null message field", deserialized);
@@ -436,7 +438,7 @@
         final Tree t = g.V(1).out().properties("name").tree().next();
 
         
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
index a497400..3d01af4 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
@@ -104,7 +104,7 @@
 
         final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
                 .result(Color.RED).create();
-        final String results = serializer.serializeResponseAsString(toSerialize);
+        final String results = serializer.serializeResponseAsString(toSerialize, allocator);
         final JsonNode json = mapper.readTree(results);
         assertNotNull(json);
         assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
@@ -113,7 +113,7 @@
     @Test
     public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
         final ResponseMessage message = ResponseMessage.build(msg).create();
-        final String results = SERIALIZER.serializeResponseAsString(message);
+        final String results = SERIALIZER.serializeResponseAsString(message, allocator);
         final JsonNode json = mapper.readTree(results);
         assertNotNull(json);
         assertEquals(msg.getRequestId().toString(), json.path(SerTokens.TOKEN_REQUEST).asText());
@@ -126,7 +126,7 @@
         funList.add(new FunObject("x"));
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -145,7 +145,7 @@
         funList.add(new FunObject("x"));
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -166,7 +166,7 @@
         funList.add(null);
         funList.add(new FunObject("y"));
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -190,7 +190,7 @@
         map.put("y", "some");
         map.put("z", innerMap);
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -217,7 +217,7 @@
         map.put(v1, 100);
         map.put(d, "test");
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -244,7 +244,7 @@
         e.property("abc", 123);
 
         final Iterable<Edge> iterable = IteratorUtils.list(g.edges());
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
@@ -277,7 +277,7 @@
         e.property("abc", 123);
 
         final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
@@ -310,7 +310,7 @@
         v.property(VertexProperty.Cardinality.single, "friends", friends);
 
         final Iterable iterable = IteratorUtils.list(g.vertices());
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -351,7 +351,7 @@
         final Map<Vertex, Integer> map = new HashMap<>();
         map.put(g.V().has("name", "marko").next(), 1000);
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
         final JsonNode json = mapper.readTree(results);
 
         assertNotNull(json);
@@ -410,7 +410,7 @@
                 .statusMessage("worked")
                 .create();
 
-        final String results = SERIALIZER.serializeResponseAsString(response);
+        final String results = SERIALIZER.serializeResponseAsString(response, allocator);
         final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
 
         assertEquals(id, deserialized.getRequestId());
@@ -429,7 +429,7 @@
         final GraphTraversalSource g = graph.traversal();
         final Tree t = g.V(1).out().properties("name").tree().next();
 
-        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create(), allocator);
 
         final JsonNode json = mapper.readTree(results);
 
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
index d77de48..6cd37b8 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryMessageSerializerV1Test.java
@@ -175,6 +175,43 @@
         assertEquals(java.awt.Color.RED.toString(), deserialized.getResult().getData());
     }
 
+    @Test
+    public void shouldToStringSerializeAsText() throws SerializationException {
+        final GraphBinaryMessageSerializerV1 serializer = new GraphBinaryMessageSerializerV1();
+        final Map<String,Object> conf = new HashMap<String,Object>() {{
+            put(GraphBinaryMessageSerializerV1.TOKEN_SERIALIZE_RESULT_TO_STRING, true);
+        }};
+        serializer.configure(conf, Collections.emptyMap());
+
+        final ResponseMessage messageWithUnexpectedType = ResponseMessage.build(UUID.randomUUID()).
+                result(java.awt.Color.RED).create();
+        final String base64 = serializer.serializeResponseAsString(messageWithUnexpectedType, allocator);
+        final ResponseMessage deserialized = serializer.deserializeResponse(base64);
+
+        assertEquals(java.awt.Color.RED.toString(), deserialized.getResult().getData());
+    }
+
+    @Test
+    public void shouldSerializeAndDeserializeRequestAsText() throws SerializationException {
+        final GraphBinaryMessageSerializerV1 serializer = new GraphBinaryMessageSerializerV1();
+        final Map<String,Object> conf = new HashMap<String,Object>() {{
+            put(GraphBinaryMessageSerializerV1.TOKEN_SERIALIZE_RESULT_TO_STRING, true);
+        }};
+        serializer.configure(conf, Collections.emptyMap());
+
+        final RequestMessage request = RequestMessage.build("op1")
+                .processor("proc1")
+                .overrideRequestId(UUID.randomUUID())
+                .addArg("arg1", "value1")
+                .create();
+
+        final ByteBuf buffer = serializer.serializeRequestAsBinary(request, allocator);
+        final int mimeLen = buffer.readByte();
+        buffer.readBytes(new byte[mimeLen]);
+        final RequestMessage deserialized = serializer.deserializeRequest(buffer);
+        assertThat(request, reflectionEquals(deserialized));
+    }
+
     private static void assertResponseEquals(ResponseMessage expected, ResponseMessage actual) {
         assertEquals(expected.getRequestId(), actual.getRequestId());
         // Status
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
index d891e50..4b137f3 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/AbstractSession.java
@@ -751,7 +751,7 @@
                         .code(code)
                         .statusAttributes(statusAttributes)
                         .responseMetaData(responseMetaData)
-                        .result(aggregate).create()));
+                        .result(aggregate).create(), nettyContext.alloc()));
             }
         } catch (Exception ex) {
             logger.warn("The result [{}] in the request {} could not be serialized and returned.", aggregate, msg.getRequestId(), ex);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
index 6020b36..54fe16b 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GremlinResponseFrameEncoder.java
@@ -84,9 +84,9 @@
                 // if the request came in on a session then the serialization must occur that same thread except
                 // in the case of errors for reasons described above.
                 if (null == session || !o.getStatus().getCode().isSuccess())
-                    serialized = new Frame(textSerializer.serializeResponseAsString(o));
+                    serialized = new Frame(textSerializer.serializeResponseAsString(o, ctx.alloc()));
                 else
-                    serialized = new Frame(session.getExecutor().submit(() -> textSerializer.serializeResponseAsString(o)).get());
+                    serialized = new Frame(session.getExecutor().submit(() -> textSerializer.serializeResponseAsString(o, ctx.alloc())).get());
 
                 objects.add(serialized);
             }
@@ -102,7 +102,7 @@
                 objects.add(serializer.serializeResponseAsBinary(error, ctx.alloc()));
             } else {
                 final MessageTextSerializer<?> textSerializer = (MessageTextSerializer<?>) serializer;
-                objects.add(textSerializer.serializeResponseAsString(error));
+                objects.add(textSerializer.serializeResponseAsString(error, ctx.alloc()));
             }
         }
     }
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
index 634d88f..6995b21 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
@@ -19,7 +19,10 @@
 package org.apache.tinkerpop.gremlin.server.handler;
 
 import com.codahale.metrics.Timer;
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
+import org.apache.tinkerpop.gremlin.server.util.TextPlainMessageSerializer;
 import org.javatuples.Pair;
 import org.javatuples.Quartet;
 import org.slf4j.Logger;
@@ -60,10 +63,12 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -99,6 +104,11 @@
      */
     private final Map<String, MessageSerializer<?>> serializers;
 
+    /**
+     * Serializer for {@code text/plain} which is a serializer exclusive to HTTP.
+     */
+    private static final TextPlainMessageSerializer textPlainSerializer = new TextPlainMessageSerializer();
+
     private final GremlinExecutor gremlinExecutor;
     private final GraphManager graphManager;
     private final Settings settings;
@@ -223,7 +233,7 @@
                             attemptCommit(requestArguments.getValue3(), graphManager, settings.strictTransactionManagement);
 
                             try {
-                                return Unpooled.wrappedBuffer(serializer.getValue1().serializeResponseAsString(responseMessage).getBytes(UTF8));
+                                return Unpooled.wrappedBuffer(serializer.getValue1().serializeResponseAsString(responseMessage, ctx.alloc()).getBytes(UTF8));
                             } catch (Exception ex) {
                                 logger.warn(String.format("Error during serialization for %s", responseMessage), ex);
 
@@ -331,6 +341,9 @@
             final String accept = p.getValue0().equals("*/*") ? "application/json" : p.getValue0();
             if (serializers.containsKey(accept))
                 return Pair.with(accept, (MessageTextSerializer<?>) serializers.get(accept));
+            else if (accept.equals("text/plain")) {
+                return Pair.with(accept, textPlainSerializer);
+            }
         }
 
         return null;
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
index 383d074..a0c3a37 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractOpProcessor.java
@@ -297,7 +297,7 @@
                         .code(code)
                         .statusAttributes(statusAttributes)
                         .responseMetaData(responseMetaData)
-                        .result(aggregate).create()));
+                        .result(aggregate).create(), nettyContext.alloc()));
             }
         } catch (Exception ex) {
             logger.warn("The result [{}] in the request {} could not be serialized and returned.", aggregate, msg.getRequestId(), ex);
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializer.java
new file mode 100644
index 0000000..81b3662
--- /dev/null
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializer.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.server.util;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
+import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * A highly use-case specific serializer that only has context for HTTP where results simply need to be converted
+ * to string in a line by line fashion for text based returns.
+ */
+public class TextPlainMessageSerializer implements MessageTextSerializer<Function<Object, String>> {
+
+    @Override
+    public Function<Object, String> getMapper() {
+        return Objects::toString;
+    }
+
+    @Override
+    public ByteBuf serializeResponseAsBinary(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not produce binary");
+    }
+
+    @Override
+    public ByteBuf serializeRequestAsBinary(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not produce binary");
+    }
+
+    @Override
+    public RequestMessage deserializeRequest(final ByteBuf msg) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not have deserialization functions");
+    }
+
+    @Override
+    public ResponseMessage deserializeResponse(final ByteBuf msg) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not have deserialization functions");
+    }
+
+    @Override
+    public String[] mimeTypesSupported() {
+        return new String[] { "text/plain" };
+    }
+
+    @Override
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+        final StringBuilder sb = new StringBuilder();
+
+        // this should only serialize success conditions so all should have data in List form
+        final List<Object> data = (List<Object>) responseMessage.getResult().getData();
+        for (int ix = 0; ix < data.size(); ix ++) {
+            sb.append("==>");
+            sb.append(data.get(ix));
+            if (ix < data.size() - 1)
+                sb.append(System.lineSeparator());
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not have any need to serialize requests");
+    }
+
+    @Override
+    public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not have deserialization functions");
+    }
+
+    @Override
+    public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+        throw new UnsupportedOperationException("text/plain does not have deserialization functions");
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
index 7a33bb0..4f44158 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
@@ -20,6 +20,8 @@
 
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.http.HttpHeaders;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0;
@@ -36,15 +38,17 @@
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 import org.apache.tinkerpop.gremlin.server.handler.SaslAndHttpBasicAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.junit.Test;
 
-import java.io.File;
 import java.time.Instant;
 import java.util.Base64;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
@@ -54,7 +58,9 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.hamcrest.core.StringContains.containsString;
+import static org.hamcrest.core.StringRegularExpression.matchesRegex;
 import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.junit.Assert.assertEquals;
 
@@ -366,6 +372,68 @@
     }
 
     @Test
+    public void should200OnGETWithGremlinQueryStringArgumentWithIteratorResultGraphBinary() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=gclassic.V()"));
+        final String mime = SerTokens.MIME_GRAPHBINARY_V1D0;
+        httpget.addHeader("Accept", mime);
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals(mime, response.getEntity().getContentType().getValue());
+            final String base64 = EntityUtils.toString(response.getEntity());
+            final GraphBinaryMessageSerializerV1 serializer = new GraphBinaryMessageSerializerV1(TypeSerializerRegistry.INSTANCE);
+            final ResponseMessage msg = serializer.deserializeResponse(base64);
+            final List<Object> data = (List<Object>) msg.getResult().getData();
+            assertEquals(6, data.size());
+            for (Object o : data) {
+                assertThat(o, instanceOf(Vertex.class));
+            }
+        }
+    }
+
+    @Test
+    public void should200OnGETWithGremlinQueryStringArgumentWithIteratorResultGraphBinaryToString() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=gclassic.V()"));
+        final String mime = SerTokens.MIME_GRAPHBINARY_V1D0 + "-stringd";
+        httpget.addHeader("Accept", mime);
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals(mime, response.getEntity().getContentType().getValue());
+            final String base64 = EntityUtils.toString(response.getEntity());
+            final GraphBinaryMessageSerializerV1 serializer = new GraphBinaryMessageSerializerV1(TypeSerializerRegistry.INSTANCE);
+            final ResponseMessage msg = serializer.deserializeResponse(base64);
+            final List<Object> data = (List<Object>) msg.getResult().getData();
+            assertEquals(6, data.size());
+            for (Object o : data) {
+                assertThat(o, instanceOf(String.class));
+                assertThat((String) o, matchesRegex("v\\[\\d\\]"));
+            }
+        }
+    }
+
+    @Test
+    public void should200OnGETWithGremlinQueryStringArgumentWithIteratorResultTextPlain() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=gclassic.V()"));
+        final String mime = "text/plain";
+        httpget.addHeader("Accept", mime);
+
+        try (final CloseableHttpResponse response = httpclient.execute(httpget)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals(mime, response.getEntity().getContentType().getValue());
+            final String text = EntityUtils.toString(response.getEntity());
+            final String[] split = text.split(System.lineSeparator());
+            assertEquals(6, split.length);
+            for (String line : split) {
+                assertThat(line, matchesRegex("==>v\\[\\d\\]"));
+            }
+        }
+    }
+
+    @Test
     public void should200OnGETWithGremlinQueryStringArgument() throws Exception {
         final CloseableHttpClient httpclient = HttpClients.createDefault();
         final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=2-1"));
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializerTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializerTest.java
new file mode 100644
index 0000000..803d149
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/TextPlainMessageSerializerTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.server.util;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+
+public class TextPlainMessageSerializerTest {
+
+    @Test
+    public void shouldProducePlainText() throws Exception {
+        final Map<String, Object> m = new HashMap<>();
+        final ResponseMessage msg = ResponseMessage.build(UUID.randomUUID()).
+                result(Arrays.asList(1, new DetachedVertex(100, "person", m), java.awt.Color.RED)).create();
+
+        final TextPlainMessageSerializer messageSerializer = new TextPlainMessageSerializer();
+        final String output = messageSerializer.serializeResponseAsString(msg, ByteBufAllocator.DEFAULT);
+        final String exp = "==>1" + System.lineSeparator() +
+                           "==>v[100]" + System.lineSeparator() +
+                           "==>java.awt.Color[r=255,g=0,b=0]";
+        assertEquals(exp, output);
+    }
+}