apr_status_t serf_connection__request_requeue()

in src/outgoing_request.c [573:688]


apr_status_t serf_connection__request_requeue(serf_request_t *request)
{
    serf_request_t *discard;
    serf_request_t **pr;

    /* For some reason, somebody wants to restart this request, that was
       at least partially written and partially read. Most likely to
       slightly change it. (E.g. to add auth headers).

       To handle this we have to do two things: we have to handle remaining
       incoming data on the existing request. And we have to make the request
       ready to write it again.. preferably as the first new request.
     */

    /* Setup a new request to handle discarding the remaining body */
    discard = create_request(request->conn,
                             NULL, NULL,
                             request->priority,
                             request->ssltunnel);

    discard->respool = request->respool;
    discard->allocator = request->allocator;
    discard->req_bkt = request->req_bkt;
    discard->resp_bkt = request->resp_bkt;

    discard->setup = NULL;  /* Already setup */
    discard->setup_baton = NULL;

    discard->acceptor = NULL;
    discard->acceptor_baton = NULL; /* Already accepted */

    discard->handler = discard_response_handler;
    discard->handler_baton = NULL;

    discard->protocol_baton = request->protocol_baton;
    discard->auth_done = request->auth_done;
    discard->auth_baton = request->auth_baton;

    discard->writing = request->writing;

    if (discard->respool) {
        apr_pool_cleanup_kill(discard->respool, request, clean_resp);
        apr_pool_cleanup_register(discard->respool, discard,
                                  clean_resp, apr_pool_cleanup_null);
    }

    if (request->depends_on) {
        /* Update request dependencies */
        discard->depends_on = request->depends_on;

        for (pr = &discard->depends_on->depends_first;
             *pr;
             pr = &(*pr)->depends_next)
        {
            if (*pr == request) {
                *pr = discard;
                discard->depends_next = request->depends_next;
                request->depends_next = NULL;
                request->depends_on = NULL;
                break;
            }
        }
    }
    if (request->depends_first) {
        serf_request_t *r;

        for (r = request->depends_first; r; r = r->depends_next) {
            r->depends_on = discard;
        }
        discard->depends_first = request->depends_first;
        request->depends_first = NULL;
    }

    /* And now make the discard request take the place of the old request */
    for (pr = &request->conn->written_reqs; *pr; pr = &(*pr)->next) {
        if (*pr == request) {
            *pr = discard;
            discard->next = request->next;
            request->next = NULL;

            if (!discard->next)
                request->conn->written_reqs_tail = discard;
            break;
        }
    }

    /* Tell the protocol handler (if any) that we are no longer looking at the
       request */

    if (request->conn->perform_cancel_request)
        request->conn->perform_cancel_request(discard, SERF_ERROR_HTTP2_CANCEL);

    /* And now unhook the existing request */
    request->allocator = NULL;
    request->respool = NULL;
    request->req_bkt = NULL;
    request->resp_bkt = NULL;
    request->writing = SERF_WRITING_NONE;
    request->auth_baton = NULL;
    request->protocol_baton = NULL;

    request->acceptor = NULL;
    request->acceptor_baton = NULL;
    request->handler = NULL;
    request->handler_baton = NULL;
    request->auth_done = false;

    if (discard->depends_first || discard->depends_on) {
        serf_connection_request_prioritize(request, discard, 0xFFFF,
                                           TRUE);
    }

    insert_priority_request(request);

    return APR_SUCCESS;
}