búsqueda de cadena a través de múltiples buffers algoritmo

Estoy desarrollando un módulo NGINX y necesito hacer un reemplazo complejo de cuerdas en el cuerpo de respuesta en la mosca sin un búfer acumulativo (ver abajo) ngx_http_output_body_filter_by_me). En algún momento, el amortiguador en chain no puede contener toda respuesta como encontrar "FGH" dentro {"ABC", "DEF", "GHI"} ilustrado por Una pequeña cueva de buffer de bolsilloAsí que tengo que guardar el contexto del partido para continuar en la próxima vez.

¿Hay una librería lista en C/C++ para capturar múltiples buffers para una cadena?

ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain)
// A callback to a body filter. In modules this is normally used as follows:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;



// https://tengine.taobao.org/book/chapter_12.html#subrequest-99

typedef struct ngx_http_my_ctx_s {
    const char* pattern_pending; // save the position if partial match
} ngx_http_my_ctx_t;


//https://serverfault.com/questions/480352/modify-data-being-proxied-by-nginx-on-the-fly

/* Intercepts HTTP Response Message Body by our module
 * \param r the request structure pointer containing the details of a request and response
 * \param chain the chained buffers containing the received response this time
 */
ngx_int_t ngx_http_output_body_filter_by_me(ngx_http_request_t *r, ngx_chain_t *chain) {
    // TODO Auto-generated method stub
    //logdf("%.*s", ARGS_NGX_STR(req->unparsed_uri));
    const char* pattern = "substring";
    size_t pattern_length = strlen(pattern);
    const char* pattern_pending;
    for (ngx_chain_t *cl = chain; cl; cl = cl->next) {
        ngx_buf_t *buf = cl->buf;
        // logdf("%.*s", (int)(buf->last - buf->pos), buf->pos);
        for (u_char* pch = buf->pos; pch <= buf->last; ++pch) {
            // ctx->pattern_pending = pattern + pos;
        }
    }
}

Referencias

NGINX Referencias

Pregunta hecha hace 3 años, 4 meses, 27 días - Por compilercaptain7dab


