• Dridi Boukelmoune's avatar
    htc: Defer workspace rollbacks for request tasks · 5b4f0f1a
    Dridi Boukelmoune authored
    When we take on a new request on a connection from which something was
    already received, we need to pipeline it and we do so at the beginning
    of the request workspace. There's a high probability that the pipeline
    is coming from the same workspace, which is a form of use-after-free
    only made safe by the workspace implementation details.
    
    To avoid the conceptual use-after-free, we defer req workspace rollbacks
    and perform them during the next HTC_RxInit() call before the pipelining
    operation.
    
    Because HTTP/1 works directly on the session, a worker can safely switch
    back and forth between sess and req tasks. This means that unless the
    session goes idle the same workspace is used from one client request
    to the next, hence the rollback previously happening in Req_Cleanup().
    
    With h2 however there is a disconnect between the session and streams.
    The connection is received in req0's workspace, and then copied into
    a stream's req workspace via the pipelining scheme. Rollbacks can be
    deferred as well, but they need to happen otherwise the session will
    soon overflow. Independent HTC_RxInit() calls happen for req0 in the
    h2 session thread, and for h2 streams in the regular request task code
    path.
    
    PROXY Protocol parsing may result in receiving more than the proxy
    preamble itself and pipelining will happen, whether it is via a req
    for HTTP/1 or req0 for h2.
    
    On the other end of the spectrum when Varnish acts as a client it
    only sends one HTTP/1 request at a time for a given connection, so
    we never expect pipelining to occur in fetch task.
    5b4f0f1a