00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00039 #include "pg_uri.h"
00040
00041 #include "../../dprint.h"
00042 #include "../../mem/mem.h"
00043 #include "../../ut.h"
00044 #include "../../lib/srdb2/db_gen.h"
00045
00046 #include <stdlib.h>
00047 #include <string.h>
00048
00049
00054 #define cmpstr(s1, s2, f) \
00055 ((s1)!=(s2)) && ((s1)==0 || (s2)==0 || (f)((s1), (s2))!=0)
00056
00057
00059 static unsigned char pg_uri_cmp(db_uri_t* uri1, db_uri_t* uri2)
00060 {
00061 struct pg_uri* puri1, *puri2;
00062
00063 if (!uri1 || !uri2) return 0;
00064
00065 puri1 = DB_GET_PAYLOAD(uri1);
00066 puri2 = DB_GET_PAYLOAD(uri2);
00067 if (puri1->port != puri2->port) return 0;
00068
00069 if (cmpstr(puri1->username, puri2->username, strcmp)) return 0;
00070 if (cmpstr(puri1->password, puri2->password, strcmp)) return 0;
00071 if (cmpstr(puri1->host, puri2->host, strcasecmp)) return 0;
00072 if (cmpstr(puri1->database, puri2->database, strcmp)) return 0;
00073 return 1;
00074 }
00075
00076
00079 static int dupl_string(char** dst, const char* begin, const char* end)
00080 {
00081 if (*dst) pkg_free(*dst);
00082
00083 *dst = pkg_malloc(end - begin + 1);
00084 if ((*dst) == NULL) {
00085 return -1;
00086 }
00087
00088 memcpy(*dst, begin, end - begin);
00089 (*dst)[end - begin] = '\0';
00090 return 0;
00091 }
00092
00093
00099 static int parse_postgres_uri(struct pg_uri* res, str* uri)
00100 {
00101 #define SHORTEST_DB_URL "//a/b"
00102 #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
00103
00104 enum state {
00105 ST_SLASH1,
00106 ST_SLASH2,
00107 ST_USER_HOST,
00108 ST_PASS_PORT,
00109 ST_HOST,
00110 ST_PORT,
00111 ST_DB
00112 };
00113
00114 enum state st;
00115 int i;
00116 const char* begin;
00117 char* prev_token;
00118
00119 prev_token = 0;
00120
00121 if (!res || !res) {
00122 goto err;
00123 }
00124
00125 if (uri->len < SHORTEST_DB_URL_LEN) {
00126 goto err;
00127 }
00128
00129 st = ST_SLASH1;
00130 begin = uri->s;
00131
00132 for(i = 0; i < uri->len; i++) {
00133 switch(st) {
00134 case ST_SLASH1:
00135 switch(uri->s[i]) {
00136 case '/':
00137 st = ST_SLASH2;
00138 break;
00139
00140 default:
00141 goto err;
00142 }
00143 break;
00144
00145 case ST_SLASH2:
00146 switch(uri->s[i]) {
00147 case '/':
00148 st = ST_USER_HOST;
00149 begin = uri->s + i + 1;
00150 break;
00151
00152 default:
00153 goto err;
00154 }
00155 break;
00156
00157 case ST_USER_HOST:
00158 switch(uri->s[i]) {
00159 case '@':
00160 st = ST_HOST;
00161 if (dupl_string(&res->username, begin, uri->s + i) < 0) goto err;
00162 begin = uri->s + i + 1;
00163 break;
00164
00165 case ':':
00166 st = ST_PASS_PORT;
00167 if (dupl_string(&prev_token, begin, uri->s + i) < 0) goto err;
00168 begin = uri->s + i + 1;
00169 break;
00170
00171 case '/':
00172 if (memchr(uri->s + i + 1, '/', uri->len - i - 1) != NULL)
00173 break;
00174 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
00175 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0)
00176 goto err;
00177 return 0;
00178 }
00179 break;
00180
00181 case ST_PASS_PORT:
00182 switch(uri->s[i]) {
00183 case '@':
00184 st = ST_HOST;
00185 res->username = prev_token;
00186 if (dupl_string(&res->password, begin, uri->s + i) < 0) goto err;
00187 begin = uri->s + i + 1;
00188 break;
00189
00190 case '/':
00191 if (memchr(uri->s + i + 1, '/', uri->len - i - 1) != NULL)
00192 break;
00193 res->host = prev_token;
00194 res->port = str2s(begin, uri->s + i - begin, 0);
00195 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0)
00196 goto err;
00197 return 0;
00198 }
00199 break;
00200
00201 case ST_HOST:
00202 switch(uri->s[i]) {
00203 case ':':
00204 st = ST_PORT;
00205 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
00206 begin = uri->s + i + 1;
00207 break;
00208
00209 case '/':
00210 if (memchr(uri->s + i + 1, '/', uri->len - i - 1) != NULL)
00211 break;
00212 if (dupl_string(&res->host, begin, uri->s + i) < 0) goto err;
00213 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0)
00214 goto err;
00215 return 0;
00216 }
00217 break;
00218
00219 case ST_PORT:
00220 switch(uri->s[i]) {
00221 case '/':
00222 res->port = str2s(begin, uri->s + i - begin, 0);
00223 if (dupl_string(&res->database, uri->s + i + 1, uri->s + uri->len) < 0)
00224 goto err;
00225 return 0;
00226 }
00227 break;
00228
00229 case ST_DB:
00230 break;
00231 }
00232 }
00233
00234 if (st != ST_DB) goto err;
00235 return 0;
00236
00237 err:
00238 if (prev_token) pkg_free(prev_token);
00239 if (res == NULL) return -1;
00240 if (res->username) {
00241 pkg_free(res->username);
00242 res->username = NULL;
00243 }
00244 if (res->password) {
00245 pkg_free(res->password);
00246 res->password = NULL;
00247 }
00248 if (res->host) {
00249 pkg_free(res->host);
00250 res->host = NULL;
00251 }
00252 if (res->database) {
00253 pkg_free(res->database);
00254 res->database = NULL;
00255 }
00256 return -1;
00257 }
00258
00259
00260
00261 static void pg_uri_free(db_uri_t* uri, struct pg_uri* payload)
00262 {
00263 if (payload == NULL) return;
00264 db_drv_free(&payload->drv);
00265 if (payload->username) pkg_free(payload->username);
00266 if (payload->password) pkg_free(payload->password);
00267 if (payload->host) pkg_free(payload->host);
00268 if (payload->database) pkg_free(payload->database);
00269 pkg_free(payload);
00270 }
00271
00272
00273 int pg_uri(db_uri_t* uri)
00274 {
00275 struct pg_uri* puri;
00276
00277 puri = (struct pg_uri*)pkg_malloc(sizeof(struct pg_uri));
00278 if (puri == NULL) {
00279 ERR("postgres: No memory left\n");
00280 goto error;
00281 }
00282 memset(puri, '\0', sizeof(struct pg_uri));
00283 if (db_drv_init(&puri->drv, pg_uri_free) < 0) goto error;
00284 if (parse_postgres_uri(puri, &uri->body) < 0) goto error;
00285
00286 DB_SET_PAYLOAD(uri, puri);
00287 uri->cmp = pg_uri_cmp;
00288 return 0;
00289
00290 error:
00291 if (puri) {
00292 db_drv_free(&puri->drv);
00293 if (puri) pkg_free(puri);
00294 }
00295 return -1;
00296 }
00297