property ForwardUncommitted message "A ServletResponse was forwarded before being committed." // TODO assume InterleavedResponse_Weak prefix "javax.servlet" prefix "javax.servlet.{ServletOutputStream,ServletResponse}" prefix "java.io.PrintWriter" nondet (start) start -> start: * start -> tracking: R = "ServletResponse.\" tracking -> ok: flushBuffer(r) tracking -> gotWriter: W = getWriter(r) gotWriter -> ok: flush(w) gotWriter -> ok: flushBuffer(r) tracking -> gotStream: S = getOutputStream(r) gotStream -> ok: flush(s) gotStream -> ok: flushBuffer(r) tracking -> error: "RequestDispatcher.forward"(*, *, r) gotWriter -> error: "RequestDispatcher.forward"(*, *, r) gotStream -> error: "RequestDispatcher.forward"(*, *, r) // The documentation of ServletResponse.getOutputStream says that "either this // method getWriter may be called to write to the body, not both." So, // technically, the property is InterleavedResponse1. However, this property is // broken, which is why we also have the weaker version InterleavedResponse2. property InterleavedResponse1 message "A ServletResponse was asked for both a writer and a stream." prefix "javax.servlet.ServletResponse" nondet (start) start -> start: * start -> gotWriter: W = getWriter(R) start -> gotStream: S = getOutputStream(R) gotWriter -> error: getOutputStream(r) gotStream -> error: getWriter(r) property InterleavedResponse2 // vertex names: w = got writer; W = used writer; similarly for s, S message "Incompatible methods for putting data into a response were used." prefix "javax.servlet.ServletResponse" nondet (start) start -> start: * start -> w: W = getWriter(R) start -> s: S = getOutputStream(R) w -> sw: S = getOutputStream(r) s -> sw: W = getWriter(r) w -> W: *(w) sw -> sW: *(w) s -> S: *(s) sw -> Sw: *(s) W -> sW: S = getOutputStream(r) S -> Sw: W = getWriter(r) sW -> error: *(s) Sw -> error: *(w)