Michael Spiegle wrote:
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.

I don't think it is correct, but I have found a solution for now. Since I can only seem to execute directives inside a container via ap_walk_config(), and it requires a section_vector to be working, I'm (ab)using ap_set_config_vectors() to send a tag to the per-dir config allocator so it knows what type of config to allocate. I have no idea how bad this is, but it appears to be working. Here's the relevant code:

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

ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Entering gfx_config_profile callback");

    //create a new profile for each <GfxProfile> encountered
    gfx_conf = ap_create_per_dir_config(cmd->pool);

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 abusing this by sending <GfxProfile> so the container creator knows what type to give me back gfx_profile_config_t* profile = ap_set_config_vectors(cmd->server, gfx_conf, "<GfxProfile>", &gfx_module, cmd->pool);

    //setup profile
    profile->name = apr_pstrdup(cmd->pool, profile_name);

//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;

    //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_config_origin(cmd_parms* cmd, void* p, const char* arg) {
    const char* endp = ap_strrchr_c(arg, '>');
    const char* args;
    char* origin_name;
    ap_conf_vector_t* gfx_conf;

ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Entering gfx_config_origin callback");

    //create a new origin for each <GfxOrigin> encountered
    gfx_conf = ap_create_per_dir_config(cmd->pool);

const char* err = ap_check_cmd_context(cmd, NOT_IN_LIMIT | NOT_IN_DIRECTORY);

    if (err != NULL)
        return err;

    //get the origin name (argument to <GfxOrigin>)
    //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 origin name");

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

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

    //i think this associates the generic config type with my origin config
gfx_origin_config_t* origin = ap_set_config_vectors(cmd->server, gfx_conf, "<GfxOrigin>", &gfx_module, cmd->pool);

    //setup origin
    origin->name = apr_pstrdup(cmd->pool, origin_name);

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

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

    return NULL;
}


static void*
gfx_create_server_config(apr_pool_t* pool, server_rec* server) {
    gfx_server_config_t* sconf;
sconf = (gfx_server_config_t*)apr_pcalloc(pool, sizeof(gfx_server_config_t));

    sconf->profiles = apr_hash_make(pool);
    sconf->origins = apr_hash_make(pool);

    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Created server config");

    return (void*)sconf;
}

static void*
gfx_create_container_config(apr_pool_t* pool, char* arg) {
    //I'm not really sure why apache calls this function at startup
    //I don't think I need it, so I'm just going to ignore it...
    if (arg == NULL)
        return (void*)NULL;

    //Create a GfxProfile struct on-command and pass it back to the caller
    if (strcmp(arg, "<GfxProfile>") == 0) {
        gfx_profile_config_t* profile;
profile = (gfx_profile_config_t*)apr_pcalloc(pool, sizeof(gfx_profile_config_t));
        profile->name = NULL;
        profile->output_format = IMAGE_TYPE_SRC;
        profile->actions = apr_array_make(pool, 8, sizeof(const char*));
        profile->rsx = 0;
        profile->rsy = 0;
        profile->qual = 0;
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Created <GfxProfile> container");
        return profile;
    }

    //Create a GfxOrigin struct on-command and pass it back to the caller
    if (strcmp(arg, "<GfxOrigin>") == 0) {
        gfx_origin_config_t* origin;
origin = (gfx_origin_config_t*)apr_pcalloc(pool, sizeof(gfx_origin_config_t));
        origin->name = NULL;
        origin->hosts = apr_array_make(pool, 16, sizeof(const char*));
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Created <GfxOrigin> container");
        return origin;
    }

    //default case.  shouldn't ever happen
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Error creating container (%s)", arg);
    return (void*)NULL;
}


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_NO_ARGS("</GfxOrigin>", NULL, NULL, RSRC_CONF, "Place Holder"),
    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,
    gfx_create_container_config, //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