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 if (!config_check_cond(con, i)) continue; /* condition not matched */ 129 130 data_config *dc = (data_config *)srv->config_context->data[i]; 131 s = p->config_storage[i]; 132 133 /* merge config */ 134 for (size_t j = 0; j < dc->value->used; ++j) { 135 data_unset *du = dc->value->data[j]; 136 137 if (buffer_is_equal_string(&du->key, CONST_STR_LEN("skeleton.array"))) { 138 PATCH(match); 139 } 140 } 141 } 142 143 return 0; 144 } 145 #undef PATCH 146 147 URIHANDLER_FUNC(mod_skeleton_uri_handler) { 148 plugin_data *p = p_d; 149 UNUSED(srv); 150 151 /* determine whether or not module participates in request */ 152 153 if (con->mode != DIRECT) return HANDLER_GO_ON; 154 if (buffer_string_is_empty(con->uri.path)) return HANDLER_GO_ON; 155 156 /* get module config for request */ 157 mod_skeleton_patch_connection(srv, con, p); 158 159 if (NULL == array_match_value_suffix(p->conf.match, con->uri.path)) { 160 return HANDLER_GO_ON; 161 } 162 163 /* module participates in request; business logic here */ 164 165 con->http_status = 403; /* example: reject request with 403 Forbidden */ 166 return HANDLER_FINISHED; 167 } 168 169 /* this function is called at dlopen() time and inits the callbacks */ 170 int mod_skeleton_plugin_init(plugin *p); 171 int mod_skeleton_plugin_init(plugin *p) { 172 p->version = LIGHTTPD_VERSION_ID; 173 p->name = "skeleton"; 174 p->init = mod_skeleton_init; 175 p->cleanup = mod_skeleton_free; 176 p->set_defaults= mod_skeleton_set_defaults; 177 178 p->handle_uri_clean = mod_skeleton_uri_handler; 179 180 return 0; 181 } 182