1 #include "first.h" 2 3 #include <stdlib.h> 4 #include <string.h> 5 6 #include "plugin.h" 7 8 #include "base.h" 9 #include "log.h" 10 #include "buffer.h" 11 #include "array.h" 12 13 /** 14 * this is a skeleton for a lighttpd plugin 15 * 16 * just replaces every occurrence of 'skeleton' by your plugin name 17 * 18 * e.g. in vim: 19 * 20 * :%s/skeleton/myhandler/ 21 * 22 */ 23 24 25 /* plugin config for all request/connections */ 26 27 typedef struct { 28 array *match; 29 } plugin_config; 30 31 typedef struct { 32 PLUGIN_DATA; 33 plugin_config **config_storage; 34 plugin_config conf; 35 } plugin_data; 36 37 38 #if 0 /* (needed if module keeps state for request) */ 39 40 typedef struct { 41 size_t foo; 42 } handler_ctx; 43 44 static handler_ctx * handler_ctx_init() { 45 handler_ctx * hctx = calloc(1, sizeof(*hctx)); 46 force_assert(hctx); 47 return hctx; 48 } 49 50 static void handler_ctx_free(handler_ctx *hctx) { 51 free(hctx); 52 } 53 54 #endif 55 56 57 /* init the plugin data */ 58 INIT_FUNC(mod_skeleton_init) { 59 return calloc(1, sizeof(plugin_data)); 60 } 61 62 /* destroy the plugin data */ 63 FREE_FUNC(mod_skeleton_free) { 64 plugin_data *p = p_d; 65 UNUSED(srv); 66 if (!p) return HANDLER_GO_ON; 67 if (p->config_storage) { 68 for (size_t i = 0; i < srv->config_context->used; i++) { 69 plugin_config *s = p->config_storage[i]; 70 if (NULL == s) continue; 71 array_free(s->match); 72 free(s); 73 } 74 free(p->config_storage); 75 } 76 free(p); 77 return HANDLER_GO_ON; 78 } 79 80 /* handle plugin config and check values */ 81 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) { 82 plugin_data *p = p_d; 83 size_t i = 0; 84 85 config_values_t cv[] = { 86 { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ 87 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } 88 }; 89 90 if (!p) return HANDLER_ERROR; 91 92 p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *)); 93 force_assert(p->config_storage); 94 95 for (i = 0; i < srv->config_context->used; i++) { 96 data_config const* config = (data_config const*)srv->config_context->data[i]; 97 plugin_config *s = calloc(1, sizeof(plugin_config)); 98 force_assert(s); 99 s->match = array_init(); 100 101 cv[0].destination = s->match; 102 103 p->config_storage[i] = s; 104 105 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { 106 return HANDLER_ERROR; 107 } 108 109 if (!array_is_vlist(s->match)) { 110 log_error_write(srv, __FILE__, __LINE__, "s", 111 "unexpected value for skeleton.array; expected list of \"urlpath\""); 112 return HANDLER_ERROR; 113 } 114 } 115 116 return HANDLER_GO_ON; 117 } 118 119 #define PATCH(x) \ 120 p->conf.x = s->x; 121 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) { 122 plugin_config *s = p->config_storage[0]; 123 124 PATCH(match); 125 126 /* skip the first, the global context */ 127 for (size_t i = 1; i < srv->config_context->used; ++i) { 128 data_config *dc = (data_config *)srv->config_context->data[i]; 129 s = p->config_storage[i]; 130 131 /* condition didn't match */ 132 if (!config_check_cond(srv, con, dc)) continue; 133 134 /* merge config */ 135 for (size_t j = 0; j < dc->value->used; ++j) { 136 data_unset *du = dc->value->data[j]; 137 138 if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) { 139 PATCH(match); 140 } 141 } 142 } 143 144 return 0; 145 } 146 #undef PATCH 147 148 URIHANDLER_FUNC(mod_skeleton_uri_handler) { 149 plugin_data *p = p_d; 150 UNUSED(srv); 151 152 /* determine whether or not module participates in request */ 153 154 if (con->mode != DIRECT) return HANDLER_GO_ON; 155 if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON; 156 157 /* get module config for request */ 158 mod_skeleton_patch_connection(srv, con, p); 159 160 if (NULL == array_match_value_suffix(p->conf.match, con->uri.path)) { 161 return HANDLER_GO_ON; 162 } 163 164 /* module participates in request; business logic here */ 165 166 con->http_status = 403; /* example: reject request with 403 Forbidden */ 167 return HANDLER_FINISHED; 168 } 169 170 /* this function is called at dlopen() time and inits the callbacks */ 171 int mod_skeleton_plugin_init(plugin *p); 172 int mod_skeleton_plugin_init(plugin *p) { 173 p->version = LIGHTTPD_VERSION_ID; 174 p->name = buffer_init_string("skeleton"); 175 p->data = NULL; 176 p->init = mod_skeleton_init; 177 p->cleanup = mod_skeleton_free; 178 p->set_defaults= mod_skeleton_set_defaults; 179 180 p->handle_uri_clean = mod_skeleton_uri_handler; 181 182 return 0; 183 } 184