Search code examples
httpfreelibevent

Should I call evhttp_request_free to release resource in http server?


I use libevent2.1.1 to write a simple http server, I think I should release evhttp_request with evhttp_request_free in http_server_callback. but when I run it, error happened. Please tell me why, and what I should do.

enter image description here

void http_server_callback (struct evhttp_request *req, void *arg)
{
    evhttp_send_reply (req, HTTP_OK, "OK", NULL);

    evhttp_request_free(req);
}

int http_server_run (void)
{ 
    struct event_base *base;
    struct evhttp *http;
    struct evhttp_bound_socket *handle;

    base = event_base_new ();
    if (! base)
    { 
        fprintf (stderr, "Couldn't create an event_base: exiting\n");
        return 1;
    }

    http = evhttp_new (base);
    if (! http)
    { 
        fprintf (stderr, "couldn't create evhttp. Exiting.\n");
        return 1;
    }

    evhttp_set_gencb (http, http_server_callback, NULL);

    handle = evhttp_bind_socket_with_handle (http, "127.0.0.1", 8888);
    if (! handle)
    { 
        fprintf (stderr, "couldn't bind to port 8888. Exiting.\n");
        return 1;
    }

    event_base_dispatch (base);

    return 0;
}

int main (void)
{ 
    WSADATA WSAData;
    WSAStartup (0x101, &WSAData);

    http_server_run();

    return 0;
}

thanks in advance


Solution

  • the req will be freed in the callback function evhttp_send_done when server finishes writing. So it results in a double free.
    the source code in libevent:

    static void
    evhttp_send_done(struct evhttp_connection *evcon, void *arg)
    {
        int need_close;
        struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
        TAILQ_REMOVE(&evcon->requests, req, next);
    
        need_close =
            (REQ_VERSION_BEFORE(req, 1, 1) &&
            !evhttp_is_connection_keepalive(req->input_headers))||
            evhttp_is_connection_close(req->flags, req->input_headers) ||
            evhttp_is_connection_close(req->flags, req->output_headers);
    
        EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
        evhttp_request_free(req);
        ...
    }