Menu

Developers

chtsanti

Developers

Notes for developers

APIs Documentation

C-icap uses the doxygen documentation system to document API functions. To produce the API documentation you need to have doxygen installed. Then under the c-icap source distribution, just run:

make doc

The documentation will be produced in HTML form under the directory ''docs/html/''. The c-icap is still under development so some of its API interfaces are not complete and they are subject to change. However someone should not expect huge changes between different releases (0.x releases).

In this page also exist some sample code for the major tools provided by the c-icap server.

Writing services

Before start writing your own service you need to:

  • read the basics about ICAP protocol:
    • reqmod and respmod requests
    • encapsulated objects (HTTP headers and body data)
    • the ICAP preview mechanism
    • the allow 204 inside and outside preview responses
    • the 100 continue responses
  • study the echo example service distributed with the c-icap server. This service implemented in services/echo/srv_echo.c file
  • install doxygen and produce documentation

To modify/examine an HTTP objects (HTTP requests or responses) there is a number of utility functions. Most of them are documented with doxygen documentation system in the following modules/sections:

  • Headers related API
  • ICAP request API
  • Services API
  • API for HTTP object manipulation
  • utility funtions

How to use c-icap configuration subsystem

The c-icap provides an easy way to allow developers define their own configuration parameters for services and modules. Example usage:

char *CONF1 = NULL;
int CONF2 = -1;
int MYCFG_PARAM = 0;

int my_cfg_handler(char *directive, char **argv, void *setdata);

/*Configuration table, should attached to the related ci_service_t object .....*/
static struct ci_conf_entry conf_variables[] = {
  {"Conf1", &CONF1, ci_cfg_set_str, NULL}, /* use the ci_cfg_set_str predefined handler */
  {"Conf2", &CONF2, ci_cfg_onoff, NULL}, /* use the ci_cfg_onoff predefined handler */
  {"Conf3", NULL, my_cfg_handler, NULL}, /* use a custom handler */
  {NULL, NULL, NULL, NULL}
};

/*example custom configuration handler*/
int my_cfg_handler(char *directive, char **argv, void *setdata)
{
  if (argv[0]!= NULL) {
     MYCFG_PARAM = atoi(argv[0]);
     return 1;
  } else
     return 0;
}

For the available configuration parameter handlers, look in the configuration API module/section in c-icap documentation.

How to use c-icap acls

To create an access list and add acls use the following code:

ci_access_entry_t *My_Access_List = NULL;

...

/*Normally the following code exist inside a configuration parameter handler*/
ci_access_entry_t *access_entry;
if ((access_entry = ci_access_entry_new(&My_Access_List), 
                   CI_ACCESS_ALLOW /*or CI_ACCESS_DENY*/))  == NULL) {
     return ERROR;
}
for (argc = 0; argv[argc]!= NULL; argc++) {
    char *acl_spec_name = argv[argc];
    if (!ci_access_entry_add_acl_by_name(access_entry, acl_spec_name)) {
         ci_debug_printf(1,"Error adding acl spec: %s, (is it defined?)\n", acl_spec_name);
         return ERROR;
    }
}

To check if an access list matches a request use :

/*My_Access_List is a global variable*/
ci_access_entry_t *My_Access_List;
...

ci_request_t *current_req = req;
int ret;
if (ret=ci_access_entry_match_request(My_Access_List,current_req)) {
    /*The request matches the accesslist*/
    if (ret == CI_ACCESS_ALLOW) {
        /*Allowed*/
    }
    else { /* CI_ACCESS_DENY or CI_ACCESS_UNKNOWN */
        /*denied*/
    }
 }

How to use templates

The following code creates the ERROR_FOUND template for the my_srv error page. This template should stored in the TemplateDir/my_srv/en/ERROR_FOUND file.

ci_membuf_t *error_page;
error_page = ci_txt_template_build_content(req, "my_srv", "ERROR_FOUND",
                       NULL);
...
/*release error_page*/
ci_membuf_free(error_page);

The following creates the template ERROR_FOUND for the service my_srv using custom formating codes: The %TT formating code produces the "TEST" string.

static int fmt_test(ci_request_t *req, char *buf, int len, char *param)
{
    return snprintf(buf, len, "TEST");
}

struct ci_fmt_entry my_fmt_table [] = {
    {"%TT", "A Test", fmt_test},
    { NULL, NULL, NULL}
}

ci_membuf_t *error_page;
error_page = ci_txt_template_build_content(req, "my_srv", "AN-ERROR",
                         my_fmt_table);
...
/*release error_page*/
ci_membuf_free(error_page);

How to use c-icap statistics subsystem

Visit this web page for an easy way to configure and view c-icap runtime statistics: FAQ:How can I get some c-icap runtime statistics

/* Create the REQUESTS_PROCCESSED and BYTES_PROCESSED counters.
   This part of code normally placed in ci_service_module::mod_post_init_service or 
   ci_service_module::mod_init_service service handlers
*/ 
REQUESTS_PROCCESSED = ci_stat_entry_register("Requests processed", STAT_INT64_T,  "My Service");
BYTES_PROCESSED =  ci_stat_entry_register("Bytes processed", STAT_KBS_T,  "My Service");
if (REQUESTS_PROCCESSED < 0 || BYTES_PROCESSED < 0) {
   /*an error*/
   return CI_ERROR;
}
....

/*Increase the REQUESTS_PROCCESSED and BYTES_PROCESSED counters:*/
ci_stat_uint64_inc(REQUESTS_PROCESSED, 1);
ci_stat_kbs_inc(BYTES_PROCESSED, bytes);  /*bytes is the size of processed object*/

How to use lookup tables

/* Create a hash lookup table. Just fix the path variable to create file, bdb or ldap tables.
   This part of code normally placed in ci_service_module::mod_post_init_service or 
   ci_service_module::mod_init_service service handlers
*/
struct ci_lookup_table *lt_db;
const char *path = "hash:/path/to/file.txt"
lt_db = ci_lookup_table_create(path);
if (lt_db && !lt_db->open(lt_db)) {
    ci_lookup_table_destroy(lt_db);
    lt_db = NULL;
}
...
/* To search in the lookup table for a record with key "chtsanti" use
   the following code. The record will be stored to a NULL terminated 
   string array and will be set to vals..
*/
char **vals=NULL;
const char *key="chtsanti";
ret = lt_db->search(lt_db, key, (void ***)&vals);
/* do something with vals */
for (i=0; vals[i]!= NULL, i++)
     print("Found the value:%s", vals[i])
lt_db->release_result(lt_db, vals);
...

/*The lookup table does not needed any more destroy it */
ci_lookup_table_destroy(lt_db);

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.