9 #include "http_vhostdb.h"
14 * virtual host plugin using MySQL for domain to directory lookups
29 plugin_config
**config_storage
;
33 static void mod_vhostdb_dbconf_free (void *vdata
)
35 vhostdb_config
*dbconf
= (vhostdb_config
*)vdata
;
37 mysql_close(dbconf
->dbconn
);
41 static int mod_vhostdb_dbconf_setup (server
*srv
, array
*opts
, void **vdata
)
43 buffer
*sqlquery
= NULL
;
44 const char *dbname
=NULL
, *user
=NULL
, *pass
=NULL
, *host
=NULL
, *sock
=NULL
;
45 unsigned int port
= 0;
47 for (size_t i
= 0; i
< opts
->used
; ++i
) {
48 const data_string
*ds
= (data_string
*)opts
->data
[i
];
49 if (ds
->type
== TYPE_STRING
&& !buffer_string_is_empty(ds
->value
)) {
50 if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("sql"))) {
52 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("dbname"))) {
53 dbname
= ds
->value
->ptr
;
54 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("user"))) {
55 user
= ds
->value
->ptr
;
56 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("password"))) {
57 pass
= ds
->value
->ptr
;
58 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("host"))) {
59 host
= ds
->value
->ptr
;
60 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("port"))) {
61 port
= strtoul(ds
->value
->ptr
, NULL
, 10);
62 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("sock"))) {
63 sock
= ds
->value
->ptr
;
74 * - password, default: empty
75 * - socket, default: mysql default
76 * - hostname, if set overrides socket
77 * - port, default: 3306
80 if (!buffer_string_is_empty(sqlquery
)
81 && dbname
&& *dbname
&& user
&& *user
) {
82 vhostdb_config
*dbconf
;
83 MYSQL
*dbconn
= mysql_init(NULL
);
85 log_error_write(srv
, __FILE__
, __LINE__
, "s",
86 "mysql_init() failed, exiting...");
90 #if MYSQL_VERSION_ID >= 50013
91 /* in mysql versions above 5.0.3 the reconnect flag is off by default */
93 my_bool reconnect
= 1;
94 mysql_options(dbconn
, MYSQL_OPT_RECONNECT
, &reconnect
);
98 /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
99 #if MYSQL_VERSION_ID < 40100
100 #ifndef CLIENT_MULTI_STATEMENTS
101 #define CLIENT_MULTI_STATEMENTS 0
104 if (!mysql_real_connect(dbconn
, host
, user
, pass
, dbname
, port
, sock
,
105 CLIENT_MULTI_STATEMENTS
)) {
106 log_error_write(srv
, __FILE__
, __LINE__
, "s",
107 mysql_error(dbconn
));
112 fd_close_on_exec(dbconn
->net
.fd
);
114 dbconf
= (vhostdb_config
*)calloc(1, sizeof(*dbconf
));
115 dbconf
->dbconn
= dbconn
;
116 dbconf
->sqlquery
= sqlquery
;
123 static void mod_vhostdb_patch_connection (server
*srv
, connection
*con
, plugin_data
*p
);
125 static int mod_vhostdb_mysql_query(server
*srv
, connection
*con
, void *p_d
, buffer
*docroot
)
127 plugin_data
*p
= (plugin_data
*)p_d
;
128 vhostdb_config
*dbconf
;
133 /*(reuse buffer for sql query before generating docroot result)*/
134 buffer
*sqlquery
= docroot
;
135 buffer_string_set_length(sqlquery
, 0); /*(also resets docroot (alias))*/
137 mod_vhostdb_patch_connection(srv
, con
, p
);
138 if (NULL
== p
->conf
.vdata
) return 0; /*(after resetting docroot)*/
139 dbconf
= (vhostdb_config
*)p
->conf
.vdata
;
141 for (char *b
= dbconf
->sqlquery
->ptr
, *d
; *b
; b
= d
+1) {
142 if (NULL
!= (d
= strchr(b
, '?'))) {
143 /* escape the uri.authority */
145 buffer_append_string_len(sqlquery
, b
, (size_t)(d
- b
));
146 buffer_string_prepare_append(sqlquery
, buffer_string_length(con
->uri
.authority
) * 2);
147 len
= mysql_real_escape_string(dbconf
->dbconn
,
148 sqlquery
->ptr
+ buffer_string_length(sqlquery
),
149 CONST_BUF_LEN(con
->uri
.authority
));
150 if ((unsigned long)~0 == len
) return -1;
151 buffer_commit(sqlquery
, len
);
153 d
= dbconf
->sqlquery
->ptr
+ buffer_string_length(dbconf
->sqlquery
);
154 buffer_append_string_len(sqlquery
, b
, (size_t)(d
- b
));
159 if (mysql_real_query(dbconf
->dbconn
, CONST_BUF_LEN(sqlquery
))) {
160 log_error_write(srv
, __FILE__
, __LINE__
, "s",
161 mysql_error(dbconf
->dbconn
));
162 buffer_string_set_length(docroot
, 0); /*(reset buffer; no result)*/
166 buffer_string_set_length(docroot
, 0); /*(reset buffer to store result)*/
168 result
= mysql_store_result(dbconf
->dbconn
);
169 cols
= mysql_num_fields(result
);
170 row
= mysql_fetch_row(result
);
171 if (row
&& cols
>= 1) {
172 buffer_copy_string(docroot
, row
[0]);
173 } /* else no such virtual host */
175 mysql_free_result(result
);
176 #if MYSQL_VERSION_ID >= 40100
177 while (0 == mysql_next_result(dbconf
->dbconn
)) ;
185 INIT_FUNC(mod_vhostdb_init
) {
186 static http_vhostdb_backend_t http_vhostdb_backend_mysql
=
187 { "mysql", mod_vhostdb_mysql_query
, NULL
};
188 plugin_data
*p
= calloc(1, sizeof(*p
));
190 /* register http_vhostdb_backend_mysql */
191 http_vhostdb_backend_mysql
.p_d
= p
;
192 http_vhostdb_backend_set(&http_vhostdb_backend_mysql
);
197 FREE_FUNC(mod_vhostdb_cleanup
) {
198 plugin_data
*p
= p_d
;
199 if (!p
) return HANDLER_GO_ON
;
201 if (p
->config_storage
) {
202 for (size_t i
= 0; i
< srv
->config_context
->used
; i
++) {
203 plugin_config
*s
= p
->config_storage
[i
];
205 mod_vhostdb_dbconf_free(s
->vdata
);
206 array_free(s
->options
);
209 free(p
->config_storage
);
214 return HANDLER_GO_ON
;
217 SETDEFAULTS_FUNC(mod_vhostdb_set_defaults
) {
218 plugin_data
*p
= p_d
;
220 config_values_t cv
[] = {
221 { "vhostdb.mysql", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_CONNECTION
},
222 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
225 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(specific_config
*));
227 for (size_t i
= 0; i
< srv
->config_context
->used
; ++i
) {
228 data_config
const *config
= (data_config
const*)srv
->config_context
->data
[i
];
229 plugin_config
*s
= calloc(1, sizeof(plugin_config
));
231 s
->options
= array_init();
232 cv
[0].destination
= s
->options
;
234 p
->config_storage
[i
] = s
;
236 if (config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
237 return HANDLER_ERROR
;
241 && 0 != mod_vhostdb_dbconf_setup(srv
, s
->options
, &s
->vdata
)) {
242 return HANDLER_ERROR
;
246 return HANDLER_GO_ON
;
251 static void mod_vhostdb_patch_connection (server
*srv
, connection
*con
, plugin_data
*p
)
253 plugin_config
*s
= p
->config_storage
[0];
256 /* skip the first, the global context */
257 for (size_t i
= 1; i
< srv
->config_context
->used
; ++i
) {
258 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
259 s
= p
->config_storage
[i
];
261 /* condition didn't match */
262 if (!config_check_cond(srv
, con
, dc
)) continue;
265 for (size_t j
= 0; j
< dc
->value
->used
; ++j
) {
266 data_unset
*du
= dc
->value
->data
[j
];
268 if (buffer_is_equal_string(du
->key
,CONST_STR_LEN("vhostdb.mysql"))){
276 /* this function is called at dlopen() time and inits the callbacks */
277 int mod_vhostdb_mysql_plugin_init (plugin
*p
);
278 int mod_vhostdb_mysql_plugin_init (plugin
*p
)
280 p
->version
= LIGHTTPD_VERSION_ID
;
281 p
->name
= buffer_init_string("vhostdb_mysql");
283 p
->init
= mod_vhostdb_init
;
284 p
->cleanup
= mod_vhostdb_cleanup
;
285 p
->set_defaults
= mod_vhostdb_set_defaults
;