Hi All,
I'm writing a module called mod_gfx which will perform on-the-fly image resizing via libgd. I wanted to make the module as configurable as possible so others can take advantage of it as well. I'm currently running into a rough spot with custom containers, but first I'd like to make mention of how the module works.

Essentially, you define conversion profiles in the module's conf file that define what happens when that image is requested. Typical URLs implementing this scheme will look like:

http://image.server.com/largesize/12/23/34/122334.jpg
http://image.server.com/thumbnail/images/logo.png
http://image.server.com/watermark/m/my_dog.gif

The first component of the path is a "profile" name that can be declared in a configuration file like this:

<GfxProfile "fullsize">
    GfxActions resize
    GfxMaxX 640
    GfxMaxY 480
    GfxQual 75
</GfxProfile>

<GfxProfile "thumbnail">
    GfxActions resize
    GfxMaxX 75
    GfxMaxY 75
    GfxQual 60
</GfxProfile>

<GfxProfile "watermark">
    GfxActions watermark
    GfxFile watermark.gif
    GfxLocX 0
    GfxLocY 0
</GfxProfile>



**Skip to here for problem**
I've got most of the above all working well. The other part of this module is to perform a match on the URL and be able to select which origin server it gets the content from. The big problem comes when I want to implement another container. I would like to do something like the following:

GfxOriginMatch OldServer ^/images/.*$
GfxOriginMatch NewServer ^/[a-z]/.*$

<GfxOrigin "OldServer">
    #round robin origin requests between these servers
    GfxOriginHost server1.olddomain.com
    GfxOriginHost server2.olddomain.com
</GfxOrigin>

<GfxOrigin "NewServer">
    GfxOriginHost server1.imageserver.com
    GfxOriginHost server2.imageserver.com
    GfxOriginHost server3.imageserver.com
</GfxOrigin>

I can't seem to figure out how to get both of these containers playing nicely with each other. I've been trying different things all day and trying to wrap my head around how apache handles configs, but I just don't seem to get it. At this point, my source code is riddled with debugging and random experiments. I don't know if it will be much use, but I posted it at the end of this email. For now, I have some direct questions:

1) Do I need to implement a config allocator under "STANDARD20_MODULE_STUFF"? If so, what exactly am I allocating? It seems like I can only allocate 1 type of container, yet I have 2.

2) When I run ap_walk_config() from inside of gfx_config_profile(), it appears to invoke the functions for the directives inside of my <GfxProfile> block, however these functions handling the directives (gfx_profile_actions in my source) don't appear to get a pointer to the parent config block (which I need to work with). Why is that?

3) What does ap_conf_vector do? Is it just an opaque type to hide something? I would really like to just pass some pointers around.


Thanks,
Mike




static const char*
gfx_config_profile(cmd_parms* cmd, void* mconfig, const char* arg) {
    const char* endp = ap_strrchr_c(arg, '>');
    const char* args;
    char* profile_name;
    ap_conf_vector_t* gfx_conf;

    //create a new profile for each <GfxProfile> encountered
    gfx_conf = ap_create_per_dir_config(cmd->pool);
gfx_server_config_t* sconf = ap_get_module_config(cmd->server->module_config, &gfx_module); gfx_profile_config_t* profile = (gfx_profile_config_t*)apr_pcalloc(cmd->pool, sizeof(gfx_profile_config_t));
    gfx_conf = (ap_conf_vector_t*)profile;
const char* err = ap_check_cmd_context(cmd, NOT_IN_LIMIT | NOT_IN_DIRECTORY);

    if (err != NULL)
        return err;

    //get the profile name (argument to <GfxProfile>)
    //do some checks for good measure
    args = apr_pstrndup(cmd->pool, arg, endp - arg);
    if (!args[0])
return apr_psprintf(cmd->pool, "%s %s", cmd->cmd->name, "> directive requires profile name");

    if (endp == NULL)
return apr_psprintf(cmd->pool, "%s %s", cmd->cmd->name, "> directive missing closing '>'");

    profile_name = ap_getword_conf(cmd->pool, &args);
    if (!profile_name)
return apr_psprintf(cmd->pool, "%s %s", cmd->cmd->name, "> error reading profile name");

//i think this associates the generic config type with my profile config //profile = ap_set_config_vectors(cmd->server, gfx_conf, profile_name, &gfx_module, cmd->pool);

//not sure yet - i hope it iterates over the gfx parms in the <GfxProfile>
    err = ap_walk_config(cmd->directive->first_child, cmd, gfx_conf);
    if (err != NULL)
        return err;

    //setup profile
    profile->name = apr_pstrdup(cmd->pool, profile_name);
    profile->output_format = IMAGE_TYPE_SRC;
    profile->actions = apr_array_make(cmd->pool, 8, MAX_LEN);
    profile->rsx = -1;
    profile->rsy = -1;
    profile->qual = -1;

    //add profile to server profiles hashmap
//gfx_server_config_t* sconf = ap_get_module_config(cmd->server->module_config, &gfx_module); apr_hash_set(sconf->profiles, profile->name, APR_HASH_KEY_STRING, profile);

    return NULL;
}

static const char*
gfx_profile_actions(cmd_parms* cmd, void* p, const char* arg) {
    gfx_profile_config_t* profile = p;
    if (profile == NULL)
return apr_psprintf(cmd->pool, "%s %s", cmd->cmd->name, " error getting profile"); *(const char**)apr_array_push(profile->actions) = apr_pstrdup(cmd->pool, arg);

    return NULL;
}

static void
gfx_register_hooks(apr_pool_t* pool) {
    ap_hook_handler(gfx_main_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

static const
command_rec gfx_cmds[] = {
    AP_INIT_RAW_ARGS("<GfxProfile", gfx_config_profile, NULL, RSRC_CONF,
                         "Container to create profiles"),
AP_INIT_NO_ARGS("</GfxProfile>", NULL, NULL, RSRC_CONF, "Place Holder"),
    AP_INIT_RAW_ARGS("<GfxOrigin", gfx_config_origin, NULL, RSRC_CONF,
                     "Container to create origin hosts"),
    AP_INIT_ITERATE("GfxActions", gfx_profile_actions, NULL, RSRC_CONF,
                    "Defines a list of actions to perform on the image"),
    AP_INIT_TAKE1("GfxRsX", gfx_profile_rsx, NULL, RSRC_CONF,
                  "Specifies a maximum width to resize to"),
    AP_INIT_TAKE1("GfxRsY", gfx_profile_rsy, NULL, RSRC_CONF,
                  "Specifies a maximum height to resize to"),
    AP_INIT_TAKE1("GfxQual", gfx_profile_qual, NULL, RSRC_CONF,
                  "Specifies the quality (if supported by output format)"),
AP_INIT_TAKE1("GfxOutputFormat", gfx_profile_outputformat, NULL, RSRC_CONF,
                  "Specifies the ouput format"),
AP_INIT_TAKE2("GfxOriginMatch", gfx_config_originmatch, NULL, RSRC_CONF,
                  "A regex to declare origins"),
    AP_INIT_TAKE1("GfxOriginHost", gfx_config_originhost, NULL, RSRC_CONF,
                  "Define a host to origin content from"),
    { NULL }
};

module AP_MODULE_DECLARE_DATA gfx_module = {
    STANDARD20_MODULE_STUFF,
    NULL,                        //do I really need this?
    NULL,                        //i'm too lazy to implement merging
    gfx_create_server_config,    //create server config
    NULL,                        //i'm too lazy to implement merging
    gfx_cmds,                    //command table
    gfx_register_hooks           //hooks
};

Reply via email to