<commit_before>#define _GNU_SOURCE
#include <assert.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>

#include "core.h"

#define bool int
#define TRUE 1
#define FALSE 0

#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

static int ws_head_slice(ws_request_t *req, int size);
static int ws_body_slice(ws_request_t *req, int size);
static void ws_graceful_finish(ws_connection_t *conn, bool eat_last);

static void ws_request_init(ws_request_t *req, ws_connection_t *conn, char*buf){
    obstack_init(&req->pieces);
    req->conn = conn;
    memcpy(&req->req_callbacks,conn->req_callbacks, sizeof(req->req_callbacks));
    req->network_timeout = conn->network_timeout;
    req->headers_buf = buf;
    req->bufposition = 0;
    req->headerlen = 0;
    req->body = 0;
    req->bodylen = 0;
    req->bodyposition = 0;
    req->next = NULL;
    req->prev = NULL;
    req->reply_state = 0;
    req->reply_head = NULL;
    req->reply_head_size = 0;
    req->reply_body = NULL;
    req->reply_body_size = 0;
    req->reply_pos = 0;
    req->reply_watch.active = 0;
}

static void ws_request_new(ws_connection_t *conn) {
    ws_request_t *req = (ws_request_t*)malloc(conn->_req_size
        + conn->max_header_size);
    if(!req) {
        ws_graceful_finish(conn, FALSE);
        return;
    }
    ws_request_init(req, conn, (char *)req + conn->_req_size);
    if(conn->last_req) {
        conn->last_req->next = req;
        req->prev = conn->last_req;
    } else {
        conn->first_req = req;
    }
    conn->last_req = req;
    ++conn->request_num;
}

int ws_request_free(ws_request_t *req) {
    obstack_free(&req->pieces, NULL);
    free(req);
}

static void ws_request_finish(ws_request_t *req) {
    bool need_free = TRUE;
    if(req->headerlen) {
        ws_request_cb cb = req->req_callbacks[WS_REQ_CB_FINISH];
        if(cb) {
            need_free = cb(req) <= 0;
        }
    }
    if(req->reply_watch.active) {
        ev_io_stop(req->conn->loop, &req->reply_watch);
    }
    if(req->next) {
        req->next->prev = req->prev;
    } else {
        req->conn->last_req = req->prev;
    }
    if(req->prev) {
        req->prev->next = req->prev;
    } else {
        req->conn->first_req = req->next;
    }
    req->conn->request_num -= 1;
    if(need_free) {
        ws_request_free(req);
    }
}

static void ws_connection_close(ws_connection_t *conn) {
    while(conn->first_req) {
        ws_request_finish(conn->first_req);
    };
    if(&conn->watcher.active) {
        ev_io_stop(conn->loop, &conn->watcher);
    }
    if(&conn->timeo.active) {
        ev_timer_stop(conn->loop, &conn->timeo);
    }
    close(conn->watcher.fd);
    ws_connection_cb cb = conn->conn_callbacks[WS_CONN_CB_DISCONNECT];
    if(cb) {
        cb(conn);
    }
    if(conn->next) {
        conn->next->prev = conn->prev;
    } else {
        conn->serv->last_conn = conn->prev;
    }
    if(conn->prev) {
        conn->prev->next = conn->next;
    } else {<commit_msg>Now you can free request inside `finish` handler<commit_after>#define _GNU_SOURCE
#include <assert.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>

#include "core.h"

#define bool int
#define TRUE 1
#define FALSE 0

#define obstack_chunk_alloc malloc
#define obstack_chunk_free free

static int ws_head_slice(ws_request_t *req, int size);
static int ws_body_slice(ws_request_t *req, int size);
static void ws_graceful_finish(ws_connection_t *conn, bool eat_last);

static void ws_request_init(ws_request_t *req, ws_connection_t *conn, char*buf){
    obstack_init(&req->pieces);
    req->conn = conn;
    memcpy(&req->req_callbacks,conn->req_callbacks, sizeof(req->req_callbacks));
    req->network_timeout = conn->network_timeout;
    req->headers_buf = buf;
    req->bufposition = 0;
    req->headerlen = 0;
    req->body = 0;
    req->bodylen = 0;
    req->bodyposition = 0;
    req->next = NULL;
    req->prev = NULL;
    req->reply_state = 0;
    req->reply_head = NULL;
    req->reply_head_size = 0;
    req->reply_body = NULL;
    req->reply_body_size = 0;
    req->reply_pos = 0;
    req->reply_watch.active = 0;
}

static void ws_request_new(ws_connection_t *conn) {
    ws_request_t *req = (ws_request_t*)malloc(conn->_req_size
        + conn->max_header_size);
    if(!req) {
        ws_graceful_finish(conn, FALSE);
        return;
    }
    ws_request_init(req, conn, (char *)req + conn->_req_size);
    if(conn->last_req) {
        conn->last_req->next = req;
        req->prev = conn->last_req;
    } else {
        conn->first_req = req;
    }
    conn->last_req = req;
    ++conn->request_num;
}

int ws_request_free(ws_request_t *req) {
    obstack_free(&req->pieces, NULL);
    free(req);
}

static void ws_request_finish(ws_request_t *req) {
    if(req->reply_watch.active) {
        ev_io_stop(req->conn->loop, &req->reply_watch);
    }
    if(req->next) {
        req->next->prev = req->prev;
    } else {
        req->conn->last_req = req->prev;
    }
    if(req->prev) {
        req->prev->next = req->prev;
    } else {
        req->conn->first_req = req->next;
    }
    req->conn->request_num -= 1;
    bool need_free = TRUE;
    if(req->headerlen) {
        ws_request_cb cb = req->req_callbacks[WS_REQ_CB_FINISH];
        if(cb) {
            need_free = cb(req) <= 0;
        }
    }
    if(need_free) {
        ws_request_free(req);
    }
}

static void ws_connection_close(ws_connection_t *conn) {
    while(conn->first_req) {
        ws_request_finish(conn->first_req);
    };
    if(&conn->watcher.active) {
        ev_io_stop(conn->loop, &conn->watcher);
    }
    if(&conn->timeo.active) {
        ev_timer_stop(conn->loop, &conn->timeo);
    }
    close(conn->watcher.fd);
    ws_connection_cb cb = conn->conn_callbacks[WS_CONN_CB_DISCONNECT];
    if(cb) {
        cb(conn);
    }
    if(conn->next) {
        conn->next->prev = conn->prev;
    } else {
        conn->serv->last_conn = conn->prev;
    }
    if(conn->prev) {
        conn->prev->next = conn->next;
    } else {
{'fraction_non_alphanumeric': 0.15258769859996854, 'fraction_numerical': 0.004404593361648577, 'mean_word_length': 2.8815628815628815, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 181, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1291468', 'n_tokens_mistral': 2430, 'n_tokens_neox': 2359, 'n_words': 409}