9 #include "http_vhostdb.h"
14 * virtual host plugin using Postgres 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 PQfinish(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
, *port
=NULL
;
46 for (size_t i
= 0; i
< opts
->used
; ++i
) {
47 const data_string
*ds
= (data_string
*)opts
->data
[i
];
48 if (ds
->type
== TYPE_STRING
) {
49 if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("sql"))) {
51 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("dbname"))) {
52 dbname
= ds
->value
->ptr
;
53 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("user"))) {
54 user
= ds
->value
->ptr
;
55 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("password"))) {
56 pass
= ds
->value
->ptr
;
57 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("host"))) {
58 host
= ds
->value
->ptr
;
59 } else if (buffer_is_equal_caseless_string(ds
->key
, CONST_STR_LEN("port"))) {
60 port
= ds
->value
->ptr
;
68 * - user (unless dbname is a pgsql conninfo URI)
71 * - password, default: empty
73 * - port, default: 5432
76 if (!buffer_string_is_empty(sqlquery
) && NULL
!= dbname
) {
77 vhostdb_config
*dbconf
;
78 PGconn
*dbconn
= PQsetdbLogin(host
,port
,NULL
,NULL
,dbname
,user
,pass
);
80 log_error_write(srv
, __FILE__
, __LINE__
, "s",
81 "PGsetdbLogin() failed, exiting...");
85 if (CONNECTION_OK
!= PQstatus(dbconn
)) {
86 log_error_write(srv
, __FILE__
, __LINE__
, "s",
87 "Failed to login to database, exiting...");
92 /* Postgres sets FD_CLOEXEC on database socket descriptors */
94 dbconf
= (vhostdb_config
*)calloc(1, sizeof(*dbconf
));
95 dbconf
->dbconn
= dbconn
;
96 dbconf
->sqlquery
= sqlquery
;
103 static void mod_vhostdb_patch_connection (server
*srv
, connection
*con
, plugin_data
*p
);
105 static int mod_vhostdb_pgsql_query(server
*srv
, connection
*con
, void *p_d
, buffer
*docroot
)
107 plugin_data
*p
= (plugin_data
*)p_d
;
108 vhostdb_config
*dbconf
;
112 /*(reuse buffer for sql query before generating docroot result)*/
113 buffer
*sqlquery
= docroot
;
114 buffer_string_set_length(sqlquery
, 0); /*(also resets docroot (alias))*/
116 mod_vhostdb_patch_connection(srv
, con
, p
);
117 if (NULL
== p
->conf
.vdata
) return 0; /*(after resetting docroot)*/
118 dbconf
= (vhostdb_config
*)p
->conf
.vdata
;
120 for (char *b
= dbconf
->sqlquery
->ptr
, *d
; *b
; b
= d
+1) {
121 if (NULL
!= (d
= strchr(b
, '?'))) {
122 /* escape the uri.authority */
125 buffer_append_string_len(sqlquery
, b
, (size_t)(d
- b
));
126 buffer_string_prepare_append(sqlquery
, buffer_string_length(con
->uri
.authority
) * 2);
127 len
= PQescapeStringConn(dbconf
->dbconn
,
128 sqlquery
->ptr
+ buffer_string_length(sqlquery
),
129 CONST_BUF_LEN(con
->uri
.authority
), &err
);
130 buffer_commit(sqlquery
, len
);
131 if (0 != err
) return -1;
133 d
= dbconf
->sqlquery
->ptr
+ buffer_string_length(dbconf
->sqlquery
);
134 buffer_append_string_len(sqlquery
, b
, (size_t)(d
- b
));
139 res
= PQexec(dbconf
->dbconn
, sqlquery
->ptr
);
141 buffer_string_set_length(docroot
, 0); /*(reset buffer to store result)*/
143 if (PGRES_TUPLES_OK
!= PQresultStatus(res
)) {
144 log_error_write(srv
, __FILE__
, __LINE__
, "s",
145 PQerrorMessage(dbconf
->dbconn
));
150 cols
= PQnfields(res
);
151 rows
= PQntuples(res
);
152 if (rows
== 1 && cols
>= 1) {
153 buffer_copy_string(docroot
, PQgetvalue(res
, 0, 0));
154 } /* else no such virtual host */
163 INIT_FUNC(mod_vhostdb_init
) {
164 static http_vhostdb_backend_t http_vhostdb_backend_pgsql
=
165 { "pgsql", mod_vhostdb_pgsql_query
, NULL
};
166 plugin_data
*p
= calloc(1, sizeof(*p
));
168 /* register http_vhostdb_backend_pgsql */
169 http_vhostdb_backend_pgsql
.p_d
= p
;
170 http_vhostdb_backend_set(&http_vhostdb_backend_pgsql
);
175 FREE_FUNC(mod_vhostdb_cleanup
) {
176 plugin_data
*p
= p_d
;
177 if (!p
) return HANDLER_GO_ON
;
179 if (p
->config_storage
) {
180 for (size_t i
= 0; i
< srv
->config_context
->used
; i
++) {
181 plugin_config
*s
= p
->config_storage
[i
];
183 mod_vhostdb_dbconf_free(s
->vdata
);
184 array_free(s
->options
);
187 free(p
->config_storage
);
192 return HANDLER_GO_ON
;
195 SETDEFAULTS_FUNC(mod_vhostdb_set_defaults
) {
196 plugin_data
*p
= p_d
;
198 config_values_t cv
[] = {
199 { "vhostdb.pgsql", NULL
, T_CONFIG_ARRAY
, T_CONFIG_SCOPE_CONNECTION
},
200 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
203 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(specific_config
*));
205 for (size_t i
= 0; i
< srv
->config_context
->used
; ++i
) {
206 data_config
const *config
= (data_config
const*)srv
->config_context
->data
[i
];
207 plugin_config
*s
= calloc(1, sizeof(plugin_config
));
209 s
->options
= array_init();
210 cv
[0].destination
= s
->options
;
212 p
->config_storage
[i
] = s
;
214 if (config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
215 return HANDLER_ERROR
;
218 if (!array_is_kvstring(s
->options
)) {
219 log_error_write(srv
, __FILE__
, __LINE__
, "s",
220 "unexpected value for vhostdb.pgsql; expected list of \"option\" => \"value\"");
221 return HANDLER_ERROR
;
225 && 0 != mod_vhostdb_dbconf_setup(srv
, s
->options
, &s
->vdata
)) {
226 return HANDLER_ERROR
;
230 return HANDLER_GO_ON
;
235 static void mod_vhostdb_patch_connection (server
*srv
, connection
*con
, plugin_data
*p
)
237 plugin_config
*s
= p
->config_storage
[0];
240 /* skip the first, the global context */
241 for (size_t i
= 1; i
< srv
->config_context
->used
; ++i
) {
242 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
243 s
= p
->config_storage
[i
];
245 /* condition didn't match */
246 if (!config_check_cond(srv
, con
, dc
)) continue;
249 for (size_t j
= 0; j
< dc
->value
->used
; ++j
) {
250 data_unset
*du
= dc
->value
->data
[j
];
252 if (buffer_is_equal_string(du
->key
,CONST_STR_LEN("vhostdb.pgsql"))){
260 /* this function is called at dlopen() time and inits the callbacks */
261 int mod_vhostdb_pgsql_plugin_init (plugin
*p
);
262 int mod_vhostdb_pgsql_plugin_init (plugin
*p
)
264 p
->version
= LIGHTTPD_VERSION_ID
;
265 p
->name
= buffer_init_string("vhostdb_pgsql");
267 p
->init
= mod_vhostdb_init
;
268 p
->cleanup
= mod_vhostdb_cleanup
;
269 p
->set_defaults
= mod_vhostdb_set_defaults
;