Использование кода httpd (апача) в своей программе

Представим ситуацию, когда вам надо использовать в своей программе кусок кода из опенсорсного проекта. В отдельных случаях удастся этот кусок локализовать и просто скопировать не заботясь о зависимости от других библиотек того самого опенсорсного проекта. Я рассмотрю более общий случай, когда зависимости (типы данных или функции) приходится тащить с собой.

В качестве примера будет функционал httpd, который создает хешированную строку фиксированной длины по исходной строке. В httpd так в частности создается путь для кеширования страницы исходя из ее URL. В результате вы сможете с помощью своего достаточно легковесного бинарника проверять есть ли в кеше определенная страница.

#include <stdio.h>
#include <apr_md5.h>
 
static void doHash(const char* it, char* val, int nlength, int ndepth)
{
    apr_md5_ctx_t context;
    unsigned char digest[16];
    char tmp[22];
    int i, k, d;
    unsigned int x;
    static const char enc_table[64] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
 
    apr_md5_init(&context);
    apr_md5_update(&context, (const unsigned char *) it, strlen(it));
    apr_md5_final(digest, &context);
 
    /* encode 128 bits as 22 characters, using a modified uuencoding
     * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is
     * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
     */
    for (i = 0, k = 0; i < 15; i += 3) {
        x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
        tmp[k++] = enc_table[x >> 18];
        tmp[k++] = enc_table[(x >> 12) & 0x3f];
        tmp[k++] = enc_table[(x >> 6) & 0x3f];
        tmp[k++] = enc_table[x & 0x3f];
    }
 
    /* one byte left */
    x = digest[15];
    tmp[k++] = enc_table[x >> 2];    /* use up 6 bits */
    tmp[k++] = enc_table[(x << 4) & 0x3f];
 
    /* now split into directory levels */
    for (i = k = d = 0; d < ndepth; ++d) {
        memcpy(&val[i], &tmp[k], nlength);
        k += nlength;
        val[i + nlength] = '/';
        i += nlength + 1;
    }
    memcpy(&val[i], &tmp[k], 22 - k);
    val[i + 22 - k] = '\0';
}
 
int main(int argc, char *argv[])
{
    // mandatory parameters
    char* url;
 
    if (argc == 2 || argc == 4) // 4 if length and depth were specified
    {
        url = argv[1];
    }
    else
    {
        printf("\nUsage: HashDir url <length> <depth>\n");
        return 1;
    }
 
    // optional parameters
    int nlength = 3; // my own default values
    int ndepth = 5;
    if (argc == 4)
    {
        nlength = atoi(argv[2]);
        ndepth = atoi(argv[3]);
    }
 
    char hash1[66];
    char str1[256] = {""};
    strcat(str1, url);
    strcat(str1, "?");
    doHash(str1, hash1, nlength, ndepth);
 
    char hash2[66];
    char str2[512] = {""};
	// can't recall what happens here in vanilla httpd, probably something 
	// appended to str2 via strcat()
 
    strcat(str2, str1);
    doHash(str2, hash2, nlength, ndepth);
 
    char output[256];
	output[0] = '\0'; // sometimes there are junk characters in the beginning, so need to set null length explicitly
    strcat(output, hash1);
    strcat(output, ".header.vary/");
    strcat(output, hash2);
    strcat(output, ".data");
 
    printf("\nurl[%s]\nhashed path[%s]\n", url, output);
    return 0;
}

Сборка осуществляется так:

gcc -m32 -D_GNU_SOURCE -I/apache/include -Llib -laprutil-1 -lapr-1 -lexpat Hasher.c -o Hasher

(поставьте свой путь к хедерам, нужен apr_md5.h)

Запускается программа с помощью скрипта, который создает необходимое окружение:

#!/bin/sh
 
LD_LIBRARY_PATH=./lib ./Hasher $@

В папке lib надо иметь те библиотеки, которые были использованы при сборке: libaprutil-1 libapr-1 libexpat.

Запуск:

./run.sh rrrr 4 3

После запуска получается примерно такая строка:

xNQ/QC2/IbV/aZc/r23/tg3kj2Q.header.vary/ZIy/ZJr/5og/jP0/qK6/0c7t4ZA.data


You can leave a response, or trackback from your own site.

Leave a Reply