mirror of
https://github.com/lxsang/ant-http
synced 2024-12-25 00:08:21 +01:00
new api
This commit is contained in:
parent
1e2e600bfc
commit
8d2449bd69
@ -53,3 +53,9 @@ autoconf
|
||||
automake --add-missing
|
||||
make distcheck
|
||||
```
|
||||
|
||||
|
||||
### To do
|
||||
- variable size dictionary
|
||||
- refactoring libantd API, remove unused functions
|
||||
- remove static strings, replace it by configurations
|
||||
|
@ -25,7 +25,7 @@ ssl.enable=0
|
||||
; the SSL cert and key files
|
||||
; ssl.cert=fullchain.pem
|
||||
; ssl.key=privkey.pem
|
||||
|
||||
; ssl.cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
|
||||
; This enable some plugins to be initialised at server startup
|
||||
[AUTOSTART]
|
||||
; to start a plugin at server statup use:
|
||||
@ -44,6 +44,33 @@ ssl.enable=0
|
||||
; ^([a-zA-Z][a-zA-Z0-9]*)\.[a-zA-Z0-9]+\..*$ = /<1><url>?<query>
|
||||
; Sytax: [regular expression on the original request]=[new request rule]
|
||||
|
||||
[MIMES]
|
||||
image/bmp=bmp
|
||||
image/jpeg=jpg,jpeg
|
||||
text/css=css
|
||||
text/markdown=md
|
||||
text/csv=csv
|
||||
application/pdf=pdf
|
||||
image/gif=gif
|
||||
text/html=html,htm,chtml
|
||||
application/json=json
|
||||
application/javascript=js
|
||||
image/png=png
|
||||
image/x-portable-pixmap=ppm
|
||||
application/x-rar-compressed=rar
|
||||
image/tiff=tiff
|
||||
application/x-tar=tar
|
||||
text/plain=txt
|
||||
application/x-font-ttf=ttf
|
||||
application/xhtml+xml=xhtml
|
||||
application/xml=xml
|
||||
application/zip=zip
|
||||
image/svg+xml=svg
|
||||
application/vnd.ms-fontobject=eot
|
||||
application/x-font-woff=woff,woff2
|
||||
application/x-font-otf=otf
|
||||
audio/mpeg=mp3,mpeg
|
||||
|
||||
[FILEHANDLER]
|
||||
; specify a plugin for handling
|
||||
; a file type
|
||||
|
BIN
dist/antd-1.0.4b.tar.gz
vendored
BIN
dist/antd-1.0.4b.tar.gz
vendored
Binary file not shown.
122
http_server.c
122
http_server.c
@ -1,4 +1,26 @@
|
||||
#include "http_server.h"
|
||||
|
||||
//define all basic mime here
|
||||
static mime_t _mimes[] = {
|
||||
{"image/bmp","bmp"},
|
||||
{"image/jpeg","jpg,jpeg"},
|
||||
{"text/css","css"},
|
||||
{"text/markdown","md"},
|
||||
{"text/csv","csv"},
|
||||
{"application/pdf","pdf"},
|
||||
{"image/gif","gif"},
|
||||
{"text/html","html"},
|
||||
{"application/json","json"},
|
||||
{"application/javascript","js"},
|
||||
{"image/png","png"},
|
||||
{"text/plain","txt"},
|
||||
{"application/xhtml+xml","xhtml"},
|
||||
{"application/xml","xml"},
|
||||
{"image/svg+xml","svg"},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
|
||||
static pthread_mutex_t server_mux = PTHREAD_MUTEX_INITIALIZER;
|
||||
config_t server_config;
|
||||
config_t *config()
|
||||
@ -64,6 +86,8 @@ void destroy_config()
|
||||
free(server_config.htdocs);
|
||||
if (server_config.tmpdir)
|
||||
free(server_config.tmpdir);
|
||||
if(server_config.ssl_cipher)
|
||||
free(server_config.ssl_cipher);
|
||||
if(server_config.errorfp)
|
||||
{
|
||||
fclose(server_config.errorfp);
|
||||
@ -74,6 +98,8 @@ void destroy_config()
|
||||
fclose(server_config.logfp);
|
||||
}
|
||||
#endif
|
||||
if(server_config.mimes)
|
||||
freedict(server_config.mimes);
|
||||
LOG("Unclosed connection: %d", server_config.connection);
|
||||
}
|
||||
|
||||
@ -141,6 +167,10 @@ static int config_handler(void *conf, const char *section, const char *name,
|
||||
{
|
||||
pconfig->sslkey = strdup(value);
|
||||
}
|
||||
else if(MATCH("SERVER","ssl.cipher"))
|
||||
{
|
||||
pconfig->ssl_cipher = strdup(value);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(section, "RULES") == 0)
|
||||
{
|
||||
@ -157,6 +187,10 @@ static int config_handler(void *conf, const char *section, const char *name,
|
||||
// auto start plugin
|
||||
plugin_load((char *)value);
|
||||
}
|
||||
else if(strcmp(section, "MIMES") == 0)
|
||||
{
|
||||
dput(pconfig->mimes,name,strdup(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* unknown section/name, error */
|
||||
@ -193,11 +227,18 @@ void load_config(const char *file)
|
||||
server_config.handlers = dict();
|
||||
server_config.maxcon = 1000;
|
||||
server_config.connection = 0;
|
||||
#ifdef USE_OPENSSL
|
||||
server_config.errorfp = NULL;
|
||||
server_config.logfp = NULL;
|
||||
server_config.mimes = dict();
|
||||
server_config.usessl = 0;
|
||||
server_config.sslcert = "cert.pem";
|
||||
server_config.sslkey = "key.pem";
|
||||
#endif
|
||||
server_config.ssl_cipher = NULL;
|
||||
// put it default mimes
|
||||
for(int i = 0; _mimes[i].type != NULL; i++)
|
||||
{
|
||||
dput(server_config.mimes,_mimes[i].type, strdup(_mimes[i].ext));
|
||||
}
|
||||
if (ini_parse(file, config_handler, &server_config) < 0)
|
||||
{
|
||||
ERROR("Can't load '%s'. Used defaut configuration", file);
|
||||
@ -209,9 +250,13 @@ void load_config(const char *file)
|
||||
LOG("SSL enable %d", server_config.usessl);
|
||||
LOG("SSL cert %s", server_config.sslcert);
|
||||
LOG("SSL key %s", server_config.sslkey);
|
||||
if(!server_config.ssl_cipher)
|
||||
LOG("SSL Cipher suite: %s", "HIGH");
|
||||
else
|
||||
LOG("SSL Cipher suite: %s", server_config.ssl_cipher);
|
||||
#endif
|
||||
}
|
||||
init_file_system();
|
||||
LOG("%d mimes entries found", server_config.mimes->size);
|
||||
}
|
||||
|
||||
void *accept_request(void *data)
|
||||
@ -238,7 +283,7 @@ void *accept_request(void *data)
|
||||
int sel = select(client->sock + 1, &read_flags, &write_flags, (fd_set *)0, &timeout);
|
||||
if (sel == -1)
|
||||
{
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 400, "Bad request");
|
||||
return task;
|
||||
}
|
||||
if (sel == 0 || (!FD_ISSET(client->sock, &read_flags) && !FD_ISSET(client->sock, &write_flags)))
|
||||
@ -285,7 +330,7 @@ void *accept_request(void *data)
|
||||
ERROR("Error performing SSL handshake %d %d %lu", stat, ret, ERR_get_error());
|
||||
//server_config.connection++;
|
||||
ERR_print_errors_fp(stderr);
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 400, "Invalid SSL request");
|
||||
return task;
|
||||
}
|
||||
}
|
||||
@ -320,7 +365,7 @@ void *accept_request(void *data)
|
||||
if (!line)
|
||||
{
|
||||
LOG("No method found");
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 405, "No method found");
|
||||
return task;
|
||||
}
|
||||
trim(token, ' ');
|
||||
@ -331,7 +376,7 @@ void *accept_request(void *data)
|
||||
if (!line)
|
||||
{
|
||||
LOG("No request found");
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 400, "Bad request");
|
||||
return task;
|
||||
}
|
||||
trim(token, ' ');
|
||||
@ -388,7 +433,7 @@ void *resolve_request(void *data)
|
||||
strcat(path, "/index.html");
|
||||
if (stat(path, &st) == -1)
|
||||
{
|
||||
association it;
|
||||
chain_t it;
|
||||
for_each_assoc(it, server_config.handlers)
|
||||
{
|
||||
newurl = __s("%s/index.%s", url, it->key);
|
||||
@ -408,7 +453,7 @@ void *resolve_request(void *data)
|
||||
}
|
||||
if (!newurl)
|
||||
{
|
||||
notfound(rq->client);
|
||||
antd_error(rq->client, 404, "Resource Not Found");
|
||||
return task;
|
||||
}
|
||||
//if(url) free(url); this is freed in the dput function
|
||||
@ -439,7 +484,7 @@ void *resolve_request(void *data)
|
||||
return execute_plugin(rq, h);
|
||||
}
|
||||
else
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 403, "Access forbidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -553,15 +598,21 @@ void *serve_file(void *data)
|
||||
int s = stat(path, &st);
|
||||
if(s == -1)
|
||||
{
|
||||
notfound(rq->client);
|
||||
antd_error(rq->client, 404, "File not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = (int)st.st_size;
|
||||
set_status(rq->client,200,"OK");
|
||||
__t(rq->client,"Content-Type: %s",mime_type);
|
||||
__t(rq->client,"Content-Length: %d",size);
|
||||
response(rq->client,"");
|
||||
char ibuf[20];
|
||||
snprintf (ibuf, sizeof(ibuf), "%d",size);
|
||||
antd_response_header_t rhd;
|
||||
rhd.cookie = NULL;
|
||||
rhd.status = 200;
|
||||
rhd.header = dict();
|
||||
dput(rhd.header, "Content-Type", strdup(mime_type));
|
||||
dput(rhd.header, "Content-Length", strdup(ibuf));
|
||||
antd_send_header(rq->client, &rhd);
|
||||
|
||||
__f(rq->client, path);
|
||||
}
|
||||
|
||||
@ -637,15 +688,15 @@ char *apply_rules(const char *host, char *url)
|
||||
void *decode_request_header(void *data)
|
||||
{
|
||||
antd_request_t *rq = (antd_request_t *)data;
|
||||
dictionary cookie = NULL;
|
||||
dictionary_t cookie = NULL;
|
||||
char *line;
|
||||
char *token;
|
||||
char *query = NULL;
|
||||
char *host = NULL;
|
||||
char buf[2 * BUFFLEN];
|
||||
char *url = (char *)dvalue(rq->request, "REQUEST_QUERY");
|
||||
dictionary xheader = dict();
|
||||
dictionary request = dict();
|
||||
dictionary_t xheader = dict();
|
||||
dictionary_t request = dict();
|
||||
dput(rq->request, "REQUEST_HEADER", xheader);
|
||||
dput(rq->request, "REQUEST_DATA", request);
|
||||
// first real all header
|
||||
@ -700,7 +751,7 @@ void *decode_request_header(void *data)
|
||||
void *decode_request(void *data)
|
||||
{
|
||||
antd_request_t *rq = (antd_request_t *)data;
|
||||
dictionary headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||
dictionary_t headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||
int ws = 0;
|
||||
char *ws_key = NULL;
|
||||
char *method = NULL;
|
||||
@ -736,7 +787,7 @@ void *decode_request(void *data)
|
||||
}
|
||||
else
|
||||
{
|
||||
unimplemented(rq->client);
|
||||
antd_error(rq->client,501, "Request Method Not Implemented");
|
||||
return task;
|
||||
}
|
||||
}
|
||||
@ -744,8 +795,8 @@ void *decode_request(void *data)
|
||||
void *decode_post_request(void *data)
|
||||
{
|
||||
antd_request_t *rq = (antd_request_t *)data;
|
||||
dictionary request = dvalue(rq->request, "REQUEST_DATA");
|
||||
dictionary headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||
dictionary_t request = dvalue(rq->request, "REQUEST_DATA");
|
||||
dictionary_t headers = dvalue(rq->request, "REQUEST_HEADER");
|
||||
char *ctype = NULL;
|
||||
int clen = -1;
|
||||
char *tmp;
|
||||
@ -762,8 +813,7 @@ void *decode_post_request(void *data)
|
||||
return task;
|
||||
if (ctype == NULL || clen == -1)
|
||||
{
|
||||
LOG("Bad request");
|
||||
badrequest(rq->client);
|
||||
antd_error(rq->client, 400, "Bad Request, missing content description");
|
||||
return task;
|
||||
}
|
||||
// decide what to do with the data
|
||||
@ -787,8 +837,11 @@ void *decode_post_request(void *data)
|
||||
key++;
|
||||
else
|
||||
key = ctype;
|
||||
dput(request, key, strdup(pquery));
|
||||
free(pquery);
|
||||
if(pquery)
|
||||
{
|
||||
dput(request, key, strdup(pquery));
|
||||
free(pquery);
|
||||
}
|
||||
}
|
||||
return task;
|
||||
}
|
||||
@ -837,7 +890,7 @@ void ws_confirm_request(void *client, const char *key)
|
||||
* @param client The client socket
|
||||
* @return The Dictionary socket or NULL
|
||||
*/
|
||||
dictionary decode_cookie(const char *line)
|
||||
dictionary_t decode_cookie(const char *line)
|
||||
{
|
||||
char *token, *token1;
|
||||
char *cpstr = strdup(line);
|
||||
@ -846,7 +899,7 @@ dictionary decode_cookie(const char *line)
|
||||
trim(cpstr, '\n');
|
||||
trim(cpstr, '\r');
|
||||
|
||||
dictionary dic = NULL;
|
||||
dictionary_t dic = NULL;
|
||||
while ((token = strsep(&cpstr, ";")))
|
||||
{
|
||||
trim(token, ' ');
|
||||
@ -915,7 +968,7 @@ void *decode_multi_part_request_data(void *data)
|
||||
antd_task_t *task = antd_create_task(NULL, (void *)rq, NULL, rq->client->last_io);
|
||||
task->priority++;
|
||||
char *boundary = (char *)dvalue(rq->request, "MULTI_PART_BOUNDARY");
|
||||
dictionary dic = (dictionary)dvalue(rq->request, "REQUEST_DATA");
|
||||
dictionary_t dic = (dictionary_t)dvalue(rq->request, "REQUEST_DATA");
|
||||
char *boundend = __s("%s--", boundary);
|
||||
// search for content disposition:
|
||||
while ((line = read_line(rq->client)) &&
|
||||
@ -1063,7 +1116,7 @@ void *decode_multi_part_request_data(void *data)
|
||||
* @param query : the query string
|
||||
* @return a dictionary of key-value
|
||||
*/
|
||||
void decode_url_request(const char *query, dictionary dic)
|
||||
void decode_url_request(const char *query, dictionary_t dic)
|
||||
{
|
||||
if (query == NULL)
|
||||
return;
|
||||
@ -1156,7 +1209,7 @@ void *execute_plugin(void *data, const char *pname)
|
||||
pthread_mutex_unlock(&server_mux);
|
||||
if (plugin == NULL)
|
||||
{
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 503, "Requested service not found");
|
||||
return task;
|
||||
}
|
||||
}
|
||||
@ -1171,7 +1224,7 @@ void *execute_plugin(void *data, const char *pname)
|
||||
if ((error = dlerror()) != NULL)
|
||||
{
|
||||
ERROR("Problem when finding %s method from %s : %s", PLUGIN_HANDLER, pname, error);
|
||||
unknow(rq->client);
|
||||
antd_error(rq->client, 503, "Requested service not found");
|
||||
return task;
|
||||
}
|
||||
// check if we need the raw data or not
|
||||
@ -1195,3 +1248,8 @@ int usessl()
|
||||
return server_config.usessl;
|
||||
}
|
||||
#endif
|
||||
|
||||
dictionary_t mimes_list()
|
||||
{
|
||||
return server_config.mimes;
|
||||
}
|
@ -35,14 +35,14 @@ void badrequest(void*);
|
||||
int rule_check(const char*, const char*, const char* , const char* , const char* , char*);
|
||||
void ws_confirm_request(void*, const char*);
|
||||
char* post_url_decode(void* client,int len);
|
||||
void decode_url_request(const char* query, dictionary);
|
||||
void decode_url_request(const char* query, dictionary_t);
|
||||
void* decode_request_header(void* data);
|
||||
void* decode_request(void* data);
|
||||
void* decode_post_request(void* data);
|
||||
void* resolve_request(void* data);
|
||||
void* decode_multi_part_request(void*,const char*);
|
||||
void* decode_multi_part_request_data(void* data);
|
||||
dictionary decode_cookie(const char*);
|
||||
dictionary_t decode_cookie(const char*);
|
||||
char* post_data_decode(void*,int);
|
||||
void set_nonblock(int);
|
||||
void* execute_plugin(void* data, const char *path);
|
||||
|
4
httpd.c
4
httpd.c
@ -10,8 +10,8 @@ static int server_sock = -1;
|
||||
|
||||
// define the cipher suit used
|
||||
// dirty hack, this should be configured by the configuration file
|
||||
#define CIPHER_SUIT "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
|
||||
|
||||
// #define CIPHER_SUIT "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
|
||||
#define CIPHER_SUIT "HIGH"
|
||||
|
||||
static int ssl_session_ctx_id = 1;
|
||||
SSL_CTX *ctx;
|
||||
|
@ -22,19 +22,33 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include "dictionary.h"
|
||||
#include "utils.h"
|
||||
|
||||
dictionary dict()
|
||||
dictionary_t dict()
|
||||
{
|
||||
dictionary d = (dictionary)malloc(DHASHSIZE*sizeof(association));
|
||||
for(int i=0; i< DHASHSIZE;i++)
|
||||
d[i] = NULL;
|
||||
return dict_n(DHASHSIZE);
|
||||
}
|
||||
dictionary_t dict_n(unsigned int size)
|
||||
{
|
||||
dictionary_t d = (dictionary_t) malloc(sizeof(struct __dict));
|
||||
if(!d) return NULL;
|
||||
d->map= (map_t)malloc(size*sizeof(chain_t));
|
||||
if(!d->map)
|
||||
{
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
d->cap = size;
|
||||
d->size = 0;
|
||||
for(unsigned int i=0; i< size;i++)
|
||||
d->map[i] = NULL;
|
||||
return d;
|
||||
}
|
||||
association dlookup(dictionary dic,const char* key)
|
||||
chain_t dlookup(dictionary_t dic,const char* key)
|
||||
{
|
||||
association np;
|
||||
if(dic == NULL) return NULL;
|
||||
for (np = dic[hash(key,DHASHSIZE)]; np != NULL; np = np->next)
|
||||
chain_t np;
|
||||
if(dic->map == NULL) return NULL;
|
||||
for (np = dic->map[hash(key,dic->cap)]; np != NULL; np = np->next)
|
||||
{
|
||||
if(!np || !np->key)
|
||||
{
|
||||
@ -45,26 +59,27 @@ association dlookup(dictionary dic,const char* key)
|
||||
}
|
||||
return NULL; /* not found */
|
||||
}
|
||||
association __put_el_with_key(dictionary dic, const char* key)
|
||||
chain_t __put_el_with_key(dictionary_t dic, const char* key)
|
||||
{
|
||||
association np;
|
||||
chain_t np;
|
||||
unsigned hashval;
|
||||
if(dic == NULL) return NULL;
|
||||
if(dic->map == NULL) return NULL;
|
||||
if ((np = dlookup(dic,key)) == NULL) { /* not found */
|
||||
np = (association) malloc(sizeof(*np));
|
||||
np->value = NULL;
|
||||
np = (chain_t) malloc(sizeof(*np));
|
||||
if (np == NULL || (np->key = strdup(key)) == NULL)
|
||||
return NULL;
|
||||
hashval = hash(key, DHASHSIZE);
|
||||
np->next = dic[hashval];
|
||||
dic[hashval] = np;
|
||||
np->value = NULL;
|
||||
hashval = hash(key, dic->cap);
|
||||
np->next = dic->map[hashval];
|
||||
dic->map[hashval] = np;
|
||||
dic->size++;
|
||||
}
|
||||
// found
|
||||
return np;
|
||||
}
|
||||
association dput(dictionary dic,const char* key, void* value)
|
||||
chain_t dput(dictionary_t dic,const char* key, void* value)
|
||||
{
|
||||
association np = __put_el_with_key(dic,key);
|
||||
chain_t np = __put_el_with_key(dic,key);
|
||||
if(np == NULL)
|
||||
{
|
||||
if(value) free(value);
|
||||
@ -74,38 +89,43 @@ association dput(dictionary dic,const char* key, void* value)
|
||||
np->value = value;
|
||||
return np;
|
||||
}
|
||||
int dremove(dictionary dic, const char* key)
|
||||
chain_t dremove(dictionary_t dic, const char* key)
|
||||
{
|
||||
if(dic == NULL) return 0;
|
||||
int hashval = hash(key, DHASHSIZE);
|
||||
association np = dic[hashval];
|
||||
if(dic->map == NULL) return 0;
|
||||
int hashval = hash(key, dic->cap);
|
||||
chain_t np = dic->map[hashval];
|
||||
if(np!=NULL && strcmp(key,np->key)==0)
|
||||
{
|
||||
dic[hashval] = np->next;
|
||||
return 1;
|
||||
dic->size--;
|
||||
dic->map[hashval] = np->next;
|
||||
np->next = NULL;
|
||||
return np;
|
||||
}
|
||||
for (np= dic[hashval]; np != NULL; np = np->next)
|
||||
for (np= dic->map[hashval]; np != NULL; np = np->next)
|
||||
if (np->next!=NULL&&strcmp(key, np->next->key) == 0)
|
||||
{
|
||||
chain_t ret = np->next;
|
||||
np->next = np->next->next; /* found */
|
||||
return 1;
|
||||
dic->size--;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
return 0; /* not found */
|
||||
return NULL; /* not found */
|
||||
|
||||
}
|
||||
void* dvalue(dictionary dic, const char* key)
|
||||
void* dvalue(dictionary_t dic, const char* key)
|
||||
{
|
||||
association as = dlookup(dic,key);
|
||||
chain_t as = dlookup(dic,key);
|
||||
if(as == NULL) return NULL;
|
||||
return as->value;
|
||||
}
|
||||
|
||||
void free_association(association * asoc)
|
||||
void free_association(chain_t * asoc)
|
||||
{
|
||||
|
||||
while( (*asoc) != NULL )
|
||||
{
|
||||
association a = *asoc;
|
||||
chain_t a = *asoc;
|
||||
(* asoc) = (*asoc) ->next;
|
||||
|
||||
if(a->key)
|
||||
@ -118,11 +138,11 @@ void free_association(association * asoc)
|
||||
|
||||
}
|
||||
|
||||
void freedict(dictionary dic){
|
||||
for(int i = 0; i < DHASHSIZE; i++)
|
||||
free_association(&(dic[i]));
|
||||
void freedict(dictionary_t dic){
|
||||
for(unsigned int i = 0; i < dic->cap; i++)
|
||||
free_association(&(dic->map[i]));
|
||||
free(dic->map);
|
||||
free(dic);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,10 +24,10 @@ THE SOFTWARE.
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "utils.h"
|
||||
#define DHASHSIZE 16
|
||||
#define for_each_assoc(assoc, dic) \
|
||||
for(int i = 0; i < DHASHSIZE; i++) \
|
||||
for(assoc = dic[i];assoc!= NULL; assoc = assoc->next)
|
||||
for(unsigned int i = 0; i < dic->cap; i++) \
|
||||
for(assoc = dic->map[i];assoc!= NULL; assoc = assoc->next)
|
||||
|
||||
/**
|
||||
* Dictionary for header
|
||||
@ -37,14 +37,22 @@ typedef struct __assoc{
|
||||
char *key;
|
||||
void* value;
|
||||
//char *value;
|
||||
} * association;
|
||||
} * chain_t;
|
||||
|
||||
typedef association* dictionary;
|
||||
dictionary dict();
|
||||
association dlookup(dictionary,const char*);
|
||||
void* dvalue(dictionary, const char*);
|
||||
association dput(dictionary,const char*, void*);
|
||||
int dremove(dictionary, const char*);
|
||||
void freedict(dictionary);
|
||||
typedef chain_t* map_t;
|
||||
|
||||
typedef struct __dict{
|
||||
unsigned int cap;
|
||||
map_t map;
|
||||
unsigned int size;
|
||||
}* dictionary_t;
|
||||
|
||||
dictionary_t dict();
|
||||
dictionary_t dict_n(unsigned int n);
|
||||
chain_t dlookup(dictionary_t,const char*);
|
||||
void* dvalue(dictionary_t, const char*);
|
||||
chain_t dput(dictionary_t,const char*, void*);
|
||||
chain_t dremove(dictionary_t, const char*);
|
||||
void freedict(dictionary_t);
|
||||
|
||||
#endif
|
330
lib/handle.c
330
lib/handle.c
@ -1,4 +1,5 @@
|
||||
#include "handle.h"
|
||||
#define HTML_TPL "<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><h2>%s</h2></BODY></HTML>"
|
||||
#ifdef USE_OPENSSL
|
||||
int usessl()
|
||||
{
|
||||
@ -18,36 +19,110 @@ void server_log(const char* fmt, ...)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
void set_status(void* client,int code,const char* msg)
|
||||
|
||||
const char* get_status_str(int stat)
|
||||
{
|
||||
char *s = __s("HTTP/1.1 %d %s", code, msg);
|
||||
response(client, s);
|
||||
free(s);
|
||||
s = __s("Server: %s ", SERVER_NAME);
|
||||
response(client, s);
|
||||
free(s);
|
||||
}
|
||||
void redirect(void* client,const char*path)
|
||||
{
|
||||
__t(client,"<html><head><meta http-equiv=\"refresh\" content=\"0; url=%s\"></head><body></body></html>",path);
|
||||
switch(stat)
|
||||
{
|
||||
case 100: return "Continue";
|
||||
case 101: return "Switching Protocols";
|
||||
case 102: return "Processing";
|
||||
case 103: return "Early Hints";
|
||||
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 202: return "Accepted";
|
||||
case 203: return "Non-Authoritative Information";
|
||||
case 204: return "No Content";
|
||||
case 205: return "Reset Content";
|
||||
case 206: return "Partial Content";
|
||||
case 207: return "Multi-Status";
|
||||
case 208: return "Already Reported";
|
||||
case 226: return "IM Used";
|
||||
|
||||
case 300: return "Multiple Choices";
|
||||
case 301: return "Moved Permanently";
|
||||
case 302: return "Found";
|
||||
case 303: return "See Other";
|
||||
case 304: return "Not Modified";
|
||||
case 305: return "Use Proxy";
|
||||
case 306: return "Switch Proxy";
|
||||
case 307: return "Temporary Redirect";
|
||||
case 308: return "Permanent Redirect";
|
||||
|
||||
case 400: return "Bad Request";
|
||||
case 401: return "Unauthorized";
|
||||
case 402: return "Payment Required";
|
||||
case 403: return "Forbidden";
|
||||
case 404: return "Not Found";
|
||||
case 405: return "Method Not Allowed";
|
||||
case 406: return "Not Acceptable";
|
||||
case 407: return "Proxy Authentication Required";
|
||||
case 408: return "Request Timeout";
|
||||
case 409: return "Conflict";
|
||||
case 410: return "Gone";
|
||||
case 411: return "Length Required";
|
||||
case 412: return "Precondition Failed";
|
||||
case 413: return "Payload Too Large";
|
||||
case 414: return "URI Too Long";
|
||||
case 415: return "Unsupported Media Type";
|
||||
case 416: return "Range Not Satisfiable";
|
||||
case 417: return "Expectation Failed";
|
||||
case 421: return "Misdirected Request";
|
||||
case 422: return "Unprocessable Entity";
|
||||
case 423: return "Locked";
|
||||
case 424: return "Failed Dependency";
|
||||
case 425: return "Too Early";
|
||||
case 426: return "Upgrade Required";
|
||||
case 428: return "Precondition Required";
|
||||
case 429: return "Too Many Requests";
|
||||
case 431: return "Request Header Fields Too Large";
|
||||
case 451: return "Unavailable For Legal Reasons";
|
||||
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 505: return "HTTP Version Not Supported";
|
||||
case 506: return "Variant Also Negotiates";
|
||||
case 507: return "Insufficient Storage";
|
||||
case 508: return "Loop Detected";
|
||||
case 510: return "Not Extended";
|
||||
case 511: return "Network Authentication Required";
|
||||
default: return "Unofficial Status";
|
||||
}
|
||||
}
|
||||
|
||||
void html(void* client)
|
||||
void antd_send_header(void* client, antd_response_header_t* res)
|
||||
{
|
||||
ctype(client,"text/html; charset=utf-8");
|
||||
}
|
||||
void text(void* client)
|
||||
{
|
||||
ctype(client,"text/plain; charset=utf-8");
|
||||
}
|
||||
void json(void* client)
|
||||
{
|
||||
ctype(client,"application/json");
|
||||
}
|
||||
void textstream(void* client)
|
||||
{
|
||||
ctype(client, "text/event-stream");
|
||||
if(!res->header)
|
||||
res->header = dict();
|
||||
dput(res->header,"Server", strdup(SERVER_NAME));
|
||||
const char* stat_str = get_status_str(res->status);
|
||||
__t(client, "HTTP/1.1 %d %s", res->status, stat_str);
|
||||
chain_t it;
|
||||
for_each_assoc(it, res->header)
|
||||
{
|
||||
__t(client,"%s: %s", it->key, (const char*)it->value);
|
||||
}
|
||||
// send out cookie
|
||||
if(res->cookie)
|
||||
{
|
||||
int size = list_size(res->cookie);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
__t(client,"Set-Cookie: %s", list_at(res->cookie, i)->value.s);
|
||||
}
|
||||
list_free(&res->cookie);
|
||||
res->cookie = NULL;
|
||||
}
|
||||
__b(client, (unsigned char*)"\r\n", 2);
|
||||
freedict(res->header);
|
||||
res->header = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
void octstream(void* client, char* name)
|
||||
{
|
||||
set_status(client,200,"OK");
|
||||
@ -55,38 +130,15 @@ void octstream(void* client, char* name)
|
||||
__t(client,"Content-Disposition: attachment; filename=\"%s\"", name);
|
||||
response(client,"");
|
||||
//Content-Disposition: attachment; filename="fname.ext"
|
||||
}
|
||||
void jpeg(void* client)
|
||||
{
|
||||
ctype(client,"image/jpeg");
|
||||
}
|
||||
void ctype(void* client, const char* type)
|
||||
{
|
||||
set_status(client,200,"OK");
|
||||
__t(client,"Content-Type: %s",type);
|
||||
response(client,"");
|
||||
}
|
||||
}*/
|
||||
|
||||
int response(void* client, const char* data)
|
||||
{
|
||||
char buf[BUFFLEN+3];
|
||||
strcpy(buf, data);
|
||||
int nbytes;
|
||||
int size = strlen(data);
|
||||
buf[size] = '\r';
|
||||
buf[size+1] = '\n';
|
||||
buf[size+2] = '\0';
|
||||
|
||||
nbytes = antd_send(client, buf, strlen(buf));
|
||||
return (nbytes ==-1?0:1);
|
||||
}
|
||||
int antd_send(void *src, const void* data, int len)
|
||||
{
|
||||
if(!src || !data) return -1;
|
||||
int written;
|
||||
antd_client_t * source = (antd_client_t *) src;
|
||||
char* ptr;
|
||||
int writelen;
|
||||
int writelen = 0;
|
||||
int count;
|
||||
#ifdef USE_OPENSSL
|
||||
if(usessl())
|
||||
@ -200,7 +252,9 @@ int antd_send(void *src, const void* data, int len)
|
||||
}
|
||||
else if(count == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
{
|
||||
return written;
|
||||
ERROR("Error while writing: %s", strerror(errno));
|
||||
break;
|
||||
//return written;
|
||||
}
|
||||
}
|
||||
#ifdef USE_OPENSSL
|
||||
@ -351,6 +405,7 @@ int antd_recv(void *src, void* data, int len)
|
||||
}
|
||||
else if(errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
{
|
||||
ERROR("Error while writing: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -408,66 +463,27 @@ int antd_close(void* src)
|
||||
src = NULL;
|
||||
return ret;
|
||||
}
|
||||
int __ti(void* client,int data)
|
||||
{
|
||||
char str[15];
|
||||
sprintf(str, "%d", data);
|
||||
return response(client,str);
|
||||
}
|
||||
|
||||
int __t(void* client, const char* fstring,...)
|
||||
{
|
||||
int nbytes;
|
||||
int dlen;
|
||||
int sent = 0;
|
||||
int buflen = 0;
|
||||
int st;
|
||||
va_list arguments;
|
||||
char * data;
|
||||
char* chunk;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
dlen = vsnprintf(0,0,fstring,arguments)+1;
|
||||
va_end(arguments);
|
||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
||||
{
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(data, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(dlen < BUFFLEN)
|
||||
{
|
||||
int ret = response(client,data);
|
||||
free(data);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(sent < dlen - 1)
|
||||
{
|
||||
if(dlen - sent > BUFFLEN)
|
||||
buflen = BUFFLEN;
|
||||
else
|
||||
buflen = dlen - sent - 1;
|
||||
//LOG("BUFFLEN %d\n",buflen);
|
||||
chunk = (char*) malloc((buflen)*sizeof(char));
|
||||
memcpy(chunk,data+sent,buflen);
|
||||
//chunk[buflen-1] = '\0';
|
||||
//response(client,chunk);
|
||||
sent += buflen;
|
||||
nbytes = antd_send(client, chunk, buflen);
|
||||
free(chunk);
|
||||
if(nbytes == -1)
|
||||
{
|
||||
//free(data);
|
||||
//return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
chunk = "\r\n";
|
||||
antd_send(client, chunk, strlen(chunk));
|
||||
}
|
||||
st = __b(client, (const unsigned char*)data, strlen(data));
|
||||
__b(client, (unsigned char*)"\r\n", 2);
|
||||
free(data);
|
||||
return st;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
//
|
||||
}
|
||||
int __b(void* client, const unsigned char* data, int size)
|
||||
@ -475,15 +491,15 @@ int __b(void* client, const unsigned char* data, int size)
|
||||
char buf[BUFFLEN];
|
||||
int sent = 0;
|
||||
int buflen = 0;
|
||||
int nbytes;
|
||||
int nbytes = 0;
|
||||
|
||||
if(size <= BUFFLEN)
|
||||
/*if(size <= BUFFLEN)
|
||||
{
|
||||
nbytes = antd_send(client,data,size);
|
||||
return (nbytes==-1?0:1);
|
||||
}
|
||||
else
|
||||
{
|
||||
{*/
|
||||
while(sent < size)
|
||||
{
|
||||
if(size - sent > BUFFLEN)
|
||||
@ -492,10 +508,13 @@ int __b(void* client, const unsigned char* data, int size)
|
||||
buflen = size - sent;
|
||||
memcpy(buf,data+sent,buflen);
|
||||
nbytes = antd_send(client,buf,buflen);
|
||||
sent += buflen;
|
||||
if(nbytes == -1) return 0;
|
||||
if(nbytes == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
sent += nbytes;
|
||||
}
|
||||
}
|
||||
//}
|
||||
return 1;
|
||||
}
|
||||
int __f(void* client, const char* file)
|
||||
@ -517,95 +536,64 @@ int __f(void* client, const char* file)
|
||||
fclose(ptr);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
int __f(void* client, const char* file)
|
||||
{
|
||||
char buf[BUFFLEN];
|
||||
FILE *ptr;
|
||||
int nbytes;
|
||||
ptr = fopen(file,"r");
|
||||
if(!ptr)
|
||||
{
|
||||
LOG("Cannot read : %s\n", file);
|
||||
return 0;
|
||||
}
|
||||
memset(buf,0, sizeof(buf));
|
||||
while(fgets(buf, sizeof(buf) - 1, ptr) != NULL)
|
||||
{
|
||||
nbytes = antd_send(client, buf, strlen(buf));
|
||||
if(nbytes == -1) return 0;
|
||||
memset(buf,0, sizeof(buf));
|
||||
//LOG("READ : %s\n", buf);
|
||||
//fgets(buf, sizeof(buf), ptr);
|
||||
}
|
||||
fclose(ptr);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
int upload(const char* tmp, const char* path)
|
||||
{
|
||||
return !rename(tmp, path);
|
||||
}
|
||||
// __plugin__.name
|
||||
void set_cookie(void* client,const char* type, dictionary dic, const char* name)
|
||||
|
||||
/*
|
||||
void set_cookie(void* client,const char* type, dictionary_t dic, const char* name)
|
||||
{
|
||||
set_status(client,200,"OK");
|
||||
__t(client,"Content-Type: %s",type);
|
||||
association assoc;
|
||||
chain_t assoc;
|
||||
for_each_assoc(assoc,dic){
|
||||
__t(client,"Set-Cookie: %s=%s; Path=/%s",assoc->key, (char*)assoc->value, name);
|
||||
}
|
||||
response(client,"");
|
||||
}
|
||||
void clear_cookie(void* client, dictionary dic)
|
||||
void clear_cookie(void* client, dictionary_t dic)
|
||||
{
|
||||
set_status(client,200,"OK");
|
||||
__t(client,"Content-Type: text/html; charset=utf-8");
|
||||
association assoc;
|
||||
chain_t assoc;
|
||||
for_each_assoc(assoc,dic){
|
||||
__t(client,"Set-Cookie: %s=%s;expires=",assoc->key, (char*)assoc->value, server_time());
|
||||
__t(client,"Set-Cookie: %s=%s;expires=%s",assoc->key, (char*)assoc->value, server_time());
|
||||
}
|
||||
response(client,"");
|
||||
}
|
||||
void unknow(void* client)
|
||||
*/
|
||||
|
||||
void antd_error(void* client, int status, const char* msg)
|
||||
{
|
||||
set_status(client,520,"Unknown Error");
|
||||
__t(client,"Content-Type: text/html; charset=utf-8");
|
||||
response(client,"");
|
||||
__t(client,"520 Unknow request");
|
||||
antd_response_header_t rsh;
|
||||
rsh.header = dict();
|
||||
rsh.cookie = NULL;
|
||||
const char* stat_str = get_status_str(status);
|
||||
rsh.status = status;
|
||||
dput(rsh.header, "Content-Type", strdup("text/html; charset=utf-8"));
|
||||
char * res_str = __s(HTML_TPL, stat_str, msg);
|
||||
int clen = 0;
|
||||
if(res_str)
|
||||
{
|
||||
clen = strlen(res_str);
|
||||
}
|
||||
char ibuf[20];
|
||||
snprintf (ibuf, sizeof(ibuf), "%d",clen);
|
||||
dput(rsh.header, "Content-Length", strdup(ibuf));
|
||||
antd_send_header(client, &rsh);
|
||||
if(res_str)
|
||||
{
|
||||
//printf("%s\n", res_str);
|
||||
__b(client, (unsigned char*)res_str, clen);
|
||||
//__t(client, HTML_TPL, stat_str, msg);
|
||||
free(res_str);
|
||||
}
|
||||
}
|
||||
void notfound(void* client)
|
||||
{
|
||||
set_status(client,404,"Not found");
|
||||
__t(client,"Content-Type: text/html; charset=utf-8");
|
||||
response(client,"");
|
||||
__t(client,"Resource not found");
|
||||
}
|
||||
void badrequest(void* client)
|
||||
{
|
||||
set_status(client,400,"Bad request");
|
||||
__t(client,"Content-Type: text/html; charset=utf-8");
|
||||
response(client,"");
|
||||
__t(client,"400 Bad request");
|
||||
}
|
||||
void unimplemented(void* client)
|
||||
{
|
||||
set_status(client,501,"Method Not Implemented");
|
||||
__t(client,"Content-Type: text/html");
|
||||
response(client,"");
|
||||
__t(client, "<HTML><HEAD><TITLE>Method Not Implemented");
|
||||
__t(client, "</TITLE></HEAD>");
|
||||
__t(client, "<BODY><P>HTTP request method not supported.");
|
||||
__t(client, "</BODY></HTML>");
|
||||
}
|
||||
void cannot_execute(void* client)
|
||||
{
|
||||
set_status(client,500,"Internal Server Error");
|
||||
__t(client,"Content-Type: text/html");
|
||||
response(client,"");
|
||||
__t(client, "<P>Error prohibited CGI execution.");
|
||||
}
|
||||
int ws_enable(dictionary dic)
|
||||
|
||||
|
||||
int ws_enable(dictionary_t dic)
|
||||
{
|
||||
if(!dic) return 0;
|
||||
char*v = (char*)dvalue(dic, "__web_socket__");
|
||||
@ -667,7 +655,7 @@ void destroy_request(void *data)
|
||||
// free all other thing
|
||||
if (rq->request)
|
||||
{
|
||||
dictionary tmp = dvalue(rq->request, "COOKIE");
|
||||
dictionary_t tmp = dvalue(rq->request, "COOKIE");
|
||||
if (tmp)
|
||||
freedict(tmp);
|
||||
tmp = dvalue(rq->request, "REQUEST_HEADER");
|
||||
|
43
lib/handle.h
43
lib/handle.h
@ -13,6 +13,7 @@
|
||||
#include "dbhelper.h"
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include "dictionary.h"
|
||||
#include "list.h"
|
||||
#include "ini.h"
|
||||
@ -48,9 +49,17 @@ typedef struct{
|
||||
|
||||
typedef struct {
|
||||
antd_client_t* client;
|
||||
dictionary request;
|
||||
dictionary_t request;
|
||||
} antd_request_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dictionary_t header;
|
||||
list_t cookie;
|
||||
int status;
|
||||
|
||||
} antd_response_header_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int port;
|
||||
@ -59,8 +68,8 @@ typedef struct {
|
||||
char *db_path;
|
||||
char* htdocs;
|
||||
char* tmpdir;
|
||||
list rules;
|
||||
dictionary handlers;
|
||||
list_t rules;
|
||||
dictionary_t handlers;
|
||||
int backlog;
|
||||
int maxcon;
|
||||
int connection;
|
||||
@ -73,6 +82,8 @@ typedef struct {
|
||||
int usessl;
|
||||
char* sslcert;
|
||||
char* sslkey;
|
||||
char* ssl_cipher;
|
||||
dictionary_t mimes;
|
||||
// #endif
|
||||
}config_t;
|
||||
|
||||
@ -90,31 +101,19 @@ typedef struct {
|
||||
|
||||
void set_nonblock(int socket);
|
||||
//void set_block(int socket);
|
||||
int response(void*, const char*);
|
||||
void ctype(void*,const char*);
|
||||
void redirect(void*,const char*);
|
||||
void html(void*);
|
||||
void text(void*);
|
||||
void json(void*);
|
||||
void jpeg(void*);
|
||||
void octstream(void*, char*);
|
||||
void textstream(void*);
|
||||
int __ti(void*,int);
|
||||
|
||||
void antd_send_header(void*,antd_response_header_t*);
|
||||
const char* get_status_str(int stat);
|
||||
int __t(void*, const char*,...);
|
||||
int __b(void*, const unsigned char*, int);
|
||||
int __f(void*, const char*);
|
||||
//int __fb(void*, const char*);
|
||||
|
||||
int upload(const char*, const char*);
|
||||
|
||||
void set_cookie(void*, const char*,dictionary,const char*);
|
||||
void set_status(void*,int,const char*);
|
||||
void clear_cookie(void*, dictionary);
|
||||
/*Default function for plugin*/
|
||||
void unknow(void*);
|
||||
void badrequest(void* client);
|
||||
void unimplemented(void* client);
|
||||
void notfound(void* client);
|
||||
int ws_enable(dictionary);
|
||||
void antd_error(void* client, int status, const char* msg);
|
||||
|
||||
int ws_enable(dictionary_t);
|
||||
char* read_line(void* sock);
|
||||
int read_buf(void* sock,char* buf,int i);
|
||||
int antd_send( void *source, const void* data, int len);
|
||||
|
119
lib/list.c
119
lib/list.c
@ -23,52 +23,52 @@ THE SOFTWARE.
|
||||
*/
|
||||
#include "list.h"
|
||||
|
||||
list list_init()
|
||||
list_t list_init()
|
||||
{
|
||||
list ret = (list)malloc(sizeof *ret);
|
||||
ret->type = RPC_TYPE_NIL;
|
||||
list_t ret = (list_t)malloc(sizeof *ret);
|
||||
ret->type = LIST_TYPE_NIL;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
void list_put(list* l, item it)
|
||||
void list_put(list_t* l, item_t it)
|
||||
{
|
||||
if(*l == NULL || (*l)->type == RPC_TYPE_NIL)
|
||||
if(*l == NULL || (*l)->type == LIST_TYPE_NIL)
|
||||
{
|
||||
free(*l);
|
||||
*l = it;
|
||||
return ;
|
||||
}
|
||||
item np = list_last(*l);
|
||||
item_t np = list_last(*l);
|
||||
np->next = it;
|
||||
}
|
||||
void list_put_special(list* l, const char* str)
|
||||
void list_put_special(list_t* l, const char* str)
|
||||
{
|
||||
item v;
|
||||
item_t v;
|
||||
if(IS_INT(str))
|
||||
{
|
||||
v = list_item(RPC_TYPE_INT);
|
||||
v = list_item(LIST_TYPE_INT);
|
||||
v->value.i = atoi(str);
|
||||
}
|
||||
else if(IS_FLOAT(str))
|
||||
{
|
||||
v = list_item(RPC_TYPE_DOUBLE);
|
||||
v = list_item(LIST_TYPE_DOUBLE);
|
||||
v->value.d = (double)atof(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = list_item(RPC_TYPE_STRING);
|
||||
v = list_item(LIST_TYPE_STRING);
|
||||
v->value.s = strdup(str);
|
||||
}
|
||||
list_put(l,v);
|
||||
}
|
||||
item list_last(list l)
|
||||
item_t list_last(list_t l)
|
||||
{
|
||||
item p = l;
|
||||
item_t p = l;
|
||||
while(p && p->next != NULL)
|
||||
p = p->next;
|
||||
return p;
|
||||
}
|
||||
int list_remove(list l,int idx)
|
||||
int list_remove(list_t l,int idx)
|
||||
{
|
||||
if(l==NULL) return 0;
|
||||
if(idx <0 || idx >= list_size(l)) return 0;
|
||||
@ -77,17 +77,17 @@ int list_remove(list l,int idx)
|
||||
l=l->next;
|
||||
return 1;
|
||||
}
|
||||
item np = list_at(l,idx-1);
|
||||
item_t np = list_at(l,idx-1);
|
||||
if(np == NULL) return 0;
|
||||
if(np->next == NULL) return 1;
|
||||
np->next = np->next->next;
|
||||
return 1;
|
||||
}
|
||||
int list_size(list l)
|
||||
int list_size(list_t l)
|
||||
{
|
||||
if(l == NULL || l->type == RPC_TYPE_NIL) return 0;
|
||||
if(l == NULL || l->type == LIST_TYPE_NIL) return 0;
|
||||
int i=0;
|
||||
item np = l;
|
||||
item_t np = l;
|
||||
while(np)
|
||||
{
|
||||
np = np->next;
|
||||
@ -95,46 +95,46 @@ int list_size(list l)
|
||||
}
|
||||
return i;
|
||||
}
|
||||
char* as_string(list l)
|
||||
char* as_string(list_t l)
|
||||
{
|
||||
char* str = "";
|
||||
if(l != NULL && l->type != RPC_TYPE_NIL)
|
||||
if(l != NULL && l->type != LIST_TYPE_NIL)
|
||||
{
|
||||
switch(l->type)
|
||||
{
|
||||
case RPC_TYPE_BASE64:
|
||||
case LIST_TYPE_BASE64:
|
||||
str = __s("b64:%s", l->value.b64);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_BOOL:
|
||||
case LIST_TYPE_BOOL:
|
||||
str = __s("bool:%d", l->value.b);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_DOUBLE:
|
||||
case LIST_TYPE_DOUBLE:
|
||||
str = __s("double:%lf", l->value.d);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_DATE:
|
||||
case LIST_TYPE_DATE:
|
||||
str = __s("date:%s", l->value.date);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_INT:
|
||||
case RPC_TYPE_I4:
|
||||
case LIST_TYPE_INT:
|
||||
case LIST_TYPE_I4:
|
||||
str = __s("int:%d", l->value.i);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_STRING:
|
||||
case LIST_TYPE_STRING:
|
||||
str = __s("string:%s", l->value.s);
|
||||
break;
|
||||
|
||||
case RPC_TYPE_ARRAY:
|
||||
case LIST_TYPE_ARRAY:
|
||||
str = __s("[%s]", as_string(l->value.array));
|
||||
break;
|
||||
default:
|
||||
str = "<Unknown>";
|
||||
break;
|
||||
}
|
||||
item np = l->next;
|
||||
item_t np = l->next;
|
||||
if(np)
|
||||
{
|
||||
str = __s("%s,\n%s", str, as_string(np));
|
||||
@ -143,12 +143,12 @@ char* as_string(list l)
|
||||
}
|
||||
return "[empty]";
|
||||
}
|
||||
item list_at(list l,int idx)
|
||||
item_t list_at(list_t l,int idx)
|
||||
{
|
||||
if(l == NULL || idx<0 || idx>= list_size(l))
|
||||
return NULL;
|
||||
int i=0;
|
||||
item np = l;
|
||||
item_t np = l;
|
||||
while(np)
|
||||
{
|
||||
if(i==idx)
|
||||
@ -158,20 +158,20 @@ item list_at(list l,int idx)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
item list_item(int type)
|
||||
item_t list_item(int type)
|
||||
{
|
||||
item ret = (item)malloc(sizeof *ret);
|
||||
item_t ret = (item_t)malloc(sizeof *ret);
|
||||
ret->type = type;
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
list split(const char* str, const char* delim)
|
||||
list_t split(const char* str, const char* delim)
|
||||
{
|
||||
if(str == NULL || delim == NULL) return NULL;
|
||||
char* str_cpy = strdup(str);
|
||||
char* org_str = str_cpy;
|
||||
char* token;
|
||||
list l = list_init();
|
||||
list_t l = list_init();
|
||||
while((token = strsep(&str_cpy,delim)))
|
||||
{
|
||||
if(strlen(token) > 0)
|
||||
@ -180,69 +180,72 @@ list split(const char* str, const char* delim)
|
||||
}
|
||||
}
|
||||
free(org_str);
|
||||
if(l->type== RPC_TYPE_NIL)
|
||||
if(l->type== LIST_TYPE_NIL)
|
||||
{
|
||||
free(l);
|
||||
return NULL;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
void list_put_i(list* l,int v)
|
||||
void list_put_i(list_t* l,int v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_INT);
|
||||
item_t it = list_item(LIST_TYPE_INT);
|
||||
it->value.i = v;
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_d(list* l,double v)
|
||||
void list_put_d(list_t* l,double v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_DOUBLE);
|
||||
item_t it = list_item(LIST_TYPE_DOUBLE);
|
||||
it->value.d = v;
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_b(list* l,int v)
|
||||
void list_put_b(list_t* l,int v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_BOOL);
|
||||
item_t it = list_item(LIST_TYPE_BOOL);
|
||||
it->value.b = v;
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_b64(list* l,const char* v)
|
||||
void list_put_b64(list_t* l,const char* v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_BASE64);
|
||||
item_t it = list_item(LIST_TYPE_BASE64);
|
||||
it->value.b64 = strdup(v);
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_date(list* l,const char* v)
|
||||
void list_put_date(list_t* l,const char* v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_DATE);
|
||||
item_t it = list_item(LIST_TYPE_DATE);
|
||||
it->value.date = strdup(v);
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_s(list* l,const char* v)
|
||||
void list_put_s(list_t* l,const char* v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_STRING);
|
||||
item_t it = list_item(LIST_TYPE_STRING);
|
||||
it->value.s = strdup(v);
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_put_array(list* l,list v)
|
||||
void list_put_array(list_t* l,list_t v)
|
||||
{
|
||||
item it = list_item(RPC_TYPE_ARRAY);
|
||||
item_t it = list_item(LIST_TYPE_ARRAY);
|
||||
it->value.array = v;
|
||||
list_put(l,it);
|
||||
}
|
||||
void list_free(list *l)
|
||||
void list_free(list_t *l)
|
||||
{
|
||||
item curr;
|
||||
item_t curr;
|
||||
while ((curr = (*l)) != NULL) {
|
||||
(*l) = (*l)->next;
|
||||
if(curr->type == RPC_TYPE_ARRAY)
|
||||
if(curr->type == LIST_TYPE_ARRAY)
|
||||
list_free(&curr->value.array);
|
||||
else if(curr->type == RPC_TYPE_STRING)
|
||||
else if(curr->type == LIST_TYPE_STRING)
|
||||
free(curr->value.s);
|
||||
else if(curr->type == RPC_TYPE_DATE)
|
||||
else if(curr->type == LIST_TYPE_DATE)
|
||||
free(curr->value.date);
|
||||
else if(curr->type == RPC_TYPE_BASE64)
|
||||
else if(curr->type == LIST_TYPE_BASE64)
|
||||
free(curr->value.b64);
|
||||
free (curr);
|
||||
}
|
||||
}
|
||||
int list_empty(list l)
|
||||
int list_empty(list_t l)
|
||||
{
|
||||
return l== NULL || l->type == RPC_TYPE_NIL;
|
||||
return l== NULL || l->type == LIST_TYPE_NIL;
|
||||
}
|
54
lib/list.h
54
lib/list.h
@ -24,7 +24,17 @@ THE SOFTWARE.
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
#include "utils.h"
|
||||
#define list item
|
||||
|
||||
#define LIST_TYPE_ARRAY 601//hash("array")
|
||||
#define LIST_TYPE_BASE64 335//hash("base64")
|
||||
#define LIST_TYPE_BOOL 40//hash("boolean")
|
||||
#define LIST_TYPE_DOUBLE 977//hash("double")
|
||||
#define LIST_TYPE_DATE 49//hash("dateTime.iso8601")
|
||||
#define LIST_TYPE_INT 1007//hash("int")
|
||||
#define LIST_TYPE_I4 235//hash("i4")
|
||||
#define LIST_TYPE_STRING 17//hash("string")
|
||||
#define LIST_TYPE_NIL 529//hash("nil")
|
||||
|
||||
typedef struct __item{
|
||||
int type;
|
||||
union{
|
||||
@ -37,25 +47,25 @@ typedef struct __item{
|
||||
struct __item* array;
|
||||
} value;
|
||||
struct __item* next;
|
||||
}*item;
|
||||
|
||||
list list_init();
|
||||
void list_put(list*,item);
|
||||
void list_put_i(list*,int);
|
||||
void list_put_d(list*,double);
|
||||
void list_put_b(list*,int);
|
||||
void list_put_b64(list*,const char*);
|
||||
void list_put_date(list*,const char*);
|
||||
void list_put_s(list*,const char*);
|
||||
void list_put_array(list*,list);
|
||||
item list_last(list);
|
||||
int list_remove(list,int);
|
||||
int list_size(list);
|
||||
item list_at(list,int);
|
||||
int list_empty(list);
|
||||
item list_item(int type);
|
||||
list split(const char*, const char*);
|
||||
char* as_string(list);
|
||||
void list_put_special(list*, const char*);
|
||||
void list_free(list *);
|
||||
}*item_t;
|
||||
typedef item_t list_t;
|
||||
list_t list_init();
|
||||
void list_put(list_t*,item_t);
|
||||
void list_put_i(list_t*,int);
|
||||
void list_put_d(list_t*,double);
|
||||
void list_put_b(list_t*,int);
|
||||
void list_put_b64(list_t*,const char*);
|
||||
void list_put_date(list_t*,const char*);
|
||||
void list_put_s(list_t*,const char*);
|
||||
void list_put_array(list_t*,list_t);
|
||||
item_t list_last(list_t);
|
||||
int list_remove(list_t,int);
|
||||
int list_size(list_t);
|
||||
item_t list_at(list_t,int);
|
||||
int list_empty(list_t);
|
||||
item_t list_item(int type);
|
||||
list_t split(const char*, const char*);
|
||||
char* as_string(list_t);
|
||||
void list_put_special(list_t*, const char*);
|
||||
void list_free(list_t *);
|
||||
#endif
|
131
lib/utils.c
131
lib/utils.c
@ -23,58 +23,6 @@ THE SOFTWARE.
|
||||
*/
|
||||
#include "utils.h"
|
||||
|
||||
//define all basic mime here
|
||||
|
||||
static mime_t _mimes[] = {
|
||||
{"image/bmp",(const char *[]){"bmp",NULL},1},
|
||||
{"image/jpeg",(const char *[]){"jpg","jpeg",NULL},1},
|
||||
{"text/css",(const char *[]){"css",NULL},0},
|
||||
{"text/markdown",(const char *[]){"md",NULL},0},
|
||||
{"text/csv",(const char *[]){"csv",NULL},0},
|
||||
{"application/pdf",(const char *[]){"pdf",NULL},1},
|
||||
{"image/gif",(const char *[]){"gif",NULL},1},
|
||||
{"text/html",(const char *[]){"html","htm",NULL},0},
|
||||
{"application/json",(const char *[]){"json",NULL},0},
|
||||
{"application/javascript",(const char *[]){"js",NULL},0},
|
||||
{"image/png",(const char *[]){"png",NULL},1},
|
||||
{"image/x-portable-pixmap",(const char *[]){"ppm",NULL},1},
|
||||
{"application/x-rar-compressed",(const char *[]){"rar",NULL},1},
|
||||
{"image/tiff",(const char *[]){"tiff",NULL},1},
|
||||
{"application/x-tar",(const char *[]){"tar",NULL},1},
|
||||
{"text/plain",(const char *[]){"txt",NULL},0},
|
||||
{"application/x-font-ttf",(const char *[]){"ttf",NULL},1},
|
||||
{"application/xhtml+xml",(const char *[]){"xhtml",NULL},0},
|
||||
{"application/xml",(const char *[]){"xml",NULL},0},
|
||||
{"application/zip",(const char *[]){"zip",NULL},1},
|
||||
{"image/svg+xml",(const char *[]){"svg",NULL},0},
|
||||
{"application/vnd.ms-fontobject",(const char *[]){"eot",NULL},1},
|
||||
{"application/x-font-woff",(const char *[]){"woff","woff2",NULL},1},
|
||||
{"application/x-font-otf",(const char *[]){"otf",NULL},1},
|
||||
{"audio/mpeg",(const char *[]){"mp3","mpeg",NULL},1},
|
||||
{NULL,NULL,0}
|
||||
};
|
||||
|
||||
|
||||
char* __s(const char* fstring,...)
|
||||
{
|
||||
char* data;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
va_end(arguments);
|
||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
||||
{
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(data, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
return data;
|
||||
} else
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Trim a string by a character on both ends
|
||||
* @param str The target string
|
||||
@ -162,21 +110,47 @@ char* ext(const char* file)
|
||||
/*get mime file info from extension*/
|
||||
mime_t mime_from_ext(const char* ex)
|
||||
{
|
||||
for(int i = 0; _mimes[i].type != NULL; i++)
|
||||
for(int j = 0; _mimes[i].ext[j] != NULL; j++)
|
||||
{
|
||||
if(IEQU(ex,_mimes[i].ext[j])) return _mimes[i];
|
||||
}
|
||||
dictionary_t mime_list = mimes_list();
|
||||
mime_t ret = (mime_t){"application/octet-stream",NULL};
|
||||
if(!mime_list)
|
||||
return ret;
|
||||
chain_t it;
|
||||
char * pattern = __s("(^\\s*%s\\s*,)|(\\s*,\\s*%s\\s*,\\s*)|(^\\s*%s\\s*$)|(,\\s*%s\\s*$)", ex, ex, ex, ex);
|
||||
if(pattern)
|
||||
{
|
||||
for_each_assoc(it,mime_list)
|
||||
{
|
||||
|
||||
return (mime_t){"application/octet-stream",(const char *[]){(char*)ext,NULL},1};
|
||||
if(regex_match(pattern,it->value,0, NULL))
|
||||
{
|
||||
ret.type = it->key;
|
||||
ret.ext = it->value;
|
||||
free(pattern);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
free(pattern);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
dictionary_t mimes_list()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/*get mime file info from type*/
|
||||
mime_t mime_from_type(const char* type)
|
||||
{
|
||||
for(int i = 0; _mimes[i].type != NULL; i++)
|
||||
if(strstr(type, _mimes[i].type) != NULL)
|
||||
return _mimes[i];
|
||||
return (mime_t){NULL,NULL,0};
|
||||
dictionary_t mime_list = mimes_list();
|
||||
mime_t ret = (mime_t){NULL,NULL};
|
||||
if(!mime_list)
|
||||
return ret;
|
||||
chain_t it = dlookup(mime_list, type);
|
||||
if(it)
|
||||
{
|
||||
ret.type = it->key;
|
||||
ret.ext = it->value;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Get correct HTTP mime type of a file
|
||||
@ -194,18 +168,7 @@ char* mime(const char* file)
|
||||
{
|
||||
free(ex);
|
||||
}
|
||||
return (char*)m.type;
|
||||
}
|
||||
|
||||
int is_bin(const char* file)
|
||||
{
|
||||
char * ex = ext(file);
|
||||
mime_t m = mime_from_ext(ex);
|
||||
if(ex)
|
||||
{
|
||||
free(ex);
|
||||
}
|
||||
return m.bin;
|
||||
return (char*)m.type;
|
||||
}
|
||||
|
||||
int match_int(const char* search)
|
||||
@ -475,3 +438,23 @@ void sha1(const char* text, char* out)
|
||||
SHA1_Final(d, &context);
|
||||
digest_to_hex(d,out);
|
||||
}
|
||||
|
||||
|
||||
char* __s(const char* fstring,...)
|
||||
{
|
||||
char* data;
|
||||
va_list arguments;
|
||||
int dlen;
|
||||
va_start( arguments, fstring);
|
||||
dlen = vsnprintf(0,0,fstring,arguments) + 1;
|
||||
va_end(arguments);
|
||||
va_end(arguments);
|
||||
if ((data = (char*)malloc(dlen*sizeof(char))) != 0)
|
||||
{
|
||||
va_start(arguments, fstring);
|
||||
vsnprintf(data, dlen, fstring, arguments);
|
||||
va_end(arguments);
|
||||
return data;
|
||||
} else
|
||||
return "";
|
||||
}
|
21
lib/utils.h
21
lib/utils.h
@ -43,6 +43,7 @@ THE SOFTWARE.
|
||||
#include "sha1.h"
|
||||
#endif
|
||||
#include "base64.h"
|
||||
#include "dictionary.h"
|
||||
|
||||
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
|
||||
#define EQU(a,b) (strcmp(a,b) == 0)
|
||||
@ -54,36 +55,25 @@ THE SOFTWARE.
|
||||
#define true 1
|
||||
#define false 0
|
||||
#ifdef DEBUG
|
||||
#define LOG(a,...) server_log("%s:%d: " a "\n", __FILE__, \
|
||||
#define LOG(a,...) server_log("[%s: %d]: " a "\n", __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(a,...) do{}while(0)
|
||||
#endif
|
||||
#define ERROR(a,...) error_log("%s:%d: " a "\n", __FILE__, \
|
||||
#define ERROR(a,...) error_log("[%s: %d]: " a "\n", __FILE__, \
|
||||
__LINE__, ##__VA_ARGS__)
|
||||
// add this to the utils
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#define BUFFLEN 1024
|
||||
#define HASHSIZE 1024
|
||||
#define DHASHSIZE 50
|
||||
|
||||
#define RPC_TYPE_ARRAY 601//hash("array")
|
||||
#define RPC_TYPE_BASE64 335//hash("base64")
|
||||
#define RPC_TYPE_BOOL 40//hash("boolean")
|
||||
#define RPC_TYPE_DOUBLE 977//hash("double")
|
||||
#define RPC_TYPE_DATE 49//hash("dateTime.iso8601")
|
||||
#define RPC_TYPE_INT 1007//hash("int")
|
||||
#define RPC_TYPE_I4 235//hash("i4")
|
||||
#define RPC_TYPE_STRING 17//hash("string")
|
||||
#define RPC_TYPE_NIL 529//hash("nil")
|
||||
|
||||
typedef struct{
|
||||
const char* type;
|
||||
const char** ext;
|
||||
int bin;
|
||||
const char* ext;
|
||||
} mime_t;
|
||||
|
||||
dictionary_t __attribute__((weak)) mimes_list();
|
||||
char* __s(const char*,...);
|
||||
void trim(char*,const char);
|
||||
void removeAll(const char* path,int mode);
|
||||
@ -91,7 +81,6 @@ char* __time(time_t time);
|
||||
char* server_time();
|
||||
char* ext(const char*);
|
||||
char* mime(const char*);
|
||||
int is_bin(const char*);
|
||||
int match_int(const char*);
|
||||
int match_float(const char*);
|
||||
int regex_match(const char*,const char*, int, regmatch_t*);
|
||||
|
Loading…
Reference in New Issue
Block a user