|
|
|
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.\<init\>"
|
|
|
|
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)
|