RejectedSoftware Forums

Sign up

Writing to HTTPServerResponse body in @after Handler Does NOT Stop Further Processing

According to the documentation for the @after UDA, we have the following:

http://vibed.org/api/vibe.web.rest/after

Writing to the response body from within the specified handler function causes any further processing of the request to be skipped, including any other @after annotations and writing the result value.

I intend to use this feature in order to write more customizable data conversions than just JSON as per the registerRestInterface. Instead, I am registering my service via resisterWebInterface and using logic in @after handlers to run conversion functions to convert between D types and Media Types.

However, after writing to the response in my @after handler using HTTPServerResponse.writeBody(), I am finding that the code in web.d still continues to attempt to write to the body in vibe.web.web.handleRequest after running all @after handlers with evaluateOutputModifiers().

		} else {
			auto ret = __traits(getMember, instance, M)(params);
			ret = evaluateOutputModifiers!overload(ret, req, res);

			static if (is(RET : Json)) {
				res.writeJsonBody(ret);
			} else static if (is(RET : InputStream) || is(RET : const ubyte[])) {
				enum type = findFirstUDA!(ContentTypeAttribute, overload);
				static if (type.found) {
					res.writeBody(ret, type.value);
				} else {
					res.writeBody(ret);
				}
			} else static if (is(RET : const(char)[])) {
				res.writeBody(ret);
			} else {
				static assert(is(RET == void), M~": Only `InputStream`, `const(ubyte[])`, `Json`, `const(char)[]` and `void` are supported as return types for route methods.");
			}

How do I stop further writes to the body after writing data via an @after handler for a class that was loaded using vibe.web.web.registerWebInterface ?

Re: Writing to HTTPServerResponse body in @after Handler Does NOT Stop Further Processing

On Sat, 20 Jul 2019 19:16:42 GMT, Vijay Nayar wrote:

According to the documentation for the @after UDA, we have the following:

http://vibed.org/api/vibe.web.rest/after

For reference, the same error also happens when using registerRestInterface as well in vibe.web.rest, just it happens in different code.

[main(ZQhm) dbg] REST handler exception: object.Exception@../../.dub/packages/vibe-d-0.8.5/vibe-d/stream/vibe/stream/counting.d(183): Writing past end of output stream.
[main(ZQhm) dbg] ----------------
[main(ZQhm) dbg] /usr/include/dmd/phobos/std/exception.d:515 pure @safe void std.exception.bailOut!(Exception).bailOut(immutable(char)[], ulong, scope const(char)[]) [0x55a750a29a76]
[main(ZQhm) dbg] /usr/include/dmd/phobos/std/exception.d:436 pure @safe bool std.exception.enforce!().enforce!(bool).enforce(bool, lazy const(char)[], immutable(char)[], ulong) [0x55a750a299f2]

Re: Writing to HTTPServerResponse body in @after Handler Does NOT Stop Further Processing

On Sat, 20 Jul 2019 19:34:20 GMT, Vijay Nayar wrote:

On Sat, 20 Jul 2019 19:16:42 GMT, Vijay Nayar wrote:

According to the documentation for the @after UDA, we have the following:

http://vibed.org/api/vibe.web.rest/after

For reference, the same error also happens when using registerRestInterface as well in vibe.web.rest, just it happens in different code.

The errors themselves can be worked around by simply turning off the --vverbose option, so it is not a blocking bug.

For a better illustration of the use case, I have included a demonstration of how arbitrary MediaType conversions can be implemented on top of Vibe.d.

https://gist.github.com/vnayar/0da1c50faaece10a8bf65d76aff08456

This case is relatively simple, but there are many use cases that can be built up using this code in slightly different ways. For example:

  • Having a controller support two mediatypes, e.g. using Protobuf for efficiency in service communication, but still support JSON for debugging.
  • Providing data that is not JSON in a consistent way, e.g. having some endpoints produce pictures, PDFs, CSV, etc.