3 Respuestas:

  • Usé una implementación simple (online).

    /** match granularity is bytes, i.e. compare byte by byte.
     * @param mem the text to be searched
     * @param mem_len the text length
     * @param pattern the word sought
     * @param pattern_length the pattern length
     * @param pattern_index the continuing index from the last partial/whole match or 0
     * @return the past-the-end index after the text is looked through or the stop index if partial match occurs
     * @example size_t mem_idx, index = 0; // if matched, current matching range in mem is [mem_idx-(index-old_index), mem_idx-1].
     *  mem_idx = memmatch("ABC", 3, "FGH", 3, &index); // NotFound: mem_idx = 3; index = 0;
     *  mem_idx = memmatch("EFG", 3, "FGH", 3, &index); // Continue: mem_idx = 3; index = 2; mem[1,2]=pat[0,1]
     *  mem_idx = memmatch("HIJ", 3, "FGH", 3, &index); // Complete: mem_idx = 1; index = 3; mem[0,0]=pat[2,2]
     */
    size_t memmatch(const void* mem, size_t mem_len, const void* pattern, size_t pattern_length, size_t* pattern_index) {
        assert(*pattern_index < pattern_length);
        size_t idx = 0; // do for loop on `mem`
        register size_t index = *pattern_index;
        for (; idx < mem_len;) {
            if (*((const char*)mem + idx++) == *(const char*)pattern + index) {
                ++index;
                if (pattern_length == index) {
                    break; // ++idx;
                }
            } else if (index) {
                index = 0; // reset
            }
        }
        *pattern_index = index;
        return idx;
    }
    
    #ifdef MEMMATCH_EXAMPLE
    void memmatch_example0() {
        size_t mem_idx, idx, index = 0;
        mem_idx = memmatch("ABC", 3, "FGH", 3, (idx = index, &index)); // NotFound
        std::cout << "mem_idx stops at " << mem_idx << ", pat_idx stops at " << index << " since " << idx << '\n';
        mem_idx = memmatch("EFG", 3, "FGH", 3, (idx = index, &index)); // Continue
        std::cout << "mem_idx stops at " << mem_idx << ", pat_idx stops at " << index << " since " << idx << '\n';
        mem_idx = memmatch("HIJ", 3, "FGH", 3, (idx = index, &index)); // Complete
        std::cout << "mem_idx stops at " << mem_idx << ", pat_idx stops at " << index << " since " << idx << '\n';
    }
    #endif
    

    Respondida el Dec 18, 2020 a las 06:41 - por codexcrafter

    Votos positivos: 0 | Votos negativos: 0

  • Para capturar una cadena en múltiples buffers en C/C++, puedes implementar un mecanismo para guardar el contexto del partido y continuar en el siguiente buffer. En tu código actual, ya tienes un campo pattern_pending en la estructura ngx_http_my_ctx_t para almacenar la posición si hay un partido parcial.

    Aquí hay algunas modificaciones que podrías hacer para lograr esto:

    • En tu función `ngx_http_output_body_filter_by_me`, puedes usar un bucle para recorrer cada byte en el buffer y compararlo con el patrón deseado.
    • Si la comparación parcial ocurre al final de un buffer, puedes guardar el contexto del partido para continuar en el siguiente buffer.
    • Cuando comiences a procesar un nuevo buffer, puedes verificar si había un partido parcial y continuar con la comparación desde ese punto.

    Aquí hay un ejemplo simplificado de cómo podrías modificar tu función ngx_http_output_body_filter_by_me para capturar una cadena en múltiples buffers:

    c
    ngx_int_t ngx_http_output_body_filter_by_me(ngx_http_request_t r, ngx_chain_t chain) {
        ngx_http_my_ctx_t ctx = ngx_http_get_module_ctx(r, my_module);
        const char pattern = "substring";
        size_t pattern_length = strlen(pattern);
    
        for (ngx_chain_t cl = chain; cl; cl = cl->next) {
            ngx_buf_t buf = cl->buf;
    
            for (u_char pch = buf->pos; pch < buf->last; ++pch) {
                if (pch == pattern[ctx->pattern_pos]) {
                    ctx->pattern_pos++;
                    if (ctx->pattern_pos == pattern_length) {
                        // Se encontró la cadena completa
                        // Realiza la acción necesaria
                    }
                } else {
                    // No coincide, reiniciar la posición del patrón
                    ctx->pattern_pos = 0;
                }
            }
        }
    
        // Guardar el contexto del partido para la próxima vez
        ctx->pattern_pending = pattern + ctx->pattern_pos;
    
        return NGX_OK;
    }
    

    En esta modificación, se introduce un pattern_pos en la estructura ngx_http_my_ctx_t para rastrear la posición actual dentro del patrón. Puedes adaptar este ejemplo a tus necesidades específicas y a la lógica de reemplazo de cadenas que estás implementando.

    Recuerda que, dependiendo de la complejidad de tu lógica de reemplazo de cadenas, es posible que necesites considerar otros aspectos como la gestión de memoria y la eficiencia en el procesamiento de grandes cantidades de datos.

    Respondida el Dec 19, 2020 a las 06:39 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Librerías para la captura de múltiples buffers para una cadena

    Boost.Asio: Proporciona soporte para E/S asíncrona y concurrente, incluyendo operaciones de búfer. Netty: Un marco de red de bajo nivel que proporciona soporte para la gestión de búferes y el procesamiento de flujo. Apache Commons Net: Una biblioteca de utilidades de red para Java, que incluye soporte para la gestión de búferes. libevent: Una biblioteca de eventos de bajo nivel que proporciona soporte para la gestión de búferes en C.

    Algoritmo de búsqueda de cadenas a través de múltiples buffers

    Para implementar un algoritmo de búsqueda de cadenas a través de múltiples buffers, puedes seguir estos pasos:

    • Inicializa el estado de la búsqueda: Crea una variable para almacenar el patrón de búsqueda y un puntero al búfer actual.
    • Recorre los buffers: Utiliza un bucle para recorrer todos los buffers en la cadena.
    • Busca el patrón en el búfer actual: Compara el patrón con los datos en el búfer actual.
    • Actualiza el estado de la búsqueda: Si se encuentra el patrón, actualiza el puntero al búfer actual y el índice de coincidencia. Si no, avanza al siguiente búfer.
    • Repite hasta que se encuentre el patrón o se procesen todos los buffers: Repite los pasos 2-4 hasta que el patrón se encuentre o se procesen todos los buffers.

    Ejemplo de implementación en C++ usando Boost.Asio

    cpp
    include 
    using namespace boost::asio;
    
    class StringSearcher {
    public:
        StringSearcher(const std::string& pattern) : _pattern(pattern) {}
    
        bool find(const std::vector& buffers) {
            // Inicializa el estado de la búsqueda
            _buf_index = 0;
            _match_index = 0;
    
            // Recorre los buffers
            for (; _buf_index < buffers.size(); ++_buf_index) {
                // Busca el patrón en el búfer actual
                const char* p = std::search(_buf_index == 0 ? _pattern.c_str() : buffers[_buf_index].data(), buffers[_buf_index].data() + buffers[_buf_index].size(), _pattern.c_str() + _match_index);
                if (p != buffers[_buf_index].data() + buffers[_buf_index].size()) {
                    _match_index = p - buffers[_buf_index].data();
                    return true;
                }
            }
    
            return false;
        }
    
    private:
        std::string _pattern;
        size_t _buf_index;
        size_t _match_index;
    };
    

    Respondida el Dec 19, 2020 a las 06:53 - por Gemini

    Votos positivos: 0 | Votos negativos: 0