/*to use *print**/ #include /*to create API*/ #include /*to connect to Postgresql*/ #include /* to use JSON in response body*/ #include /*to use struct pq_confo*/ #include "pqconfo.h" /*to user file2char*/ #include "file2char.h" #define ROUTE_HELLO "/hello" #define ROUTE_ENTITIES "/entities" /** * callback functions declaration */ int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data); int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data); int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data); int main(int argc, char *argv[]) { /*declaration*/ struct _u_instance instance; int frameworkRet, apiPort, apiPortRet, cx; /*TODO How is const defined?*/ const int pqConInfoSize = 100; char pqConInfo[pqConInfoSize]; int pqConfoRet; const struct pq_confo * pqConfo; printf("main() Started...\n"); if (argc != 3) { fprintf(stderr, "Usage: ./main \n"); return 1; } printf("main() argv[1]: %s\n", argv[1]); printf("main() argv[2]: %s\n", argv[2]); /*get Postgresql connection info from config*/ /*TODO Validate argv!*/ pqConfoRet=get_pq_confo(argv[2],&pqConfo); if(pqConfoRet){ fprintf(stderr, "Postgresql connection information are NOT valid\n"); return 2; }else{ fprintf(stdout,"pqConfoRet: %d\n",pqConfoRet); } /*create pq connection info*/ cx = snprintf(pqConInfo,pqConInfoSize,"postgresql://%s:%s@%s:%d/%s",pqConfo->user,pqConfo->secret,pqConfo->host,pqConfo->port,pqConfo->db); if(0>cx && cx>=pqConInfoSize){ fprintf(stderr,"main() error creating pqConInfo\n"); /*free Postgresql connection info*/ pqConfoRet=free_pq_confo(&pqConfo); if(pqConfoRet){ fprintf(stderr, "Postgresql connection information are NOT free\n"); return 3; } return 4; } /*free Postgresql connection info*/ pqConfoRet=free_pq_confo(&pqConfo); if(pqConfoRet){ fprintf(stderr, "Postgresql connection information are NOT free\n"); return 5; } /*store command line argument in variable*/ /*validate user input*/ /*omit injection*/ /*stream:argv*/ apiPortRet = sscanf(argv[1], "%d", &apiPort); /*valid user input:1 successfully filled item*/ if (apiPortRet != 1) { fprintf(stderr, "The argument must be an integer\n"); return 6; } if (apiPort < 0) { fprintf(stderr, "Error passing a negative port\n"); exit(1); } printf("main() port: %d\n", apiPort); /*TODO Is mem leaked when connection to pq failes?*/ if (ulfius_init_instance(&instance, apiPort, NULL, NULL) != U_OK) { printf("main() Error ulfius_init_instance, abort"); return 7; } /*connect to database*/ //TODO This is a synchronous call! Shall we block the rest? PGconn *conn = PQconnectdb(pqConInfo); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); PQfinish(conn); return 8; }else if(PQstatus(conn)==CONNECTION_OK){ printf("main() connected to database\n"); }else{ printf("main() connection status NOT known\n"); } //TODO Why? u_map_put(instance.default_headers, "Access-Control-Allow-Origin", "*"); // Maximum body size sent by the client is 1 Kb instance.max_post_body_size = 1024; // Endpoint list declaration ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_HELLO, NULL, 0, &callback_get_hello, NULL); //user_data: pass pq connection information to callback ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, NULL, 0, &callback_get_entities, (void *)conn); // default_endpoint declaration ulfius_set_default_endpoint(&instance, &callback_default, NULL); // Start the framework // Open an http connection frameworkRet = ulfius_start_framework(&instance); if (frameworkRet == U_OK) { printf("main() Start framework on port %d\n", instance.port); /*wait*/ while(1){ sleep(3600); } } else { printf("main() Error starting framework; frameworkRet: %d\n",frameworkRet); } printf("main() End framework\n"); /*clean up API*/ ulfius_stop_framework(&instance); ulfius_clean_instance(&instance); /*clean up Postgresql connection*/ PQfinish(conn); printf("main() Done.\n"); return 0; } /** * Callback function that put a "Hello World!" string in the response */ int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data) { ulfius_set_string_body_response(response, 200, "Hello World!"); return U_CALLBACK_CONTINUE; } /** * Default callback function called if no endpoint has a match */ int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data) { ulfius_set_string_body_response(response, 404, "Page not found, do what you want"); return U_CALLBACK_CONTINUE; } /** * Callback function for route /entities */ int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data) { /*decalarations*/ PGconn *conn; char *prepStmEntities; PGresult *pqRes; int nbRecords,nbFields; json_t *arrayRecords, *arrayFields, *stringField; printf("callback_get_entities() Started...\n"); conn = (PGconn *)user_data; /*define prepared statement*/ prepStmEntities = "SELECT * FROM entities;"; /*create prepared statement*/ /*conn:connection*/ /*stm:statement*/ /*1:number of passed parameters*/ /*NULL: server figures out parameter type*/ /*paramValues:pointer of an array of strings containing parameters*/ /*NULL:relevant for binary parameters*/ /*NULL:relevant for binary parameters*/ /*0:obtain result in text format*/ pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0); if (PQresultStatus(pqRes) != PGRES_TUPLES_OK) { printf("callback_get_entities() No data retrieved\n"); /*clean up result*/ PQclear(pqRes); //TODO Why this casting? (void)(request); (void)(user_data); ulfius_set_string_body_response(response, 200, "This is the /entities route: Dba error!"); printf("callback_get_entities() Done.\n"); return U_CALLBACK_CONTINUE; } /*evaluate result*/ nbRecords = PQntuples(pqRes); nbFields = PQnfields(pqRes); arrayRecords=json_array(); for(int i=0;i