... | ... |
@@ -1072,6 +1072,7 @@ wk_accept(_wk *web) |
1072 | 1072 |
return(NULL); |
1073 | 1073 |
} |
1074 | 1074 |
client->fd=newfd; |
1075 |
+ sock_setsafe(client->fd); |
|
1075 | 1076 |
DEBUG_CONN(("WEBK","wk_accept: connid: %i, fd: %i",client->connid,client->fd)); |
1076 | 1077 |
FD_SET(client->fd,&(web->fdset)); |
1077 | 1078 |
sselect_addread(web->ssel,client->fd,(void *)client); |
... | ... |
@@ -463,7 +463,7 @@ wk_serve_etagset(wk *paramweb, int connid, char *etag) |
463 | 463 |
} |
464 | 464 |
|
465 | 465 |
int |
466 |
-wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
|
466 |
+wk_serve_generic_headers(wk *paramweb, int connid, int datalen, const char *mime, int *etagnotmodified) |
|
467 | 467 |
{ |
468 | 468 |
static const char *strcontenttype={"Content-Type: "}; |
469 | 469 |
_wk *web=(_wk *)paramweb; |
... | ... |
@@ -476,6 +476,8 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const |
476 | 476 |
if((client=wk_clientget(web,connid))==NULL) |
477 | 477 |
return(-1); |
478 | 478 |
cachedetag=(wk_etagnotmodified(web,client)==0)?1:0; |
479 |
+ if(etagnotmodified!=NULL) |
|
480 |
+ *etagnotmodified=cachedetag; |
|
479 | 481 |
if(!cachedetag) |
480 | 482 |
wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
481 | 483 |
else |
... | ... |
@@ -505,6 +507,20 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const |
505 | 507 |
if(client->keepalive) |
506 | 508 |
wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n"); |
507 | 509 |
wk_writestr((wk *)web,connid,"\r\n"); |
510 |
+ return(0); |
|
511 |
+} |
|
512 |
+ |
|
513 |
+int |
|
514 |
+wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
|
515 |
+{ |
|
516 |
+ _wk *web=(_wk *)paramweb; |
|
517 |
+ int cachedetag; |
|
518 |
+ int res; |
|
519 |
+ if(web==NULL || datalen<0 || (data==NULL && datalen>0)) |
|
520 |
+ return(-1); |
|
521 |
+ res=wk_serve_generic_headers((wk *)web,connid,datalen,mime,&cachedetag); |
|
522 |
+ if(res!=0) |
|
523 |
+ return(res); |
|
508 | 524 |
if(!cachedetag) |
509 | 525 |
return(wk_write((wk *)web,connid,data,datalen)); |
510 | 526 |
return(0); |
... | ... |
@@ -1198,6 +1198,7 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
1198 | 1198 |
char *sep; |
1199 | 1199 |
wk_uri *uri; |
1200 | 1200 |
wk_action action; |
1201 |
+ int flagusepostcallback; |
|
1201 | 1202 |
if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
1202 | 1203 |
return(-1); /* internal error */ |
1203 | 1204 |
/* get memory for the uri data */ |
... | ... |
@@ -1276,15 +1277,20 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
1276 | 1277 |
sbuf_add(hbuf,"",1); |
1277 | 1278 |
/* mark data as used */ |
1278 | 1279 |
sbuf_getbytes(in,end-sbuf_ptr(in)+4); |
1279 |
- /* call the http method */ |
|
1280 |
+ /* call the http method if GET (or not post callback) , or the post method if POST */ |
|
1280 | 1281 |
client->uriready=1; |
1281 | 1282 |
client->continuationactive=0; |
1282 |
- action=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
|
1283 |
+ flagusepostcallback=(strcmp(client->uri.method,"POST")==0 && web->callback_post!=NULL)?1:0; |
|
1284 |
+ if(flagusepostcallback) { |
|
1285 |
+ action=web->callback_post((wk *)web, client->connid, uri, web->userptr); |
|
1286 |
+ } else { |
|
1287 |
+ action=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
|
1288 |
+ } |
|
1283 | 1289 |
if(action==wkact_continuation) { |
1284 | 1290 |
client->uriready=1; |
1285 | 1291 |
client->continuationactive=1; |
1286 | 1292 |
client->status=wkc_header; |
1287 |
- } else if(action==wkact_post && web->callback_post!=NULL) { |
|
1293 |
+ } else if(flagusepostcallback) { |
|
1288 | 1294 |
char *lenvar; |
1289 | 1295 |
char *contenttype; |
1290 | 1296 |
if(strcmp(client->uri.method,"POST")!=0 || |
... | ... |
@@ -1354,7 +1360,7 @@ wk_clientservicereadpost(_wk *web, wk_client *client) |
1354 | 1360 |
sbuf_getbytes(in,end-start); |
1355 | 1361 |
client->pendingpost-=(end-start); |
1356 | 1362 |
} |
1357 |
- if(*sep=='&') { |
|
1363 |
+ if(sep!=NULL && *sep=='&') { |
|
1358 | 1364 |
sbuf_getbytes(in,1); |
1359 | 1365 |
client->pendingpost--; |
1360 | 1366 |
client->inpostvar=-1; |
... | ... |
@@ -1362,14 +1368,14 @@ wk_clientservicereadpost(_wk *web, wk_client *client) |
1362 | 1368 |
} |
1363 | 1369 |
if(client->pendingpost>0) |
1364 | 1370 |
return(0); /* nothing more to do for now*/ |
1365 |
- /* call the post method */ |
|
1371 |
+ /* call the http method */ |
|
1366 | 1372 |
client->uriready=1; |
1367 | 1373 |
client->continuationactive=0; |
1368 |
- action=web->callback_post((wk *)web, client->connid, client->uri, web->userptr); |
|
1374 |
+ action=web->callback_http((wk *)web, client->connid, &(client->uri), web->userptr); |
|
1369 | 1375 |
if(action==wkact_continuation) { |
1370 | 1376 |
client->uriready=1; |
1371 | 1377 |
client->continuationactive=1; |
1372 |
- client->status=wkc_header; |
|
1378 |
+ client->status=wkc_post; |
|
1373 | 1379 |
} else { |
1374 | 1380 |
client->uriready=1; |
1375 | 1381 |
client->continuationactive=0; |
... | ... |
@@ -1407,15 +1413,16 @@ wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile) |
1407 | 1413 |
return(-1); /* varname too long */ |
1408 | 1414 |
} |
1409 | 1415 |
post->name=sbuf_ptrunused(buf); |
1410 |
- sbuf_addstr(buf,varname); |
|
1416 |
+ sbuf_add(buf,varname,strlen(varname)+1); |
|
1411 | 1417 |
if(tofile!=NULL) { |
1412 | 1418 |
if((strlen(tofile)+1)>(sbuf_unused(buf))) { |
1413 | 1419 |
wk_sbufrelease((wk *)web,post->bufid),post->bufid=-1; |
1414 | 1420 |
return(-1); /* varname+tofile too long */ |
1415 | 1421 |
} |
1416 | 1422 |
post->tofile=sbuf_ptrunused(buf); |
1417 |
- sbuf_addstr(buf,tofile); |
|
1423 |
+ sbuf_add(buf,tofile,strlen(tofile)+1); |
|
1418 | 1424 |
} |
1425 |
+ client->usedpost++; |
|
1419 | 1426 |
post->value=NULL; |
1420 | 1427 |
post->filewritten=0; |
1421 | 1428 |
post->valueterminated=0; |
... | ... |
@@ -930,10 +930,15 @@ uri_urldecode(char *s) |
930 | 930 |
s[o]=' '; |
931 | 931 |
else if(s[i]=='%' && (a=s[i+1])!='\0' && (b=s[i+2])!='\0' && ISHEXNIBBLE(a) && ISHEXNIBBLE(b)) { |
932 | 932 |
n=(HEXNIBBLE2BIN(a)<<4)|HEXNIBBLE2BIN(b); |
933 |
- s[o]=128|64|(n>>6); |
|
934 |
- s[o+1]=128|(n&0x3f); |
|
935 |
- i+=2; |
|
936 |
- o++; |
|
933 |
+ if(n>=128) { |
|
934 |
+ s[o]=128|64|(n>>6); |
|
935 |
+ s[o+1]=128|(n&0x3f); |
|
936 |
+ i+=2; |
|
937 |
+ o++; |
|
938 |
+ } else { |
|
939 |
+ s[o]=n; |
|
940 |
+ i+=2; |
|
941 |
+ } |
|
937 | 942 |
} else |
938 | 943 |
s[o]=s[i]; |
939 | 944 |
} |
... | ... |
@@ -33,6 +33,10 @@ |
33 | 33 |
#define ALIVETIMEOUT 15 |
34 | 34 |
#define MAXETAGSIZE 127 |
35 | 35 |
|
36 |
+#define HEXNIBBLE2BIN(a) (((a)>='0' && (a)<='9')?(a)-'0':((a)>='a' && (a)<='f')?(a)-'a'+10:((a)>='A' && (a)<='F')?(a)-'A'+10:0) |
|
37 |
+#define ISHEXNIBBLE(a) ((((a)>='0' && (a)<='9')||((a)>='a' && (a)<='f')||((a)>='A' && (a)<='F'))?1:0) |
|
38 |
+ |
|
39 |
+ |
|
36 | 40 |
typedef struct wk_post { |
37 | 41 |
char *name; |
38 | 42 |
char *value; |
... | ... |
@@ -916,6 +920,28 @@ mime_getdefault(const char *filename, const char *defaultmime) |
916 | 920 |
return(defaultmime); |
917 | 921 |
} |
918 | 922 |
|
923 |
+int |
|
924 |
+uri_urldecode(char *s) |
|
925 |
+{ |
|
926 |
+ int i,o; |
|
927 |
+ int a,b,n; |
|
928 |
+ for(i=0,o=0;s[i]!='\0';i++,o++) { |
|
929 |
+ if(s[i]=='+') |
|
930 |
+ s[o]=' '; |
|
931 |
+ else if(s[i]=='%' && (a=s[i+1])!='\0' && (b=s[i+2])!='\0' && ISHEXNIBBLE(a) && ISHEXNIBBLE(b)) { |
|
932 |
+ n=(HEXNIBBLE2BIN(a)<<4)|HEXNIBBLE2BIN(b); |
|
933 |
+ s[o]=128|64|(n>>6); |
|
934 |
+ s[o+1]=128|(n&0x3f); |
|
935 |
+ i+=2; |
|
936 |
+ o++; |
|
937 |
+ } else |
|
938 |
+ s[o]=s[i]; |
|
939 |
+ } |
|
940 |
+ s[o]='\0'; |
|
941 |
+ return(0); |
|
942 |
+} |
|
943 |
+ |
|
944 |
+ |
|
919 | 945 |
int |
920 | 946 |
wk_sbufacquire(wk *paramweb) |
921 | 947 |
{ |
... | ... |
@@ -31,6 +31,7 @@ |
31 | 31 |
#define BUFBLOCKBLOCK 256 |
32 | 32 |
#define POSTBLOCK 16 |
33 | 33 |
#define ALIVETIMEOUT 15 |
34 |
+#define MAXETAGSIZE 127 |
|
34 | 35 |
|
35 | 36 |
typedef struct wk_post { |
36 | 37 |
char *name; |
... | ... |
@@ -67,6 +68,7 @@ typedef struct wk_client { |
67 | 68 |
int pendingpost; |
68 | 69 |
int inpostvar; |
69 | 70 |
int cookiebufid; |
71 |
+ char etag[MAXETAGSIZE+1]; |
|
70 | 72 |
time_t lastio; |
71 | 73 |
} wk_client; |
72 | 74 |
|
... | ... |
@@ -117,6 +119,7 @@ static int wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile); |
117 | 119 |
static int wk_postset(_wk *web, wk_client *client,char *varname, char *data, int datalen); |
118 | 120 |
static char *wk_postget(_wk *web, wk_client *client,char *varname, int *isfile); |
119 | 121 |
static int wk_postfree(_wk *web, wk_client *client); |
122 |
+static int wk_etagnotmodified(_wk *web, wk_client *client); |
|
120 | 123 |
|
121 | 124 |
#ifdef WK_DEBUG_IO |
122 | 125 |
#define DEBUG_IN_PRE { int sbp=sbuf_count(in); |
... | ... |
@@ -438,6 +441,22 @@ wk_serve_cookieadd(wk *paramweb, int connid, char *cookiename, char *value, char |
438 | 441 |
return(0); |
439 | 442 |
} |
440 | 443 |
|
444 |
+int |
|
445 |
+wk_serve_etagset(wk *paramweb, int connid, char *etag) |
|
446 |
+{ |
|
447 |
+ _wk *web=(_wk *)paramweb; |
|
448 |
+ wk_client *client; |
|
449 |
+ if(web==NULL) |
|
450 |
+ return(-1); |
|
451 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
452 |
+ return(-1); |
|
453 |
+ if(etag!=NULL) { |
|
454 |
+ strncpy(client->etag,etag,sizeof(client->etag)); |
|
455 |
+ client->etag[sizeof(client->etag)-1]='\0'; |
|
456 |
+ } else |
|
457 |
+ client->etag[0]='\0'; |
|
458 |
+ return(0); |
|
459 |
+} |
|
441 | 460 |
|
442 | 461 |
int |
443 | 462 |
wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
... | ... |
@@ -447,28 +466,44 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const |
447 | 466 |
wk_client *client; |
448 | 467 |
char buf[256]; |
449 | 468 |
sbuf *cookiebuf; |
469 |
+ int cachedetag; |
|
450 | 470 |
if(web==NULL) |
451 | 471 |
return(-1); |
452 | 472 |
if((client=wk_clientget(web,connid))==NULL) |
453 | 473 |
return(-1); |
454 |
- wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
|
474 |
+ cachedetag=(wk_etagnotmodified(web,client)==0)?1:0; |
|
475 |
+ if(!cachedetag) |
|
476 |
+ wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
|
477 |
+ else |
|
478 |
+ wk_writestr((wk *)web,connid,"HTTP/1.1 304 Not modified\r\n"); |
|
455 | 479 |
if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) { |
456 | 480 |
if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 || |
457 | 481 |
sbuf_count(cookiebuf)!=0) |
458 | 482 |
return(-1); /* insufficient memory */ |
459 | 483 |
wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
460 | 484 |
} |
461 |
- sprintf(buf,"Content-Length: %i\r\n",datalen); |
|
462 |
- wk_writestr((wk *)web,connid,buf); |
|
463 |
- if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
464 |
- sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
465 |
- else |
|
466 |
- sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
467 |
- wk_writestr((wk *)web,connid,buf); |
|
485 |
+ if(!cachedetag) { |
|
486 |
+ if(client->etag[0]!='\0') { |
|
487 |
+ sprintf(buf,"ETag: \"%s\"\r\n",client->etag); |
|
488 |
+ client->etag[0]='\0'; |
|
489 |
+ wk_writestr((wk *)web,connid,buf); |
|
490 |
+ } |
|
491 |
+ sprintf(buf,"Content-Length: %i\r\n",datalen); |
|
492 |
+ wk_writestr((wk *)web,connid,buf); |
|
493 |
+ if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
494 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
495 |
+ else |
|
496 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
497 |
+ wk_writestr((wk *)web,connid,buf); |
|
498 |
+ } else { |
|
499 |
+ wk_writestr((wk *)web,connid,"Content-Length: 0\r\n"); |
|
500 |
+ } |
|
468 | 501 |
if(client->keepalive) |
469 | 502 |
wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n"); |
470 | 503 |
wk_writestr((wk *)web,connid,"\r\n"); |
471 |
- return(wk_write((wk *)web,connid,data,datalen)); |
|
504 |
+ if(!cachedetag) |
|
505 |
+ return(wk_write((wk *)web,connid,data,datalen)); |
|
506 |
+ return(0); |
|
472 | 507 |
} |
473 | 508 |
|
474 | 509 |
int |
... | ... |
@@ -480,33 +515,47 @@ wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime) |
480 | 515 |
char buf[256]; |
481 | 516 |
sbuf *cookiebuf; |
482 | 517 |
struct stat st; |
518 |
+ int cachedetag; |
|
483 | 519 |
if(web==NULL || filename==NULL) |
484 | 520 |
return(-1); |
485 | 521 |
if((client=wk_clientget(web,connid))==NULL) |
486 | 522 |
return(-1); |
487 | 523 |
if(client->fdtoserve!=-1) |
488 | 524 |
close(client->fdtoserve),client->fdtoserve=-1; |
489 |
- if((client->fdtoserve=open(filename,O_RDONLY))==-1) { |
|
490 |
- wk_serve_error((wk *)web,connid,wkerr_notfound); |
|
491 |
- return(-1); |
|
492 |
- } |
|
493 |
- wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n"); |
|
525 |
+ cachedetag=(wk_etagnotmodified(web,client)==0)?1:0; |
|
526 |
+ if(!cachedetag) { |
|
527 |
+ if((client->fdtoserve=open(filename,O_RDONLY))==-1) { |
|
528 |
+ wk_serve_error((wk *)web,connid,wkerr_notfound); |
|
529 |
+ return(-1); |
|
530 |
+ } |
|
531 |
+ wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
|
532 |
+ } else |
|
533 |
+ wk_writestr((wk *)web,connid,"HTTP/1.1 304 Not modified\r\n"); |
|
494 | 534 |
if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) { |
495 | 535 |
if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 || |
496 | 536 |
sbuf_count(cookiebuf)!=0) |
497 | 537 |
return(-1); /* insufficient memory */ |
498 | 538 |
wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
499 | 539 |
} |
500 |
- if(fstat(client->fdtoserve,&st)==0) { |
|
501 |
- sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size); |
|
540 |
+ if(!cachedetag) { |
|
541 |
+ if(client->etag[0]!='\0') { |
|
542 |
+ sprintf(buf,"ETag: \"%s\"\r\n",client->etag); |
|
543 |
+ client->etag[0]='\0'; |
|
544 |
+ wk_writestr((wk *)web,connid,buf); |
|
545 |
+ } |
|
546 |
+ if(fstat(client->fdtoserve,&st)==0) { |
|
547 |
+ sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size); |
|
548 |
+ wk_writestr((wk *)web,connid,buf); |
|
549 |
+ } else |
|
550 |
+ client->keepalive=0; |
|
551 |
+ if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
552 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
553 |
+ else |
|
554 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
502 | 555 |
wk_writestr((wk *)web,connid,buf); |
503 |
- } else |
|
504 |
- client->keepalive=0; |
|
505 |
- if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
506 |
- sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
507 |
- else |
|
508 |
- sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
509 |
- wk_writestr((wk *)web,connid,buf); |
|
556 |
+ } else { |
|
557 |
+ wk_writestr((wk *)web,connid,"Content-Length: 0\r\n"); |
|
558 |
+ } |
|
510 | 559 |
if(client->keepalive) |
511 | 560 |
wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n"); |
512 | 561 |
wk_writestr((wk *)web,connid,"\r\n"); |
... | ... |
@@ -1051,6 +1100,7 @@ wk_clientacquire(_wk *web) |
1051 | 1100 |
client->fdtoserve=-1; |
1052 | 1101 |
client->headerbufid=-1; |
1053 | 1102 |
client->cookiebufid=-1; |
1103 |
+ client->etag[0]='\0'; |
|
1054 | 1104 |
return(client); |
1055 | 1105 |
} |
1056 | 1106 |
|
... | ... |
@@ -1225,6 +1275,9 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
1225 | 1275 |
client->uriready=1; |
1226 | 1276 |
client->continuationactive=0; |
1227 | 1277 |
client->status=wkc_header; |
1278 |
+ if(client->cookiebufid!=-1) |
|
1279 |
+ wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
|
1280 |
+ client->etag[0]='\0'; |
|
1228 | 1281 |
} |
1229 | 1282 |
return(0); |
1230 | 1283 |
} |
... | ... |
@@ -1431,4 +1484,21 @@ wk_postfree(_wk *web, wk_client *client) |
1431 | 1484 |
return(0); |
1432 | 1485 |
} |
1433 | 1486 |
|
1487 |
+static int |
|
1488 |
+wk_etagnotmodified(_wk *web, wk_client *client) |
|
1489 |
+{ |
|
1490 |
+ char *h; |
|
1491 |
+ int len; |
|
1492 |
+ int etaglen; |
|
1493 |
+ if(client->etag[0]=='\0') |
|
1494 |
+ return(-1); |
|
1495 |
+ if((h=wk_uri_getheader(&(client->uri),"If-None-Match",NULL))==NULL) |
|
1496 |
+ return(-1); |
|
1497 |
+ etaglen=strlen(client->etag); |
|
1498 |
+ if((len=strlen(h))<2 || h[0]!='\"' || h[len-1]!='\"') |
|
1499 |
+ return(-1); |
|
1500 |
+ if((len-2)!=etaglen || memcmp(h+1,client->etag,etaglen)!=0) |
|
1501 |
+ return(-1); |
|
1502 |
+ return(0); |
|
1503 |
+} |
|
1434 | 1504 |
|
... | ... |
@@ -24,7 +24,9 @@ |
24 | 24 |
#define CLIENTBLOCK 1024 |
25 | 25 |
#define CLIENTBLOCKBLOCK 256 |
26 | 26 |
#define MAXOUTBUF 128 |
27 |
+#ifndef BUFSIZE |
|
27 | 28 |
#define BUFSIZE 8192 |
29 |
+#endif |
|
28 | 30 |
#define BUFBLOCK 128 |
29 | 31 |
#define BUFBLOCKBLOCK 256 |
30 | 32 |
#define POSTBLOCK 16 |
... | ... |
@@ -146,6 +148,12 @@ wk_debug_io(char *iotype, int fd, char *ptr, long int size) |
146 | 148 |
#define DEBUG_OUT_POST |
147 | 149 |
#endif |
148 | 150 |
|
151 |
+#ifdef WK_DEBUG_CONN |
|
152 |
+#include "loglib.h" |
|
153 |
+#define DEBUG_CONN(a) log_write a |
|
154 |
+#else |
|
155 |
+#define DEBUG_CONN(a) |
|
156 |
+#endif |
|
149 | 157 |
|
150 | 158 |
wk * |
151 | 159 |
wk_init(int serverfd, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
... | ... |
@@ -386,8 +394,10 @@ wk_service(wk *paramweb) |
386 | 394 |
continue; |
387 | 395 |
if(client->lastio>now) |
388 | 396 |
client->lastio=now; |
389 |
- if((now-ALIVETIMEOUT)>client->lastio) |
|
397 |
+ if((now-ALIVETIMEOUT)>client->lastio) { |
|
398 |
+ DEBUG_CONN(("WEBK","TIMEOUT: Closing client connection; now:%li, ALIVETIMEOUT:%li, lastio:%li, diff:%li\n",(long)now,(long)ALIVETIMEOUT,(long)client->lastio,(long)(now-client->lastio))); |
|
390 | 399 |
wk_close((wk *)web, client->connid); /* timeout */ |
400 |
+ } |
|
391 | 401 |
} |
392 | 402 |
} |
393 | 403 |
} |
... | ... |
@@ -637,6 +647,7 @@ wk_close(wk *paramweb, int connid) |
637 | 647 |
return(-1); |
638 | 648 |
if((client=wk_clientget(web,connid))==NULL) |
639 | 649 |
return(-1); |
650 |
+ DEBUG_CONN(("WEBK","wk_close: connid: %i, fd: %i",connid,client->fd)); |
|
640 | 651 |
if(client->fd!=-1) { |
641 | 652 |
sselect_delread(web->ssel,client->fd); |
642 | 653 |
sselect_delwrite(web->ssel,client->fd); |
... | ... |
@@ -965,6 +976,7 @@ wk_accept(_wk *web) |
965 | 976 |
return(NULL); |
966 | 977 |
} |
967 | 978 |
client->fd=newfd; |
979 |
+ DEBUG_CONN(("WEBK","wk_accept: connid: %i, fd: %i",client->connid,client->fd)); |
|
968 | 980 |
FD_SET(client->fd,&(web->fdset)); |
969 | 981 |
sselect_addread(web->ssel,client->fd,(void *)client); |
970 | 982 |
return(client); |
... | ... |
@@ -148,15 +148,15 @@ wk_debug_io(char *iotype, int fd, char *ptr, long int size) |
148 | 148 |
|
149 | 149 |
|
150 | 150 |
wk * |
151 |
-wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
151 |
+wk_init(int serverfd, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
152 | 152 |
{ |
153 | 153 |
_wk *web; |
154 |
- if(ssel==NULL || callback_http==NULL) |
|
154 |
+ if(ssel==NULL || callback_http==NULL || serverfd==-1) |
|
155 | 155 |
return(NULL); |
156 | 156 |
if((web=malloc(sizeof(_wk)))==NULL) |
157 | 157 |
return(NULL); |
158 | 158 |
memset(web,0,sizeof(_wk)); |
159 |
- web->serverfd=-1; |
|
159 |
+ web->serverfd=serverfd; |
|
160 | 160 |
web->callback_event=callback_event; |
161 | 161 |
web->callback_http=callback_http; |
162 | 162 |
web->callback_post=callback_post; |
... | ... |
@@ -164,11 +164,6 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk |
164 | 164 |
web->userptr=userptr; |
165 | 165 |
web->ssel=ssel; |
166 | 166 |
FD_ZERO(&(web->fdset)); |
167 |
- if((web->serverfd=ipv4_server(port))==-1) { |
|
168 |
- wk_free((wk *)web),web=NULL; |
|
169 |
- return(NULL); |
|
170 |
- } |
|
171 |
- sock_setunsafe(web->serverfd); |
|
172 | 167 |
FD_SET(web->serverfd,&(web->fdset)); |
173 | 168 |
sselect_addread(ssel,web->serverfd,NULL); |
174 | 169 |
if(web->callback_event!=NULL) |
... | ... |
@@ -188,11 +183,10 @@ wk_free(wk *paramweb) |
188 | 183 |
return; |
189 | 184 |
if(web->callback_event!=NULL) |
190 | 185 |
web->callback_event((wk *)web,-1,wke_fini,web->userptr); |
191 |
- /* release server fds */ |
|
186 |
+ /* unregister the server fd */ |
|
192 | 187 |
if(web->serverfd!=-1) { |
193 | 188 |
sselect_delread(web->ssel,web->serverfd); |
194 | 189 |
FD_CLR(web->serverfd,&(web->fdset)); |
195 |
- close(web->serverfd),web->serverfd=-1; |
|
196 | 190 |
} |
197 | 191 |
/* release client fds and free clients */ |
198 | 192 |
for(i=0;i<web->usedclientblocks;i++) { |
... | ... |
@@ -665,7 +665,7 @@ wk_uri_getheader(wk_uri *uri, char *header, char *defaultvalue) |
665 | 665 |
if(uri==NULL || uri->headers==NULL || header==NULL) |
666 | 666 |
return(NULL); |
667 | 667 |
len=strlen(header); |
668 |
- for(n=0,ptr=uri->headers;*ptr!='\0';ptr++,n++) { |
|
668 |
+ for(n=0,ptr=uri->headers;*ptr!='\0';ptr+=strlen(ptr)+1,n++) { |
|
669 | 669 |
if(memcmp(ptr,header,len)==0 && ptr[len]==':' && ptr[len+1]==' ') |
670 | 670 |
return(ptr+len+2); |
671 | 671 |
} |
... | ... |
@@ -679,7 +679,7 @@ wk_uri_getheaderbynum(wk_uri *uri, int num) |
679 | 679 |
char *ptr; |
680 | 680 |
if(uri==NULL || uri->headers==NULL) |
681 | 681 |
return(NULL); |
682 |
- for(n=0,ptr=uri->headers;*ptr!='\0';ptr++,n++) { |
|
682 |
+ for(n=0,ptr=uri->headers;*ptr!='\0';ptr+=strlen(ptr)+1,n++) { |
|
683 | 683 |
if(n==num) |
684 | 684 |
return(ptr); |
685 | 685 |
} |
... | ... |
@@ -736,7 +736,7 @@ wk_uri_getcookie(wk_uri *uri, char *cookiename, int *len) |
736 | 736 |
if(uri==NULL || uri->headers==NULL || cookiename==NULL || len==NULL) |
737 | 737 |
return(NULL); |
738 | 738 |
namelen=strlen(cookiename); |
739 |
- for(n=0,header=uri->headers;*header!='\0';header++,n++) { |
|
739 |
+ for(n=0,header=uri->headers;*header!='\0';header+=strlen(header)+1,n++) { |
|
740 | 740 |
if(memcmp(header,"Cookie: ",8)!=0 && memcmp(header,"cookie: ",8)!=0) |
741 | 741 |
continue; |
742 | 742 |
for(ptr=header+8;*ptr!='\0';ptr=((*next!='\0')?next+1:next)) { |
... | ... |
@@ -764,7 +764,7 @@ wk_uri_getcookie(wk_uri *uri, char *cookiename, int *len) |
764 | 764 |
end--; |
765 | 765 |
/* cookie found, return it */ |
766 | 766 |
*len=end-sep; |
767 |
- return(ptr); |
|
767 |
+ return(sep); |
|
768 | 768 |
} |
769 | 769 |
} |
770 | 770 |
return(NULL); |
... | ... |
@@ -64,6 +64,7 @@ typedef struct wk_client { |
64 | 64 |
wk_post *post; |
65 | 65 |
int pendingpost; |
66 | 66 |
int inpostvar; |
67 |
+ int cookiebufid; |
|
67 | 68 |
time_t lastio; |
68 | 69 |
} wk_client; |
69 | 70 |
|
... | ... |
@@ -401,6 +402,39 @@ wk_service(wk *paramweb) |
401 | 402 |
return(0); |
402 | 403 |
} |
403 | 404 |
|
405 |
+int |
|
406 |
+wk_serve_cookieadd(wk *paramweb, int connid, char *cookiename, char *value, char *domain, int maxage, char *attributes) |
|
407 |
+{ |
|
408 |
+ _wk *web=(_wk *)paramweb; |
|
409 |
+ wk_client *client; |
|
410 |
+ sbuf *buf; |
|
411 |
+ char str[1024]; |
|
412 |
+ if(web==NULL || cookiename==NULL || (value==NULL && maxage>0)) |
|
413 |
+ return(-1); |
|
414 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
415 |
+ return(-1); |
|
416 |
+ if(client->cookiebufid==-1) { |
|
417 |
+ if((client->cookiebufid=wk_sbufacquire((wk *)web))==-1) |
|
418 |
+ return(-1); /* insufficient memory */ |
|
419 |
+ } |
|
420 |
+ if((buf=wk_sbufget((wk *)web,client->cookiebufid))==NULL) |
|
421 |
+ return(-1); /* internal error */ |
|
422 |
+ if(sbuf_count(buf)==0) { |
|
423 |
+ sbuf_addstr(buf,"Cache-control: no-cache=\"set-cookie\"\r\n"); |
|
424 |
+ sbuf_addstr(buf,"Expires: Tue, 01 Jan 1980 1:00:00 GMT\r\n"); |
|
425 |
+ } |
|
426 |
+ snprintf(str,sizeof(str)-1,"Set-Cookie: %s=%s %s%s%s; Max-Age=%i ; Version=1%s%s\r\n", |
|
427 |
+ cookiename,(value!=NULL)?value:"", |
|
428 |
+ (domain!=NULL)?"; Domain = ":"", |
|
429 |
+ (domain!=NULL && *domain!='.')?".":"", |
|
430 |
+ (domain!=NULL)?domain:"", |
|
431 |
+ maxage, |
|
432 |
+ (attributes!=NULL)?"; ":"",(attributes!=NULL)?attributes:""); |
|
433 |
+ sbuf_addstr(buf,str); |
|
434 |
+ return(0); |
|
435 |
+} |
|
436 |
+ |
|
437 |
+ |
|
404 | 438 |
int |
405 | 439 |
wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
406 | 440 |
{ |
... | ... |
@@ -408,11 +442,18 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const |
408 | 442 |
_wk *web=(_wk *)paramweb; |
409 | 443 |
wk_client *client; |
410 | 444 |
char buf[256]; |
445 |
+ sbuf *cookiebuf; |
|
411 | 446 |
if(web==NULL) |
412 | 447 |
return(-1); |
413 | 448 |
if((client=wk_clientget(web,connid))==NULL) |
414 | 449 |
return(-1); |
415 | 450 |
wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
451 |
+ if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) { |
|
452 |
+ if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 || |
|
453 |
+ sbuf_count(cookiebuf)!=0) |
|
454 |
+ return(-1); /* insufficient memory */ |
|
455 |
+ wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
|
456 |
+ } |
|
416 | 457 |
sprintf(buf,"Content-Length: %i\r\n",datalen); |
417 | 458 |
wk_writestr((wk *)web,connid,buf); |
418 | 459 |
if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
... | ... |
@@ -433,6 +474,7 @@ wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime) |
433 | 474 |
_wk *web=(_wk *)paramweb; |
434 | 475 |
wk_client *client; |
435 | 476 |
char buf[256]; |
477 |
+ sbuf *cookiebuf; |
|
436 | 478 |
struct stat st; |
437 | 479 |
if(web==NULL || filename==NULL) |
438 | 480 |
return(-1); |
... | ... |
@@ -445,6 +487,12 @@ wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime) |
445 | 487 |
return(-1); |
446 | 488 |
} |
447 | 489 |
wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n"); |
490 |
+ if(client->cookiebufid!=-1 && (cookiebuf=wk_sbufget((wk *)web,client->cookiebufid))!=NULL) { |
|
491 |
+ if(wk_write((wk *)web,connid,sbuf_getbytes(cookiebuf,sbuf_count(cookiebuf)),sbuf_count(cookiebuf))==-1 || |
|
492 |
+ sbuf_count(cookiebuf)!=0) |
|
493 |
+ return(-1); /* insufficient memory */ |
|
494 |
+ wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
|
495 |
+ } |
|
448 | 496 |
if(fstat(client->fdtoserve,&st)==0) { |
449 | 497 |
sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size); |
450 | 498 |
wk_writestr((wk *)web,connid,buf); |
... | ... |
@@ -675,6 +723,65 @@ wk_uri_copyvar(wk_uri *uri, char *varname, char *dest, int destlen) |
675 | 723 |
return(dest); |
676 | 724 |
} |
677 | 725 |
|
726 |
+char * |
|
727 |
+wk_uri_getcookie(wk_uri *uri, char *cookiename, int *len) |
|
728 |
+{ |
|
729 |
+ int n; |
|
730 |
+ char *header; |
|
731 |
+ int namelen; |
|
732 |
+ char *ptr; |
|
733 |
+ char *sep; |
|
734 |
+ char *end; |
|
735 |
+ char *next; |
|
736 |
+ if(uri==NULL || uri->headers==NULL || cookiename==NULL || len==NULL) |
|
737 |
+ return(NULL); |
|
738 |
+ namelen=strlen(cookiename); |
|
739 |
+ for(n=0,header=uri->headers;*header!='\0';header++,n++) { |
|
740 |
+ if(memcmp(header,"Cookie: ",8)!=0 && memcmp(header,"cookie: ",8)!=0) |
|
741 |
+ continue; |
|
742 |
+ for(ptr=header+8;*ptr!='\0';ptr=((*next!='\0')?next+1:next)) { |
|
743 |
+ /* cookies are separated by ',' or ';' */ |
|
744 |
+ next=strchr(ptr,';'); |
|
745 |
+ if(next==NULL) |
|
746 |
+ next=ptr+strlen(ptr); |
|
747 |
+ if((sep=strchr(ptr,','))!=NULL && sep<next) |
|
748 |
+ next=sep; |
|
749 |
+ /* trim cookie name */ |
|
750 |
+ while(*ptr==' ') |
|
751 |
+ ptr++; |
|
752 |
+ /* check for our cookie and search for the value pos */ |
|
753 |
+ if(memcmp(ptr,cookiename,namelen)!=0) |
|
754 |
+ continue; /* not our cookie */ |
|
755 |
+ for(sep=ptr+namelen;*sep==' ';sep++) |
|
756 |
+ ; |
|
757 |
+ if(*sep!='=') |
|
758 |
+ continue; /* was partial match or unrecognized cookie format */ |
|
759 |
+ /* skip '=' and trim value */ |
|
760 |
+ sep++; |
|
761 |
+ while(*sep==' ') |
|
762 |
+ sep++; |
|
763 |
+ for(end=next;end>sep && end[-1]==' ';) |
|
764 |
+ end--; |
|
765 |
+ /* cookie found, return it */ |
|
766 |
+ *len=end-sep; |
|
767 |
+ return(ptr); |
|
768 |
+ } |
|
769 |
+ } |
|
770 |
+ return(NULL); |
|
771 |
+} |
|
772 |
+ |
|
773 |
+char * |
|
774 |
+wk_uri_copycookie(wk_uri *uri, char *cookiename, char *dest, int destlen) |
|
775 |
+{ |
|
776 |
+ char *value; |
|
777 |
+ int len; |
|
778 |
+ if(dest==NULL || destlen<1 || (value=wk_uri_getcookie(uri,cookiename,&len))==NULL) |
|
779 |
+ return(NULL); |
|
780 |
+ memcpy(dest,value,(len<(destlen-1))?len:destlen-1); |
|
781 |
+ dest[(len<(destlen-1))?len:destlen-1]='\0'; |
|
782 |
+ return(dest); |
|
783 |
+} |
|
784 |
+ |
|
678 | 785 |
|
679 | 786 |
int |
680 | 787 |
wk_post_addvalid(wk *paramweb, int connid, char *varname, char *tofile) |
... | ... |
@@ -937,6 +1044,7 @@ wk_clientacquire(_wk *web) |
937 | 1044 |
client->usedoutbufids=1; |
938 | 1045 |
client->fdtoserve=-1; |
939 | 1046 |
client->headerbufid=-1; |
1047 |
+ client->cookiebufid=-1; |
|
940 | 1048 |
return(client); |
941 | 1049 |
} |
942 | 1050 |
|
... | ... |
@@ -959,6 +1067,8 @@ wk_clientrelease(_wk *web, int connid) |
959 | 1067 |
wk_sbufrelease((wk *)web,client->outbufids[w]),client->outbufids[w]=-1; |
960 | 1068 |
if(client->headerbufid!=-1) |
961 | 1069 |
wk_sbufrelease((wk *)web,client->headerbufid),client->headerbufid=-1; |
1070 |
+ if(client->cookiebufid!=-1) |
|
1071 |
+ wk_sbufrelease((wk *)web,client->cookiebufid),client->cookiebufid=-1; |
|
962 | 1072 |
wk_postfree(web,client); |
963 | 1073 |
memset(client,0,sizeof(wk_client)); |
964 | 1074 |
return(0); |
... | ... |
@@ -15,6 +15,7 @@ |
15 | 15 |
#include <sys/types.h> |
16 | 16 |
#include <sys/stat.h> |
17 | 17 |
#include <fcntl.h> |
18 |
+#include <time.h> |
|
18 | 19 |
#include "sbuf.h" |
19 | 20 |
#include "socklib.h" |
20 | 21 |
#include "webkernel.h" |
... | ... |
@@ -27,6 +28,7 @@ |
27 | 28 |
#define BUFBLOCK 128 |
28 | 29 |
#define BUFBLOCKBLOCK 256 |
29 | 30 |
#define POSTBLOCK 16 |
31 |
+#define ALIVETIMEOUT 15 |
|
30 | 32 |
|
31 | 33 |
typedef struct wk_post { |
32 | 34 |
char *name; |
... | ... |
@@ -62,6 +64,7 @@ typedef struct wk_client { |
62 | 64 |
wk_post *post; |
63 | 65 |
int pendingpost; |
64 | 66 |
int inpostvar; |
67 |
+ time_t lastio; |
|
65 | 68 |
} wk_client; |
66 | 69 |
|
67 | 70 |
typedef struct wk_clientblock { |
... | ... |
@@ -98,6 +101,7 @@ typedef struct _wk { |
98 | 101 |
wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
99 | 102 |
wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
100 | 103 |
void *userptr; |
104 |
+ time_t lasttimeoutcheck; |
|
101 | 105 |
} _wk; |
102 | 106 |
|
103 | 107 |
static wk_client *wk_accept(_wk *web); |
... | ... |
@@ -256,21 +260,27 @@ wk_service(wk *paramweb) |
256 | 260 |
{ |
257 | 261 |
int fds[FDBLOCK]; |
258 | 262 |
int fd; |
259 |
- int n,i; |
|
263 |
+ int n,i,j,k; |
|
260 | 264 |
sbuf *in; |
261 | 265 |
sbuf *out; |
262 | 266 |
_wk *web=(_wk *)paramweb; |
263 | 267 |
wk_client *client; |
268 |
+ wk_clientblock *cb; |
|
269 |
+ time_t now; |
|
264 | 270 |
if(web==NULL) |
265 | 271 |
return(-1); |
272 |
+ now=time(NULL); |
|
266 | 273 |
while((n=sselect_getreadfiltered(web->ssel,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
267 | 274 |
for(i=0;i<n;i++) { |
268 | 275 |
fd=fds[i]; |
269 | 276 |
if(fd==web->serverfd) { |
270 | 277 |
do { |
271 | 278 |
/* accept new connection */ |
272 |
- if((client=wk_accept(web))!=NULL && web->callback_event!=NULL) |
|
273 |
- web->callback_event((wk *)web,client->connid,wke_connected,web->userptr); |
|
279 |
+ if((client=wk_accept(web))!=NULL) { |
|
280 |
+ if(web->callback_event!=NULL) |
|
281 |
+ web->callback_event((wk *)web,client->connid,wke_connected,web->userptr); |
|
282 |
+ client->lastio=now; |
|
283 |
+ } |
|
274 | 284 |
} while(sock_readable(fd)==0); |
275 | 285 |
continue; /* all done here */ |
276 | 286 |
} |
... | ... |
@@ -296,6 +306,7 @@ wk_service(wk *paramweb) |
296 | 306 |
continue; |
297 | 307 |
} |
298 | 308 |
DEBUG_IN_POST; |
309 |
+ client->lastio=now; |
|
299 | 310 |
if(client->status==wkc_header) { |
300 | 311 |
if(wk_clientservicereadheader(web,client)==-1) { |
301 | 312 |
/* internal error, protocol error or no enough memory */ |
... | ... |
@@ -325,7 +336,8 @@ wk_service(wk *paramweb) |
325 | 336 |
continue; /* internal error */ |
326 | 337 |
} |
327 | 338 |
DEBUG_OUT_PRE; |
328 |
- sbuf_send(out,fd,sbuf_count(out)); |
|
339 |
+ if(sbuf_send(out,fd,sbuf_count(out))>0) |
|
340 |
+ client->lastio=now; |
|
329 | 341 |
DEBUG_OUT_POST; |
330 | 342 |
/* if we are serving from file, load the next chunk */ |
331 | 343 |
if(client->fdtoserve!=-1 && client->usedoutbufids==1) { |
... | ... |
@@ -359,6 +371,33 @@ wk_service(wk *paramweb) |
359 | 371 |
} |
360 | 372 |
} |
361 | 373 |
} |
374 |
+ /* timeout check */ |
|
375 |
+ if(web->lasttimeoutcheck>now) |
|
376 |
+ web->lasttimeoutcheck=now; /* fix time warp */ |
|
377 |
+ if((now-(ALIVETIMEOUT/2))>web->lasttimeoutcheck) { |
|
378 |
+ web->lasttimeoutcheck=now; |
|
379 |
+ for(i=0;i<web->usedclientblocks;i++) { |
|
380 |
+ cb=web->clientblocks+i; |
|
381 |
+ if(cb->clients==NULL) |
|
382 |
+ continue; |
|
383 |
+ for(j=0;j<cb->sizeclients;j+=8) { |
|
384 |
+ if(cb->acquired[j>>3]==0) |
|
385 |
+ continue; |
|
386 |
+ for(k=0x1,n=0;n<8;n++,k<<=1) { |
|
387 |
+ if(!(cb->acquired[j>>3]&k)) |
|
388 |
+ continue; |
|
389 |
+ client=cb->clients+j+n; |
|
390 |
+ if(client->fd==-1) |
|
391 |
+ continue; |
|
392 |
+ if(client->lastio>now) |
|
393 |
+ client->lastio=now; |
|
394 |
+ if((now-ALIVETIMEOUT)>client->lastio) |
|
395 |
+ wk_close((wk *)web, client->connid); /* timeout */ |
|
396 |
+ } |
|
397 |
+ } |
|
398 |
+ } |
|
399 |
+ |
|
400 |
+ } |
|
362 | 401 |
return(0); |
363 | 402 |
} |
364 | 403 |
|
... | ... |
@@ -1028,11 +1067,11 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
1028 | 1067 |
return(-1); /* header not in format "name: value" */ |
1029 | 1068 |
/* check for keepalive header */ |
1030 | 1069 |
if(memcmp(ptr,"Connection: ",12)==0) { |
1031 |
- if(strcmp(ptr+12,"keep-alive")==0 || strcmp(ptr+12,"Keep-Alive")==0) |
|
1070 |
+ if(strcmp(ptr+12,"keep-alive")==0 || strcmp(ptr+12,"Keep-Alive")==0) |
|
1032 | 1071 |
client->keepalive=1; |
1033 | 1072 |
else if(strcmp(ptr+12,"close")==0 || strcmp(ptr+12,"Close")==0) |
1034 | 1073 |
client->keepalive=0; |
1035 |
- } |
|
1074 |
+ } |
|
1036 | 1075 |
sbuf_add(hbuf,ptr,strlen(ptr)+1); |
1037 | 1076 |
ptr+=strlen(ptr)+1; |
1038 | 1077 |
} |
... | ... |
@@ -1027,9 +1027,12 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
1027 | 1027 |
if((sep=strchr(ptr,':'))==NULL || sep[1]!=' ') |
1028 | 1028 |
return(-1); /* header not in format "name: value" */ |
1029 | 1029 |
/* check for keepalive header */ |
1030 |
- if(memcmp(ptr,"Connection: ",12)==0 && |
|
1031 |
- (strcmp(ptr+12,"keep-alive")==0 || strcmp(ptr+12,"Keep-Alive")==0)) |
|
1030 |
+ if(memcmp(ptr,"Connection: ",12)==0) { |
|
1031 |
+ if(strcmp(ptr+12,"keep-alive")==0 || strcmp(ptr+12,"Keep-Alive")==0) |
|
1032 | 1032 |
client->keepalive=1; |
1033 |
+ else if(strcmp(ptr+12,"close")==0 || strcmp(ptr+12,"Close")==0) |
|
1034 |
+ client->keepalive=0; |
|
1035 |
+ } |
|
1033 | 1036 |
sbuf_add(hbuf,ptr,strlen(ptr)+1); |
1034 | 1037 |
ptr+=strlen(ptr)+1; |
1035 | 1038 |
} |
... | ... |
@@ -111,6 +111,37 @@ static int wk_postset(_wk *web, wk_client *client,char *varname, char *data, int |
111 | 111 |
static char *wk_postget(_wk *web, wk_client *client,char *varname, int *isfile); |
112 | 112 |
static int wk_postfree(_wk *web, wk_client *client); |
113 | 113 |
|
114 |
+#ifdef WK_DEBUG_IO |
|
115 |
+#define DEBUG_IN_PRE { int sbp=sbuf_count(in); |
|
116 |
+#define DEBUG_IN_POST wk_debug_io("READ",fd,sbuf_ptr(in)+sbp,sbuf_count(in)-sbp); } |
|
117 |
+#define DEBUG_OUT_PRE { int sbu=out->got; |
|
118 |
+#define DEBUG_OUT_POST wk_debug_io("WRITTEN",fd,out->buf+sbu,out->got-sbu); } |
|
119 |
+ |
|
120 |
+static void |
|
121 |
+wk_debug_io(char *iotype, int fd, char *ptr, long int size) |
|
122 |
+{ |
|
123 |
+ int n,c; |
|
124 |
+ fprintf(stderr,"%s %li bytes on %i:",iotype,size,fd); |
|
125 |
+ for(n=0;n<size;n++) { |
|
126 |
+ c=((unsigned char *)ptr)[n]; |
|
127 |
+ if(c=='\r' || c=='\n') |
|
128 |
+ fprintf(stderr,"\\%c",(c=='\r')?'r':'n'); |
|
129 |
+ else if(c<' ' || c>'~') |
|
130 |
+ fprintf(stderr,"\\x%02X",c); |
|
131 |
+ else |
|
132 |
+ fprintf(stderr,"%c",c); |
|
133 |
+ } |
|
134 |
+ fprintf(stderr,"\n"); |
|
135 |
+} |
|
136 |
+ |
|
137 |
+#else |
|
138 |
+#define DEBUG_IN_PRE |
|
139 |
+#define DEBUG_IN_POST |
|
140 |
+#define DEBUG_OUT_PRE |
|
141 |
+#define DEBUG_OUT_POST |
|
142 |
+#endif |
|
143 |
+ |
|
144 |
+ |
|
114 | 145 |
wk * |
115 | 146 |
wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
116 | 147 |
{ |
... | ... |
@@ -236,13 +267,16 @@ wk_service(wk *paramweb) |
236 | 267 |
for(i=0;i<n;i++) { |
237 | 268 |
fd=fds[i]; |
238 | 269 |
if(fd==web->serverfd) { |
239 |
- /* accept new connection */ |
|
240 |
- if((client=wk_accept(web))!=NULL && web->callback_event!=NULL) |
|
241 |
- web->callback_event((wk *)web,client->connid,wke_connected,web->userptr); |
|
270 |
+ do { |
|
271 |
+ /* accept new connection */ |
|
272 |
+ if((client=wk_accept(web))!=NULL && web->callback_event!=NULL) |
|
273 |
+ web->callback_event((wk *)web,client->connid,wke_connected,web->userptr); |
|
274 |
+ } while(sock_readable(fd)==0); |
|
242 | 275 |
continue; /* all done here */ |
243 | 276 |
} |
244 | 277 |
if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) { |
245 |
- wk_close((wk *)web,client->connid); |
|
278 |
+ sselect_delread(web->ssel,fd); |
|
279 |
+ close(fd),fd=-1; |
|
246 | 280 |
continue; /* internal error */ |
247 | 281 |
} |
248 | 282 |
if((in=wk_sbufget((wk *) web,client->inbufid))==NULL) { |
... | ... |
@@ -255,11 +289,13 @@ wk_service(wk *paramweb) |
255 | 289 |
sselect_delread(web->ssel,fd); |
256 | 290 |
continue; |
257 | 291 |
} |
292 |
+ DEBUG_IN_PRE; |
|
258 | 293 |
if(sbuf_fill(in,fd,sock_queued(fd))==0) { |
259 | 294 |
/* client has closed connection */ |
260 | 295 |
wk_close((wk *) web, client->connid); |
261 | 296 |
continue; |
262 | 297 |
} |
298 |
+ DEBUG_IN_POST; |
|
263 | 299 |
if(client->status==wkc_header) { |
264 | 300 |
if(wk_clientservicereadheader(web,client)==-1) { |
265 | 301 |
/* internal error, protocol error or no enough memory */ |
... | ... |
@@ -288,7 +324,9 @@ wk_service(wk *paramweb) |
288 | 324 |
wk_close((wk *)web,client->connid); |
289 | 325 |
continue; /* internal error */ |
290 | 326 |
} |
327 |
+ DEBUG_OUT_PRE; |
|
291 | 328 |
sbuf_send(out,fd,sbuf_count(out)); |
329 |
+ DEBUG_OUT_POST; |
|
292 | 330 |
/* if we are serving from file, load the next chunk */ |
293 | 331 |
if(client->fdtoserve!=-1 && client->usedoutbufids==1) { |
294 | 332 |
sbuf_discard(out); |
... | ... |
@@ -314,8 +352,8 @@ wk_service(wk *paramweb) |
314 | 352 |
client->continuationactive=web->callback_continuation((wk *)web,client->connid,&(client->uri),web->userptr); |
315 | 353 |
} else { |
316 | 354 |
client->uriready=0; /* we have finished servicing this one */ |
317 |
- if(!client->keepalive) |
|
318 |
- wk_close((wk *)web, fd); /* all sent */ |
|
355 |
+ if(client->keepalive==0) |
|
356 |
+ wk_close((wk *)web, client->connid); /* all sent */ |
|
319 | 357 |
} |
320 | 358 |
} |
321 | 359 |
} |
... | ... |
@@ -335,7 +373,7 @@ wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const |
335 | 373 |
return(-1); |
336 | 374 |
if((client=wk_clientget(web,connid))==NULL) |
337 | 375 |
return(-1); |
338 |
- wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n"); |
|
376 |
+ wk_writestr((wk *)web,connid,"HTTP/1.0 200 OK\r\n"); |
|
339 | 377 |
sprintf(buf,"Content-Length: %i\r\n",datalen); |
340 | 378 |
wk_writestr((wk *)web,connid,buf); |
341 | 379 |
if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
... | ... |
@@ -744,7 +782,7 @@ wk_sbufrelease(wk *paramweb, int sbufid) |
744 | 782 |
return(-1); |
745 | 783 |
numblock=sbufid/BUFBLOCK; |
746 | 784 |
j=sbufid%BUFBLOCK; |
747 |
- bit=0x1<<(j&3); |
|
785 |
+ bit=0x1<<(j&7); |
|
748 | 786 |
if((buf=wk_sbufget(web,sbufid))==NULL) |
749 | 787 |
return(-1); |
750 | 788 |
web->bufblocks[numblock].usedbufs--; |
... | ... |
@@ -763,7 +801,7 @@ wk_sbufget(wk *paramweb, int sbufid) |
763 | 801 |
return(NULL); |
764 | 802 |
numblock=sbufid/BUFBLOCK; |
765 | 803 |
j=sbufid%BUFBLOCK; |
766 |
- bit=0x1<<(j&3); |
|
804 |
+ bit=0x1<<(j&7); |
|
767 | 805 |
if(web==NULL || |
768 | 806 |
web->bufblocks==NULL || |
769 | 807 |
web->sizebufblocks<=numblock || |
... | ... |
@@ -871,7 +909,7 @@ wk_clientrelease(_wk *web, int connid) |
871 | 909 |
int w; |
872 | 910 |
numblock=connid/CLIENTBLOCK; |
873 | 911 |
j=connid%CLIENTBLOCK; |
874 |
- bit=0x1<<(j&3); |
|
912 |
+ bit=0x1<<(j&7); |
|
875 | 913 |
if((client=wk_clientget(web,connid))==NULL) |
876 | 914 |
return(-1); |
877 | 915 |
web->clientblocks[numblock].usedclients--; |
... | ... |
@@ -893,7 +931,7 @@ wk_clientget(_wk *web, int connid) |
893 | 931 |
int numblock,j,bit; |
894 | 932 |
numblock=connid/CLIENTBLOCK; |
895 | 933 |
j=connid%CLIENTBLOCK; |
896 |
- bit=0x1<<(j&3); |
|
934 |
+ bit=0x1<<(j&7); |
|
897 | 935 |
if(web==NULL || |
898 | 936 |
web->clientblocks==NULL || |
899 | 937 |
web->sizeclientblocks<=numblock || |
... | ... |
@@ -974,7 +1012,10 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
974 | 1012 |
/* headers */ |
975 | 1013 |
*end='\0'; |
976 | 1014 |
uri->headers=sbuf_ptrunused(hbuf); |
977 |
- client->keepalive=0; |
|
1015 |
+ if(strcmp(uri->protocol,"HTTP/0.9")==0 || strcmp(uri->protocol,"HTTP/1.0")==0) |
|
1016 |
+ client->keepalive=0; |
|
1017 |
+ else |
|
1018 |
+ client->keepalive=1; /* default for http/1.1 */ |
|
978 | 1019 |
while(ptr<end) { |
979 | 1020 |
if(*ptr!='\n') |
980 | 1021 |
return(-1); /* line is not ended with \r\n */ |
... | ... |
@@ -994,6 +1035,8 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
994 | 1035 |
} |
995 | 1036 |
/* add header terminator */ |
996 | 1037 |
sbuf_add(hbuf,"",1); |
1038 |
+ /* mark data as used */ |
|
1039 |
+ sbuf_getbytes(in,end-sbuf_ptr(in)+4); |
|
997 | 1040 |
/* call the http method */ |
998 | 1041 |
client->uriready=1; |
999 | 1042 |
client->continuationactive=0; |
... | ... |
@@ -67,7 +67,7 @@ typedef struct wk_client { |
67 | 67 |
typedef struct wk_clientblock { |
68 | 68 |
int sizeclients; |
69 | 69 |
int usedclients; |
70 |
- unsigned char acquired[CLIENTBLOCKBLOCK/8]; |
|
70 |
+ unsigned char acquired[CLIENTBLOCK/8]; |
|
71 | 71 |
wk_client *clients; |
72 | 72 |
} wk_clientblock; |
73 | 73 |
|
... | ... |
@@ -169,7 +169,7 @@ wk_free(wk *paramweb) |
169 | 169 |
for(k=0x1,n=0;n<8;n++,k<<=1) { |
170 | 170 |
if(!(cb->acquired[j>>3]&k)) |
171 | 171 |
continue; |
172 |
- client=cb->clients+j+k; |
|
172 |
+ client=cb->clients+j+n; |
|
173 | 173 |
if(client->fd!=-1) { |
174 | 174 |
sselect_delread(web->ssel,client->fd); |
175 | 175 |
sselect_delwrite(web->ssel,client->fd); |
... | ... |
@@ -821,6 +821,7 @@ wk_clientacquire(_wk *web) |
821 | 821 |
if((cb->clients=malloc(sizeof(wk_client)*CLIENTBLOCK))==NULL) |
822 | 822 |
return(NULL); /* insufficient memory */ |
823 | 823 |
memset(cb->clients,0,sizeof(wk_client)*CLIENTBLOCK); |
824 |
+ memset(cb->acquired,0,sizeof(cb->acquired)); |
|
824 | 825 |
cb->sizeclients=CLIENTBLOCK; |
825 | 826 |
cb->usedclients=0; |
826 | 827 |
web->usedclientblocks++; |
... | ... |
@@ -433,6 +433,19 @@ The request was not understood or is not allowed by this server.\r\n\ |
433 | 433 |
int |
434 | 434 |
wk_serve_redirect(wk *paramweb, int connid, char *newlocation) |
435 | 435 |
{ |
436 |
+ static const char strredirect1[]={"\ |
|
437 |
+HTTP/1.1 307 Temporary Redirect\r\n\ |
|
438 |
+Content-Type: text/html\r\n\ |
|
439 |
+Content-Length: 114\r\n\ |
|
440 |
+Location: " |
|
441 |
+}; |
|
442 |
+ static const char strredirect2[]={"\ |
|
443 |
+\r\n\ |
|
444 |
+\r\n\ |
|
445 |
+<title>307 Temporary Redirect</title>\r\n\ |
|
446 |
+<h1>307 Temporary Redirect</h1>\r\n\ |
|
447 |
+The requsted page was moved temporarily.\r\n\ |
|
448 |
+"}; |
|
436 | 449 |
int res; |
437 | 450 |
int total; |
438 | 451 |
_wk *web=(_wk *)paramweb; |
... | ... |
@@ -442,13 +455,13 @@ wk_serve_redirect(wk *paramweb, int connid, char *newlocation) |
442 | 455 |
if((client=wk_clientget(web,connid))==NULL || newlocation==NULL || newlocation[0]=='\0') |
443 | 456 |
return(-1); |
444 | 457 |
total=0; |
445 |
- if((res=wk_writestr((wk *)web,connid,"HTTP/1.1 302 Found\r\nLocation: "))<0) |
|
458 |
+ if((res=wk_writestr((wk *)web,connid,strredirect1))<0) |
|
446 | 459 |
return(-1); |
447 | 460 |
total+=res; |
448 | 461 |
if((res=wk_writestr((wk *)web,connid,newlocation))<0) |
449 | 462 |
return(-1); |
450 | 463 |
total+=res; |
451 |
- if((res=wk_writestr((wk *)web,connid,"\r\n\r\n\r\n"))<0) |
|
464 |
+ if((res=wk_writestr((wk *)web,connid,strredirect2))<0) |
|
452 | 465 |
return(-1); |
453 | 466 |
total+=res; |
454 | 467 |
return(total); |
... | ... |
@@ -448,7 +448,7 @@ wk_serve_redirect(wk *paramweb, int connid, char *newlocation) |
448 | 448 |
if((res=wk_writestr((wk *)web,connid,newlocation))<0) |
449 | 449 |
return(-1); |
450 | 450 |
total+=res; |
451 |
- if((res=wk_writestr((wk *)web,connid,"\r\n\r\n"))<0) |
|
451 |
+ if((res=wk_writestr((wk *)web,connid,"\r\n\r\n\r\n"))<0) |
|
452 | 452 |
return(-1); |
453 | 453 |
total+=res; |
454 | 454 |
return(total); |
... | ... |
@@ -430,6 +430,31 @@ The request was not understood or is not allowed by this server.\r\n\ |
430 | 430 |
return(res); |
431 | 431 |
} |
432 | 432 |
|
433 |
+int |
|
434 |
+wk_serve_redirect(wk *paramweb, int connid, char *newlocation) |
|
435 |
+{ |
|
436 |
+ int res; |
|
437 |
+ int total; |
|
438 |
+ _wk *web=(_wk *)paramweb; |
|
439 |
+ wk_client *client; |
|
440 |
+ if(web==NULL) |
|
441 |
+ return(-1); |
|
442 |
+ if((client=wk_clientget(web,connid))==NULL || newlocation==NULL || newlocation[0]=='\0') |
|
443 |
+ return(-1); |
|
444 |
+ total=0; |
|
445 |
+ if((res=wk_writestr((wk *)web,connid,"HTTP/1.1 302 Found\r\nLocation: "))<0) |
|
446 |
+ return(-1); |
|
447 |
+ total+=res; |
|
448 |
+ if((res=wk_writestr((wk *)web,connid,newlocation))<0) |
|
449 |
+ return(-1); |
|
450 |
+ total+=res; |
|
451 |
+ if((res=wk_writestr((wk *)web,connid,"\r\n\r\n"))<0) |
|
452 |
+ return(-1); |
|
453 |
+ total+=res; |
|
454 |
+ return(total); |
|
455 |
+} |
|
456 |
+ |
|
457 |
+ |
|
433 | 458 |
int |
434 | 459 |
wk_writestr(wk *paramweb, int connid, const char *str) |
435 | 460 |
{ |
... | ... |
@@ -40,7 +40,6 @@ typedef struct wk_post { |
40 | 40 |
typedef enum wkc_status { |
41 | 41 |
wkc_header=0, |
42 | 42 |
wkc_post, |
43 |
- wkc_none, |
|
44 | 43 |
} wkc_status; |
45 | 44 |
|
46 | 45 |
typedef struct wk_client { |
... | ... |
@@ -51,13 +50,13 @@ typedef struct wk_client { |
51 | 50 |
int sizeoutbufids; |
52 | 51 |
int usedoutbufids; |
53 | 52 |
int outbufids[MAXOUTBUF]; |
54 |
- wkc_status status; |
|
55 |
- int serviced; |
|
56 |
- int continuationactive; |
|
57 |
- int fdtoserve; |
|
53 |
+ int uriready; |
|
58 | 54 |
wk_uri uri; |
59 | 55 |
int headerbufid; |
56 |
+ wkc_status status; |
|
60 | 57 |
int keepalive; |
58 |
+ int continuationactive; |
|
59 |
+ int fdtoserve; |
|
61 | 60 |
int sizepost; |
62 | 61 |
int usedpost; |
63 | 62 |
wk_post *post; |
... | ... |
@@ -216,7 +215,7 @@ wk_geturi(wk *paramweb, int connid) |
216 | 215 |
return(NULL); |
217 | 216 |
if((client=wk_clientget(web,connid))==NULL) |
218 | 217 |
return(NULL); |
219 |
- if(client->serviced==0) |
|
218 |
+ if(client->uriready==0) |
|
220 | 219 |
return(NULL); |
221 | 220 |
return(&(client->uri)); |
222 | 221 |
} |
... | ... |
@@ -314,7 +313,7 @@ wk_service(wk *paramweb) |
314 | 313 |
if(client->continuationactive && web->callback_continuation!=NULL) { |
315 | 314 |
client->continuationactive=web->callback_continuation((wk *)web,client->connid,&(client->uri),web->userptr); |
316 | 315 |
} else { |
317 |
- client->serviced=0; /* we have finished servicing this one */ |
|
316 |
+ client->uriready=0; /* we have finished servicing this one */ |
|
318 | 317 |
if(!client->keepalive) |
319 | 318 |
wk_close((wk *)web, fd); /* all sent */ |
320 | 319 |
} |
... | ... |
@@ -886,16 +885,8 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
886 | 885 |
char *sep; |
887 | 886 |
wk_uri *uri; |
888 | 887 |
wk_action action; |
889 |
- /* check if we have all the headers */ |
|
890 | 888 |
if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
891 | 889 |
return(-1); /* internal error */ |
892 |
- if((end=str_findfirstempty(sbuf_ptr(in),sbuf_count(in)))==NULL) { |
|
893 |
- sbuf_discard(in); |
|
894 |
- if(sbuf_unused(in)==0) |
|
895 |
- return(-1); /* header part too long */ |
|
896 |
- /* incomplete headers, have to wait for more data */ |
|
897 |
- return(0); |
|
898 |
- } |
|
899 | 890 |
/* get memory for the uri data */ |
900 | 891 |
if(client->headerbufid!=-1) |
901 | 892 |
wk_sbufrelease((wk *)web,client->headerbufid),client->headerbufid=-1; |
... | ... |
@@ -903,7 +894,17 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
903 | 894 |
return(-1); /* insufficient memory */ |
904 | 895 |
if((hbuf=wk_sbufget((wk *)web,client->headerbufid))==NULL) |
905 | 896 |
return(-1); /* internal error */ |
897 |
+ /* check if we have all the headers */ |
|
898 |
+ if((end=str_findfirstempty(sbuf_ptr(in),sbuf_count(in)))==NULL) { |
|
899 |
+ sbuf_discard(in); |
|
900 |
+ if(sbuf_unused(in)==0) |
|
901 |
+ return(-1); /* header part too long */ |
|
902 |
+ /* incomplete headers, have to wait for more data */ |
|
903 |
+ return(0); |
|
904 |
+ } |
|
906 | 905 |
/* prepare to fill the uri struct */ |
906 |
+ client->uriready=0; |
|
907 |
+ sbuf_wipe(hbuf); |
|
907 | 908 |
uri=&(client->uri); |
908 | 909 |
memset(uri,0,sizeof(wk_uri)); |
909 | 910 |
/* check that the method is supported */ |
... | ... |
@@ -955,13 +956,13 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
955 | 956 |
/* add header terminator */ |
956 | 957 |
sbuf_add(hbuf,"",1); |
957 | 958 |
/* call the http method */ |
958 |
- client->serviced=1; |
|
959 |
+ client->uriready=1; |
|
959 | 960 |
client->continuationactive=0; |
960 | 961 |
action=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
961 | 962 |
if(action==wkact_continuation) { |
962 |
- client->serviced=1; |
|
963 |
+ client->uriready=1; |
|
963 | 964 |
client->continuationactive=1; |
964 |
- client->status=wkc_none; |
|
965 |
+ client->status=wkc_header; |
|
965 | 966 |
} else if(action==wkact_post && web->callback_post!=NULL) { |
966 | 967 |
char *lenvar; |
967 | 968 |
char *contenttype; |
... | ... |
@@ -975,15 +976,15 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
975 | 976 |
} |
976 | 977 |
while(*lenvar==' ' || *lenvar=='\t') |
977 | 978 |
lenvar++; |
978 |
- client->serviced=1; |
|
979 |
+ client->uriready=1; |
|
979 | 980 |
client->continuationactive=0; |
980 | 981 |
client->status=wkc_post; |
981 | 982 |
client->pendingpost=atoi(lenvar); |
982 | 983 |
client->inpostvar=-1; |
983 | 984 |
} else { |
984 |
- client->serviced=1; |
|
985 |
+ client->uriready=1; |
|
985 | 986 |
client->continuationactive=0; |
986 |
- client->status=wkc_none; |
|
987 |
+ client->status=wkc_header; |
|
987 | 988 |
} |
988 | 989 |
return(0); |
989 | 990 |
} |
... | ... |
@@ -1038,17 +1039,17 @@ wk_clientservicereadpost(_wk *web, wk_client *client) |
1038 | 1039 |
if(client->pendingpost>0) |
1039 | 1040 |
return(0); /* nothing more to do for now*/ |
1040 | 1041 |
/* call the post method */ |
1041 |
- client->serviced=1; |
|
1042 |
+ client->uriready=1; |
|
1042 | 1043 |
client->continuationactive=0; |
1043 | 1044 |
action=web->callback_post((wk *)web, client->connid, client->uri, web->userptr); |
1044 | 1045 |
if(action==wkact_continuation) { |
1045 |
- client->serviced=1; |
|
1046 |
+ client->uriready=1; |
|
1046 | 1047 |
client->continuationactive=1; |
1047 |
- client->status=wkc_none; |
|
1048 |
+ client->status=wkc_header; |
|
1048 | 1049 |
} else { |
1049 |
- client->serviced=1; |
|
1050 |
+ client->uriready=1; |
|
1050 | 1051 |
client->continuationactive=0; |
1051 |
- client->status=wkc_none; |
|
1052 |
+ client->status=wkc_header; |
|
1052 | 1053 |
} |
1053 | 1054 |
return(0); |
1054 | 1055 |
} |
... | ... |
@@ -275,6 +275,9 @@ wk_service(wk *paramweb) |
275 | 275 |
continue; |
276 | 276 |
} |
277 | 277 |
} |
278 |
+ sbuf_discard(in); |
|
279 |
+ if(sbuf_unused(in)>0) |
|
280 |
+ sselect_addread(web->ssel,client->fd,(void *)client); |
|
278 | 281 |
} |
279 | 282 |
} |
280 | 283 |
while((n=sselect_getwritefiltered(web->ssel,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
... | ... |
@@ -959,7 +962,7 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
959 | 962 |
client->serviced=1; |
960 | 963 |
client->continuationactive=1; |
961 | 964 |
client->status=wkc_none; |
962 |
- } else if(action==wkact_post) { |
|
965 |
+ } else if(action==wkact_post && web->callback_post!=NULL) { |
|
963 | 966 |
char *lenvar; |
964 | 967 |
char *contenttype; |
965 | 968 |
if(strcmp(client->uri.method,"POST")!=0 || |
... | ... |
@@ -994,9 +997,10 @@ wk_clientservicereadpost(_wk *web, wk_client *client) |
994 | 997 |
char *sep; |
995 | 998 |
char *start; |
996 | 999 |
char *end; |
1000 |
+ wk_action action; |
|
997 | 1001 |
if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
998 | 1002 |
return(-1); /* internal error */ |
999 |
- while(sbuf_count(in)>0) { |
|
1003 |
+ while(sbuf_count(in)>0 && client->pendingpost>0) { |
|
1000 | 1004 |
if(client->inpostvar==-1) { |
1001 | 1005 |
sbuf_discard(in); |
1002 | 1006 |
buf=sbuf_ptr(in); |
... | ... |
@@ -1031,6 +1035,21 @@ wk_clientservicereadpost(_wk *web, wk_client *client) |
1031 | 1035 |
client->inpostvar=-1; |
1032 | 1036 |
} |
1033 | 1037 |
} |
1038 |
+ if(client->pendingpost>0) |
|
1039 |
+ return(0); /* nothing more to do for now*/ |
|
1040 |
+ /* call the post method */ |
|
1041 |
+ client->serviced=1; |
|
1042 |
+ client->continuationactive=0; |
|
1043 |
+ action=web->callback_post((wk *)web, client->connid, client->uri, web->userptr); |
|
1044 |
+ if(action==wkact_continuation) { |
|
1045 |
+ client->serviced=1; |
|
1046 |
+ client->continuationactive=1; |
|
1047 |
+ client->status=wkc_none; |
|
1048 |
+ } else { |
|
1049 |
+ client->serviced=1; |
|
1050 |
+ client->continuationactive=0; |
|
1051 |
+ client->status=wkc_none; |
|
1052 |
+ } |
|
1034 | 1053 |
return(0); |
1035 | 1054 |
} |
1036 | 1055 |
|
... | ... |
@@ -31,8 +31,10 @@ |
31 | 31 |
typedef struct wk_post { |
32 | 32 |
char *name; |
33 | 33 |
char *value; |
34 |
- int isfile; |
|
34 |
+ char *tofile; |
|
35 |
+ int bufid; |
|
35 | 36 |
int filewritten; |
37 |
+ int valueterminated; |
|
36 | 38 |
} wk_post; |
37 | 39 |
|
38 | 40 |
typedef enum wkc_status { |
... | ... |
@@ -59,6 +61,8 @@ typedef struct wk_client { |
59 | 61 |
int sizepost; |
60 | 62 |
int usedpost; |
61 | 63 |
wk_post *post; |
64 |
+ int pendingpost; |
|
65 |
+ int inpostvar; |
|
62 | 66 |
} wk_client; |
63 | 67 |
|
64 | 68 |
typedef struct wk_clientblock { |
... | ... |
@@ -102,8 +106,9 @@ static wk_client *wk_clientacquire(_wk *web); |
102 | 106 |
static int wk_clientrelease(_wk *web, int connid); |
103 | 107 |
static wk_client *wk_clientget(_wk *web, int connid); |
104 | 108 |
static int wk_clientservicereadheader(_wk *web, wk_client *client); |
109 |
+static int wk_clientservicereadpost(_wk *web, wk_client *client); |
|
105 | 110 |
static int wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile); |
106 |
-static int wk_postset(_wk *web, wk_client *client,char *varname, char *value); |
|
111 |
+static int wk_postset(_wk *web, wk_client *client,char *varname, char *data, int datalen); |
|
107 | 112 |
static char *wk_postget(_wk *web, wk_client *client,char *varname, int *isfile); |
108 | 113 |
static int wk_postfree(_wk *web, wk_client *client); |
109 | 114 |
|
... | ... |
@@ -245,6 +250,7 @@ wk_service(wk *paramweb) |
245 | 250 |
wk_close((wk *)web,client->connid); |
246 | 251 |
continue; /* internal error */ |
247 | 252 |
} |
253 |
+ sbuf_discard(in); |
|
248 | 254 |
if(sbuf_unused(in)<=0) { |
249 | 255 |
/* no room for the new data */ |
250 | 256 |
sselect_delread(web->ssel,fd); |
... | ... |
@@ -261,8 +267,13 @@ wk_service(wk *paramweb) |
261 | 267 |
wk_close((wk *) web, client->connid); |
262 | 268 |
continue; |
263 | 269 |
} |
264 |
- } else if(client->status==wkc_post) { |
|
265 |
-#warning TODO |
|
270 |
+ } |
|
271 |
+ if(client->status==wkc_post) { |
|
272 |
+ if(wk_clientservicereadpost(web,client)==-1) { |
|
273 |
+ /* internal error, protocol error or no enough memory */ |
|
274 |
+ wk_close((wk *) web, client->connid); |
|
275 |
+ continue; |
|
276 |
+ } |
|
266 | 277 |
} |
267 | 278 |
} |
268 | 279 |
} |
... | ... |
@@ -871,14 +882,15 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
871 | 882 |
char *lineend; |
872 | 883 |
char *sep; |
873 | 884 |
wk_uri *uri; |
885 |
+ wk_action action; |
|
874 | 886 |
/* check if we have all the headers */ |
875 | 887 |
if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
876 | 888 |
return(-1); /* internal error */ |
877 |
- sbuf_discard(in); |
|
878 | 889 |
if((end=str_findfirstempty(sbuf_ptr(in),sbuf_count(in)))==NULL) { |
890 |
+ sbuf_discard(in); |
|
879 | 891 |
if(sbuf_unused(in)==0) |
880 | 892 |
return(-1); /* header part too long */ |
881 |
- /* uncomplete headers, have to wait for more data */ |
|
893 |
+ /* incomplete headers, have to wait for more data */ |
|
882 | 894 |
return(0); |
883 | 895 |
} |
884 | 896 |
/* get memory for the uri data */ |
... | ... |
@@ -942,44 +954,138 @@ wk_clientservicereadheader(_wk *web, wk_client *client) |
942 | 954 |
/* call the http method */ |
943 | 955 |
client->serviced=1; |
944 | 956 |
client->continuationactive=0; |
945 |
-#warning TODO: wkc_post |
|
946 |
- client->continuationactive=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
|
957 |
+ action=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
|
958 |
+ if(action==wkact_continuation) { |
|
959 |
+ client->serviced=1; |
|
960 |
+ client->continuationactive=1; |
|
961 |
+ client->status=wkc_none; |
|
962 |
+ } else if(action==wkact_post) { |
|
963 |
+ char *lenvar; |
|
964 |
+ char *contenttype; |
|
965 |
+ if(strcmp(client->uri.method,"POST")!=0 || |
|
966 |
+ (lenvar=wk_uri_getheader(&(client->uri),"Content-Length",NULL))==NULL) { |
|
967 |
+ return(-1); /* malformed post */ |
|
968 |
+ } |
|
969 |
+ if((contenttype=wk_uri_getheader(&(client->uri),"Content-Type",NULL))==NULL || |
|
970 |
+ strcmp(contenttype,"application/x-www-form-urlencoded")!=0) { |
|
971 |
+ return(-1); /* unsupported encoding */ |
|
972 |
+ } |
|
973 |
+ while(*lenvar==' ' || *lenvar=='\t') |
|
974 |
+ lenvar++; |
|
975 |
+ client->serviced=1; |
|
976 |
+ client->continuationactive=0; |
|
977 |
+ client->status=wkc_post; |
|
978 |
+ client->pendingpost=atoi(lenvar); |
|
979 |
+ client->inpostvar=-1; |
|
980 |
+ } else { |
|
981 |
+ client->serviced=1; |
|
982 |
+ client->continuationactive=0; |
|
983 |
+ client->status=wkc_none; |
|
984 |
+ } |
|
985 |
+ return(0); |
|
986 |
+} |
|
987 |
+ |
|
988 |
+static int |
|
989 |
+wk_clientservicereadpost(_wk *web, wk_client *client) |
|
990 |
+{ |
|
991 |
+ sbuf *in; |
|
992 |
+ char *buf; |
|
993 |
+ int buflen; |
|
994 |
+ char *sep; |
|
995 |
+ char *start; |
|
996 |
+ char *end; |
|
997 |
+ if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
|
998 |
+ return(-1); /* internal error */ |
|
999 |
+ while(sbuf_count(in)>0) { |
|
1000 |
+ if(client->inpostvar==-1) { |
|
1001 |
+ sbuf_discard(in); |
|
1002 |
+ buf=sbuf_ptr(in); |
|
1003 |
+ buflen=sbuf_count(in); |
|
1004 |
+ if(buflen>client->pendingpost) |
|
1005 |
+ buflen=client->pendingpost; |
|
1006 |
+ if((sep=memchr(buf,'=',buflen))==NULL) |
|
1007 |
+ return(0); /* varname not found */ |
|
1008 |
+ *sep='\0'; |
|
1009 |
+ for(client->inpostvar=0;client->inpostvar<client->usedpost;client->inpostvar++) { |
|
1010 |
+ if(strcmp(client->post[client->inpostvar].name,buf)==0) |
|
1011 |
+ break; |
|
1012 |
+ } |
|
1013 |
+ sbuf_getbytes(in,(sep+1)-buf); |
|
1014 |
+ client->pendingpost-=((sep+1)-buf); |
|
1015 |
+ } |
|
1016 |
+ start=sbuf_ptr(in); |
|
1017 |
+ end=start+sbuf_count(in); |
|
1018 |
+ if((end-start)>client->pendingpost) |
|
1019 |
+ end=start+client->pendingpost; |
|
1020 |
+ if((sep=memchr(start,'&',end-start))!=NULL) |
|
1021 |
+ end=sep; |
|
1022 |
+ if(client->inpostvar>=0) { |
|
1023 |
+ if(client->inpostvar<client->usedpost) |
|
1024 |
+ wk_postset(web,client,client->post[client->inpostvar].name,start,end-start); |
|
1025 |
+ sbuf_getbytes(in,end-start); |
|
1026 |
+ client->pendingpost-=(end-start); |
|
1027 |
+ } |
|
1028 |
+ if(*sep=='&') { |
|
1029 |
+ sbuf_getbytes(in,1); |
|
1030 |
+ client->pendingpost--; |
|
1031 |
+ client->inpostvar=-1; |
|
1032 |
+ } |
|
1033 |
+ } |
|
947 | 1034 |
return(0); |
948 | 1035 |
} |
949 | 1036 |
|
1037 |
+ |
|
950 | 1038 |
static int |
951 | 1039 |
wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile) |
952 | 1040 |
{ |
953 | 1041 |
wk_post *post; |
1042 |
+ sbuf *buf; |
|
1043 |
+ int i; |
|
954 | 1044 |
if(client->post==NULL || client->sizepost==client->usedpost) { |
955 | 1045 |
wk_post *newpost; |
956 | 1046 |
if((newpost=(wk_post *)realloc(client->post,(client->sizepost+POSTBLOCK)*sizeof(wk_post)))==NULL) |
957 | 1047 |
return(-1); /* insufficient memory */ |
958 | 1048 |
client->post=newpost; |
959 | 1049 |
memset(client->post+client->sizepost,0,POSTBLOCK*sizeof(wk_post)); |
1050 |
+ for(i=0;i<POSTBLOCK;i++) |
|
1051 |
+ client->post[client->sizepost+i].bufid=-1; |
|
960 | 1052 |
client->sizepost+=POSTBLOCK; |
961 | 1053 |
} |
962 | 1054 |
post=client->post+client->usedpost; |
963 |
- if((post->name=strdup(varname))==NULL) |
|
1055 |
+ if((post->bufid=wk_sbufacquire((wk *)web))==-1) |
|
964 | 1056 |
return(-1); /* insufficient memory */ |
1057 |
+ if((buf=wk_sbufget((wk *)web,post->bufid))==NULL) { |
|
1058 |
+ post->bufid=-1; |
|
1059 |
+ return(-1); /* internal error */ |
|
1060 |
+ } |
|
1061 |
+ if((strlen(varname)+1)>(sbuf_unused(buf)-2)) { |
|
1062 |
+ wk_sbufrelease((wk *)web,post->bufid),post->bufid=-1; |
|
1063 |
+ return(-1); /* varname too long */ |
|
1064 |
+ } |
|
1065 |
+ post->name=sbuf_ptrunused(buf); |
|
1066 |
+ sbuf_addstr(buf,varname); |
|
965 | 1067 |
if(tofile!=NULL) { |
966 |
- if((post->value=strdup(tofile))==NULL) { |
|
967 |
- free(post->name),post->name=NULL; |
|
968 |
- return(-1); /* insufficient memory */ |
|
1068 |
+ if((strlen(tofile)+1)>(sbuf_unused(buf))) { |
|
1069 |
+ wk_sbufrelease((wk *)web,post->bufid),post->bufid=-1; |
|
1070 |
+ return(-1); /* varname+tofile too long */ |
|
969 | 1071 |
} |
970 |
- } else |
|
971 |
- post->isfile=0; |
|
1072 |
+ post->tofile=sbuf_ptrunused(buf); |
|
1073 |
+ sbuf_addstr(buf,tofile); |
|
1074 |
+ } |
|
1075 |
+ post->value=NULL; |
|
1076 |
+ post->filewritten=0; |
|
1077 |
+ post->valueterminated=0; |
|
972 | 1078 |
return(0); |
973 | 1079 |
} |
974 | 1080 |
|
975 | 1081 |
static int |
976 |
-wk_postset(_wk *web, wk_client *client,char *varname, char *value) |
|
1082 |
+wk_postset(_wk *web, wk_client *client,char *varname, char *data, int datalen) |
|
977 | 1083 |
{ |
978 | 1084 |
int i; |
979 | 1085 |
wk_post *post; |
980 | 1086 |
int fd; |
981 |
- int len; |
|
982 |
- if(varname==NULL || value==NULL) |
|
1087 |
+ sbuf *buf; |
|
1088 |
+ if(varname==NULL || data==NULL || datalen==0) |
|
983 | 1089 |
return(-1); |
984 | 1090 |
for(i=0;i<client->usedpost;i++) { |
985 | 1091 |
if(strcmp(client->post[i].name,varname)==0) |
... | ... |
@@ -988,21 +1094,26 @@ wk_postset(_wk *web, wk_client *client,char *varname, char *value) |
988 | 1094 |
if(i>=client->usedpost) |
989 | 1095 |
return(-1); /* var not found */ |
990 | 1096 |
post=client->post+i; |
991 |
- if(post->isfile) { |
|
992 |
- if((fd=open(post->value,O_CREAT|O_APPEND,0600))==-1) |
|
1097 |
+ if(post->tofile!=NULL) { |
|
1098 |
+ if((fd=open(post->tofile,O_CREAT|O_APPEND,0600))==-1) |
|
993 | 1099 |
return(-1); /* couldn't open file */ |
994 |
- len=strlen(value); |
|
995 |
- if(write(fd,value,len)!=len) { |
|
1100 |
+ if(write(fd,data,datalen)!=datalen) { |
|
996 | 1101 |
close(fd),fd=-1; |
997 |
- return(-1); /* couldn't open file */ |
|
1102 |
+ return(-1); /* couldn't write all data */ |
|
998 | 1103 |
} |
999 | 1104 |
close(fd),fd=-1; |
1000 | 1105 |
post->filewritten=1; |
1001 | 1106 |
} else { |
1002 |
- if(post->value!=NULL) |
|
1003 |
- free(post->value),post->value=NULL; |
|
1004 |
- if((post->value=strdup(value))==NULL) |
|
1005 |
- return(-1); |
|
1107 |
+ if((buf=wk_sbufget((wk *)web,post->bufid))==NULL) { |
|
1108 |
+ post->bufid=-1; |
|
1109 |
+ return(-1); /* internal error */ |
|
1110 |
+ } |
|
1111 |
+ if(post->value==NULL) |
|
1112 |
+ post->value=sbuf_ptrunused(buf); |
|
1113 |
+ if(datalen>(sbuf_unused(buf)-1)) |
|
1114 |
+ datalen=sbuf_unused(buf)-1; |
|
1115 |
+ sbuf_add(buf,data,datalen); |
|
1116 |
+ post->valueterminated=0; |
|
1006 | 1117 |
} |
1007 | 1118 |
return(0); |
1008 | 1119 |
} |
... | ... |
@@ -1012,6 +1123,7 @@ wk_postget(_wk *web, wk_client *client,char *varname, int *isfile) |
1012 | 1123 |
{ |
1013 | 1124 |
int i; |
1014 | 1125 |
wk_post *post; |
1126 |
+ sbuf *buf; |
|
1015 | 1127 |
if(varname==NULL) |
1016 | 1128 |
return(NULL); |
1017 | 1129 |
for(i=0;i<client->usedpost;i++) { |
... | ... |
@@ -1021,10 +1133,23 @@ wk_postget(_wk *web, wk_client *client,char *varname, int *isfile) |
1021 | 1133 |
if(i>=client->usedpost) |
1022 | 1134 |
return(NULL); /* var not found */ |
1023 | 1135 |
post=client->post+i; |
1136 |
+ /* file post */ |
|
1024 | 1137 |
if(isfile!=NULL) |
1025 |
- *isfile=post->isfile; |
|
1026 |
- if(post->isfile && !post->filewritten) |
|
1027 |
- return(NULL); |
|
1138 |
+ *isfile=(post->tofile!=NULL)?1:0; |
|
1139 |
+ if(post->tofile) { |
|
1140 |
+ if(!post->filewritten) |
|
1141 |
+ return(NULL); |
|
1142 |
+ return(post->tofile); |
|
1143 |
+ } |
|
1144 |
+ /* buffer post */ |
|
1145 |
+ if((buf=wk_sbufget((wk *)web,post->bufid))==NULL) |
|
1146 |
+ return(NULL); /* internal error */ |
|
1147 |
+ if(!post->valueterminated) { |
|
1148 |
+ if(sbuf_unused(buf)<1) |
|
1149 |
+ return(NULL); /* internal error */ |
|
1150 |
+ *(sbuf_ptrunused(buf))='\0'; |
|
1151 |
+ post->valueterminated=1; |
|
1152 |
+ } |
|
1028 | 1153 |
return(post->value); |
1029 | 1154 |
} |
1030 | 1155 |
|
... | ... |
@@ -1032,12 +1157,11 @@ static int |
1032 | 1157 |
wk_postfree(_wk *web, wk_client *client) |
1033 | 1158 |
{ |
1034 | 1159 |
int i; |
1160 |
+ wk_post *post; |
|
1035 | 1161 |
for(i=0;i<client->usedpost;i++) { |
1036 |
- if(client->post[i].name!=NULL) |
|
1037 |
- free(client->post[i].name),client->post[i].name=NULL; |
|
1038 |
- if(client->post[i].value!=NULL) |
|
1039 |
- free(client->post[i].value),client->post[i].value=NULL; |
|
1040 |
- client->post[i].isfile=0; |
|
1162 |
+ post=client->post+i; |
|
1163 |
+ if(post->bufid!=-1) |
|
1164 |
+ wk_sbufrelease((wk *)web,post->bufid),post->bufid=-1; |
|
1041 | 1165 |
} |
1042 | 1166 |
if(client->post!=NULL) { |
1043 | 1167 |
client->usedpost=0; |
... | ... |
@@ -535,6 +535,18 @@ wk_uri_getvar(wk_uri *uri, char *varname, int *len) |
535 | 535 |
return(NULL); |
536 | 536 |
} |
537 | 537 |
|
538 |
+char * |
|
539 |
+wk_uri_copyvar(wk_uri *uri, char *varname, char *dest, int destlen) |
|
540 |
+{ |
|
541 |
+ char *value; |
|
542 |
+ int len; |
|
543 |
+ if(dest==NULL || destlen<1 || (value=wk_uri_getvar(uri,varname,&len))==NULL) |
|
544 |
+ return(NULL); |
|
545 |
+ memcpy(dest,value,(len<(destlen-1))?len:destlen-1); |
|
546 |
+ dest[(len<(destlen-1))?len:destlen-1]='\0'; |
|
547 |
+ return(dest); |
|
548 |
+} |
|
549 |
+ |
|
538 | 550 |
|
539 | 551 |
int |
540 | 552 |
wk_post_addvalid(wk *paramweb, int connid, char *varname, char *tofile) |
... | ... |
@@ -26,7 +26,20 @@ |
26 | 26 |
#define BUFSIZE 8192 |
27 | 27 |
#define BUFBLOCK 128 |
28 | 28 |
#define BUFBLOCKBLOCK 256 |
29 |
+#define POSTBLOCK 16 |
|
29 | 30 |
|
31 |
+typedef struct wk_post { |
|
32 |
+ char *name; |
|
33 |
+ char *value; |
|
34 |
+ int isfile; |
|
35 |
+ int filewritten; |
|
36 |
+} wk_post; |
|
37 |
+ |
|
38 |
+typedef enum wkc_status { |
|
39 |
+ wkc_header=0, |
|
40 |
+ wkc_post, |
|
41 |
+ wkc_none, |
|
42 |
+} wkc_status; |
|
30 | 43 |
|
31 | 44 |
typedef struct wk_client { |
32 | 45 |
wk *web; |
... | ... |
@@ -36,12 +49,16 @@ typedef struct wk_client { |
36 | 49 |
int sizeoutbufids; |
37 | 50 |
int usedoutbufids; |
38 | 51 |
int outbufids[MAXOUTBUF]; |
52 |
+ wkc_status status; |
|
39 | 53 |
int serviced; |
40 | 54 |
int continuationactive; |
41 | 55 |
int fdtoserve; |
42 | 56 |
wk_uri uri; |
43 | 57 |
int headerbufid; |
44 | 58 |
int keepalive; |
59 |
+ int sizepost; |
|
60 |
+ int usedpost; |
|
61 |
+ wk_post *post; |
|
45 | 62 |
} wk_client; |
46 | 63 |
|
47 | 64 |
typedef struct wk_clientblock { |
... | ... |
@@ -75,6 +92,7 @@ typedef struct _wk { |
75 | 92 |
wk_bufblock *bufblocks; |
76 | 93 |
void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/); |
77 | 94 |
wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
95 |
+ wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
|
78 | 96 |
wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
79 | 97 |
void *userptr; |
80 | 98 |
} _wk; |
... | ... |
@@ -83,10 +101,14 @@ static wk_client *wk_accept(_wk *web); |
83 | 101 |
static wk_client *wk_clientacquire(_wk *web); |
84 | 102 |
static int wk_clientrelease(_wk *web, int connid); |
85 | 103 |
static wk_client *wk_clientget(_wk *web, int connid); |
86 |
-static int wk_clientserviceread(_wk *web, wk_client *client); |
|
104 |
+static int wk_clientservicereadheader(_wk *web, wk_client *client); |
|
105 |
+static int wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile); |
|
106 |
+static int wk_postset(_wk *web, wk_client *client,char *varname, char *value); |
|
107 |
+static char *wk_postget(_wk *web, wk_client *client,char *varname, int *isfile); |
|
108 |
+static int wk_postfree(_wk *web, wk_client *client); |
|
87 | 109 |
|
88 | 110 |
wk * |
89 |
-wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
111 |
+wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_post)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
90 | 112 |
{ |
91 | 113 |
_wk *web; |
92 | 114 |
if(ssel==NULL || callback_http==NULL) |
... | ... |
@@ -97,6 +119,7 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk |
97 | 119 |
web->serverfd=-1; |
98 | 120 |
web->callback_event=callback_event; |
99 | 121 |
web->callback_http=callback_http; |
122 |
+ web->callback_post=callback_post; |
|
100 | 123 |
web->callback_continuation=callback_continuation; |
101 | 124 |
web->userptr=userptr; |
102 | 125 |
web->ssel=ssel; |
... | ... |
@@ -151,6 +174,7 @@ wk_free(wk *paramweb) |
151 | 174 |
} |
152 | 175 |
if(client->fdtoserve!=-1) |
153 | 176 |
close(client->fdtoserve),client->fdtoserve=-1; |
177 |
+ wk_postfree(web,client); |
|
154 | 178 |
} |
155 | 179 |
} |
156 | 180 |
cb->usedclients=0; |
... | ... |
@@ -231,10 +255,14 @@ wk_service(wk *paramweb) |
231 | 255 |
wk_close((wk *) web, client->connid); |
232 | 256 |
continue; |
233 | 257 |
} |
234 |
- if(wk_clientserviceread(web,client)==-1) { |
|
235 |
- /* internal error, protocol error or no enough memory */ |
|
236 |
- wk_close((wk *) web, client->connid); |
|
237 |
- continue; |
|
258 |
+ if(client->status==wkc_header) { |
|
259 |
+ if(wk_clientservicereadheader(web,client)==-1) { |
|
260 |
+ /* internal error, protocol error or no enough memory */ |
|
261 |
+ wk_close((wk *) web, client->connid); |
|
262 |
+ continue; |
|
263 |
+ } |
|
264 |
+ } else if(client->status==wkc_post) { |
|
265 |
+#warning TODO |
|
238 | 266 |
} |
239 | 267 |
} |
240 | 268 |
} |
... | ... |
@@ -482,6 +510,57 @@ wk_uri_getheaderbynum(wk_uri *uri, int num) |
482 | 510 |
return(NULL); |
483 | 511 |
} |
484 | 512 |
|
513 |
+char * |
|
514 |
+wk_uri_getvar(wk_uri *uri, char *varname, int *len) |
|
515 |
+{ |
|
516 |
+ char *ptr,*end; |
|
517 |
+ int varlen; |
|
518 |
+ if(uri==NULL || uri->path==NULL || (ptr=strchr(uri->path,'?'))==NULL) |
|
519 |
+ return(NULL); |
|
520 |
+ varlen=strlen(varname); |
|
521 |
+ ptr++; |
|
522 |
+ while(*ptr!='\0' && ptr!=NULL) { |
|
523 |
+ if(memcmp(ptr,varname,varlen)==0 && ptr[varlen]=='=') { |
|
524 |
+ ptr+=varlen+1; |
|
525 |
+ if((end=strchr(ptr,'&'))==NULL) |
|
526 |
+ end=ptr+strlen(ptr); |
|
527 |
+ if(len!=NULL) |
|
528 |
+ *len=end-ptr; |
|
529 |
+ return(ptr); |
|
530 |
+ } |
|
531 |
+ if((end=strchr(ptr,'&'))==NULL) |
|
532 |
+ break; |
|
533 |
+ ptr=end+1; |
|
534 |
+ } |
|
535 |
+ return(NULL); |
|
536 |
+} |
|
537 |
+ |
|
538 |
+ |
|
539 |
+int |
|
540 |
+wk_post_addvalid(wk *paramweb, int connid, char *varname, char *tofile) |
|
541 |
+{ |
|
542 |
+ _wk *web=(_wk *)paramweb; |
|
543 |
+ wk_client *client; |
|
544 |
+ if(web==NULL || varname==NULL) |
|
545 |
+ return(-1); |
|
546 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
547 |
+ return(-1); |
|
548 |
+ return(wk_postadd(web,client,varname,tofile)); |
|
549 |
+} |
|
550 |
+ |
|
551 |
+char * |
|
552 |
+wk_post_get(wk *paramweb, int connid, char *varname, int *isfile) |
|
553 |
+{ |
|
554 |
+ _wk *web=(_wk *)paramweb; |
|
555 |
+ wk_client *client; |
|
556 |
+ if(web==NULL || varname==NULL) |
|
557 |
+ return(NULL); |
|
558 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
559 |
+ return(NULL); |
|
560 |
+ return(wk_postget(web,client,varname,isfile)); |
|
561 |
+} |
|
562 |
+ |
|
563 |
+ |
|
485 | 564 |
const char * |
486 | 565 |
mime_getdefault(const char *filename, const char *defaultmime) |
487 | 566 |
{ |
... | ... |
@@ -739,6 +818,7 @@ wk_clientrelease(_wk *web, int connid) |
739 | 818 |
wk_sbufrelease((wk *)web,client->outbufids[w]),client->outbufids[w]=-1; |
740 | 819 |
if(client->headerbufid!=-1) |
741 | 820 |
wk_sbufrelease((wk *)web,client->headerbufid),client->headerbufid=-1; |
821 |
+ wk_postfree(web,client); |
|
742 | 822 |
memset(client,0,sizeof(wk_client)); |
743 | 823 |
return(0); |
744 | 824 |
} |
... | ... |
@@ -771,7 +851,7 @@ str_findfirstempty(char *ptr, int size) |
771 | 851 |
} |
772 | 852 |
|
773 | 853 |
static int |
774 |
-wk_clientserviceread(_wk *web, wk_client *client) |
|
854 |
+wk_clientservicereadheader(_wk *web, wk_client *client) |
|
775 | 855 |
{ |
776 | 856 |
sbuf *in,*hbuf; |
777 | 857 |
char *end; |
... | ... |
@@ -850,7 +930,109 @@ wk_clientserviceread(_wk *web, wk_client *client) |
850 | 930 |
/* call the http method */ |
851 | 931 |
client->serviced=1; |
852 | 932 |
client->continuationactive=0; |
933 |
+#warning TODO: wkc_post |
|
853 | 934 |
client->continuationactive=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
854 | 935 |
return(0); |
855 | 936 |
} |
856 | 937 |
|
938 |
+static int |
|
939 |
+wk_postadd(_wk *web, wk_client *client,char *varname, char *tofile) |
|
940 |
+{ |
|
941 |
+ wk_post *post; |
|
942 |
+ if(client->post==NULL || client->sizepost==client->usedpost) { |
|
943 |
+ wk_post *newpost; |
|
944 |
+ if((newpost=(wk_post *)realloc(client->post,(client->sizepost+POSTBLOCK)*sizeof(wk_post)))==NULL) |
|
945 |
+ return(-1); /* insufficient memory */ |
|
946 |
+ client->post=newpost; |
|
947 |
+ memset(client->post+client->sizepost,0,POSTBLOCK*sizeof(wk_post)); |
|
948 |
+ client->sizepost+=POSTBLOCK; |
|
949 |
+ } |
|
950 |
+ post=client->post+client->usedpost; |
|
951 |
+ if((post->name=strdup(varname))==NULL) |
|
952 |
+ return(-1); /* insufficient memory */ |
|
953 |
+ if(tofile!=NULL) { |
|
954 |
+ if((post->value=strdup(tofile))==NULL) { |
|
955 |
+ free(post->name),post->name=NULL; |
|
956 |
+ return(-1); /* insufficient memory */ |
|
957 |
+ } |
|
958 |
+ } else |
|
959 |
+ post->isfile=0; |
|
960 |
+ return(0); |
|
961 |
+} |
|
962 |
+ |
|
963 |
+static int |
|
964 |
+wk_postset(_wk *web, wk_client *client,char *varname, char *value) |
|
965 |
+{ |
|
966 |
+ int i; |
|
967 |
+ wk_post *post; |
|
968 |
+ int fd; |
|
969 |
+ int len; |
|
970 |
+ if(varname==NULL || value==NULL) |
|
971 |
+ return(-1); |
|
972 |
+ for(i=0;i<client->usedpost;i++) { |
|
973 |
+ if(strcmp(client->post[i].name,varname)==0) |
|
974 |
+ break; |
|
975 |
+ } |
|
976 |
+ if(i>=client->usedpost) |
|
977 |
+ return(-1); /* var not found */ |
|
978 |
+ post=client->post+i; |
|
979 |
+ if(post->isfile) { |
|
980 |
+ if((fd=open(post->value,O_CREAT|O_APPEND,0600))==-1) |
|
981 |
+ return(-1); /* couldn't open file */ |
|
982 |
+ len=strlen(value); |
|
983 |
+ if(write(fd,value,len)!=len) { |
|
984 |
+ close(fd),fd=-1; |
|
985 |
+ return(-1); /* couldn't open file */ |
|
986 |
+ } |
|
987 |
+ close(fd),fd=-1; |
|
988 |
+ post->filewritten=1; |
|
989 |
+ } else { |
|
990 |
+ if(post->value!=NULL) |
|
991 |
+ free(post->value),post->value=NULL; |
|
992 |
+ if((post->value=strdup(value))==NULL) |
|
993 |
+ return(-1); |
|
994 |
+ } |
|
995 |
+ return(0); |
|
996 |
+} |
|
997 |
+ |
|
998 |
+static char * |
|
999 |
+wk_postget(_wk *web, wk_client *client,char *varname, int *isfile) |
|
1000 |
+{ |
|
1001 |
+ int i; |
|
1002 |
+ wk_post *post; |
|
1003 |
+ if(varname==NULL) |
|
1004 |
+ return(NULL); |
|
1005 |
+ for(i=0;i<client->usedpost;i++) { |
|
1006 |
+ if(strcmp(client->post[i].name,varname)==0) |
|
1007 |
+ break; |
|
1008 |
+ } |
|
1009 |
+ if(i>=client->usedpost) |
|
1010 |
+ return(NULL); /* var not found */ |
|
1011 |
+ post=client->post+i; |
|
1012 |
+ if(isfile!=NULL) |
|
1013 |
+ *isfile=post->isfile; |
|
1014 |
+ if(post->isfile && !post->filewritten) |
|
1015 |
+ return(NULL); |
|
1016 |
+ return(post->value); |
|
1017 |
+} |
|
1018 |
+ |
|
1019 |
+static int |
|
1020 |
+wk_postfree(_wk *web, wk_client *client) |
|
1021 |
+{ |
|
1022 |
+ int i; |
|
1023 |
+ for(i=0;i<client->usedpost;i++) { |
|
1024 |
+ if(client->post[i].name!=NULL) |
|
1025 |
+ free(client->post[i].name),client->post[i].name=NULL; |
|
1026 |
+ if(client->post[i].value!=NULL) |
|
1027 |
+ free(client->post[i].value),client->post[i].value=NULL; |
|
1028 |
+ client->post[i].isfile=0; |
|
1029 |
+ } |
|
1030 |
+ if(client->post!=NULL) { |
|
1031 |
+ client->usedpost=0; |
|
1032 |
+ client->sizepost=0; |
|
1033 |
+ free(client->post),client->post=NULL; |
|
1034 |
+ } |
|
1035 |
+ return(0); |
|
1036 |
+} |
|
1037 |
+ |
|
1038 |
+ |
... | ... |
@@ -204,7 +204,7 @@ wk_service(wk *paramweb) |
204 | 204 |
wk_client *client; |
205 | 205 |
if(web==NULL) |
206 | 206 |
return(-1); |
207 |
- while((n=sselect_getreadfiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
207 |
+ while((n=sselect_getreadfiltered(web->ssel,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
208 | 208 |
for(i=0;i<n;i++) { |
209 | 209 |
fd=fds[i]; |
210 | 210 |
if(fd==web->serverfd) { |
... | ... |
@@ -238,7 +238,7 @@ wk_service(wk *paramweb) |
238 | 238 |
} |
239 | 239 |
} |
240 | 240 |
} |
241 |
- while((n=sselect_getwritefiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
241 |
+ while((n=sselect_getwritefiltered(web->ssel,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
242 | 242 |
for(i=0;i<n;i++) { |
243 | 243 |
fd=fds[i]; |
244 | 244 |
if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) |
... | ... |
@@ -548,7 +548,7 @@ wk_sbufacquire(wk *paramweb) |
548 | 548 |
/* make sure there are free bufblocks */ |
549 | 549 |
if(web->usedbufblocks==web->sizebufblocks) { |
550 | 550 |
wk_bufblock *newbb; |
551 |
- if((newbb=(wk_bufblock *)realloc(web->bufblocks,web->sizebufblocks+BUFBLOCKBLOCK))==NULL) |
|
551 |
+ if((newbb=(wk_bufblock *)realloc(web->bufblocks,(web->sizebufblocks+BUFBLOCKBLOCK)*sizeof(wk_bufblock)))==NULL) |
|
552 | 552 |
return(-1); /* insufficient memory */ |
553 | 553 |
web->bufblocks=newbb; |
554 | 554 |
memset(web->bufblocks+web->sizebufblocks,0,BUFBLOCKBLOCK*sizeof(wk_bufblock)); |
... | ... |
@@ -569,6 +569,7 @@ wk_sbufacquire(wk *paramweb) |
569 | 569 |
memset(bb->bufs,0,sizeof(wk_buf)*BUFBLOCK); |
570 | 570 |
bb->sizebufs=BUFBLOCK; |
571 | 571 |
bb->usedbufs=0; |
572 |
+ web->usedbufblocks++; |
|
572 | 573 |
} |
573 | 574 |
/* get first unused sbuf */ |
574 | 575 |
for(j=0;j<bb->sizebufs;j+=8) { |
... | ... |
@@ -659,7 +660,7 @@ wk_clientacquire(_wk *web) |
659 | 660 |
/* make sure there are free clientblocks */ |
660 | 661 |
if(web->usedclientblocks==web->sizeclientblocks) { |
661 | 662 |
wk_clientblock *newcb; |
662 |
- if((newcb=(wk_clientblock *)realloc(web->clientblocks,web->sizeclientblocks+CLIENTBLOCKBLOCK))==NULL) |
|
663 |
+ if((newcb=(wk_clientblock *)realloc(web->clientblocks,(web->sizeclientblocks+CLIENTBLOCKBLOCK)*sizeof(wk_clientblock)))==NULL) |
|
663 | 664 |
return(NULL); /* insufficient memory */ |
664 | 665 |
web->clientblocks=newcb; |
665 | 666 |
memset(web->clientblocks+web->sizeclientblocks,0,CLIENTBLOCKBLOCK*sizeof(wk_clientblock)); |
... | ... |
@@ -680,6 +681,7 @@ wk_clientacquire(_wk *web) |
680 | 681 |
memset(cb->clients,0,sizeof(wk_client)*CLIENTBLOCK); |
681 | 682 |
cb->sizeclients=CLIENTBLOCK; |
682 | 683 |
cb->usedclients=0; |
684 |
+ web->usedclientblocks++; |
|
683 | 685 |
} |
684 | 686 |
/* get first unused client */ |
685 | 687 |
for(j=0;j<cb->sizeclients;j+=8) { |
... | ... |
@@ -762,8 +764,8 @@ str_findfirstempty(char *ptr, int size) |
762 | 764 |
{ |
763 | 765 |
int i; |
764 | 766 |
for(i=0;i<(size-3);i++) { |
765 |
- if(ptr[0]=='\r' && ptr[1]=='\n' && ptr[2]=='\r' && ptr[3]=='\n') |
|
766 |
- return(ptr); |
|
767 |
+ if(ptr[i+0]=='\r' && ptr[i+1]=='\n' && ptr[i+2]=='\r' && ptr[i+3]=='\n') |
|
768 |
+ return(ptr+i); |
|
767 | 769 |
} |
768 | 770 |
return(NULL); |
769 | 771 |
} |
... | ... |
@@ -819,7 +821,7 @@ wk_clientserviceread(_wk *web, wk_client *client) |
819 | 821 |
sbuf_add(hbuf,ptr,strlen(ptr)+1); |
820 | 822 |
ptr+=strlen(ptr)+1; |
821 | 823 |
/* protocol */ |
822 |
- uri->path=sbuf_ptrunused(hbuf); |
|
824 |
+ uri->protocol=sbuf_ptrunused(hbuf); |
|
823 | 825 |
sbuf_add(hbuf,ptr,strlen(ptr)+1); |
824 | 826 |
ptr+=strlen(ptr)+1; |
825 | 827 |
/* headers */ |
... | ... |
@@ -592,7 +592,7 @@ wk_sbufacquire(wk *paramweb) |
592 | 592 |
} |
593 | 593 |
|
594 | 594 |
int |
595 |
-wk_bufrelease(wk *paramweb, int sbufid) |
|
595 |
+wk_sbufrelease(wk *paramweb, int sbufid) |
|
596 | 596 |
{ |
597 | 597 |
sbuf *buf; |
598 | 598 |
int numblock,j,bit; |
... | ... |
@@ -612,7 +612,7 @@ wk_bufrelease(wk *paramweb, int sbufid) |
612 | 612 |
} |
613 | 613 |
|
614 | 614 |
sbuf * |
615 |
-wk_bufget(wk *paramweb, int sbufid) |
|
615 |
+wk_sbufget(wk *paramweb, int sbufid) |
|
616 | 616 |
{ |
617 | 617 |
int numblock,j,bit; |
618 | 618 |
_wk *web=(_wk *)paramweb; |
... | ... |
@@ -12,6 +12,9 @@ |
12 | 12 |
#include <stdlib.h> |
13 | 13 |
#include <unistd.h> |
14 | 14 |
#include <string.h> |
15 |
+#include <sys/types.h> |
|
16 |
+#include <sys/stat.h> |
|
17 |
+#include <fcntl.h> |
|
15 | 18 |
#include "sbuf.h" |
16 | 19 |
#include "socklib.h" |
17 | 20 |
#include "webkernel.h" |
... | ... |
@@ -34,8 +37,10 @@ typedef struct wk_client { |
34 | 37 |
int usedoutbufids; |
35 | 38 |
int outbufids[MAXOUTBUF]; |
36 | 39 |
int serviced; |
37 |
- wk_uri uri; |
|
38 | 40 |
int continuationactive; |
41 |
+ int fdtoserve; |
|
42 |
+ wk_uri uri; |
|
43 |
+ int headerbufid; |
|
39 | 44 |
int keepalive; |
40 | 45 |
} wk_client; |
41 | 46 |
|
... | ... |
@@ -78,7 +83,7 @@ static wk_client *wk_accept(_wk *web); |
78 | 83 |
static wk_client *wk_clientacquire(_wk *web); |
79 | 84 |
static int wk_clientrelease(_wk *web, int connid); |
80 | 85 |
static wk_client *wk_clientget(_wk *web, int connid); |
81 |
-static void wk_clientserviceread(_wk *web, wk_client *client); |
|
86 |
+static int wk_clientserviceread(_wk *web, wk_client *client); |
|
82 | 87 |
|
83 | 88 |
wk * |
84 | 89 |
wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
... | ... |
@@ -144,6 +149,8 @@ wk_free(wk *paramweb) |
144 | 149 |
FD_CLR(client->fd,&(web->fdset)); |
145 | 150 |
close(client->fd),client->fd=-1; |
146 | 151 |
} |
152 |
+ if(client->fdtoserve!=-1) |
|
153 |
+ close(client->fdtoserve),client->fdtoserve=-1; |
|
147 | 154 |
} |
148 | 155 |
} |
149 | 156 |
cb->usedclients=0; |
... | ... |
@@ -190,7 +197,7 @@ wk_service(wk *paramweb) |
190 | 197 |
{ |
191 | 198 |
int fds[FDBLOCK]; |
192 | 199 |
int fd; |
193 |
- int n,i,k; |
|
200 |
+ int n,i; |
|
194 | 201 |
sbuf *in; |
195 | 202 |
sbuf *out; |
196 | 203 |
_wk *web=(_wk *)paramweb; |
... | ... |
@@ -221,10 +228,14 @@ wk_service(wk *paramweb) |
221 | 228 |
} |
222 | 229 |
if(sbuf_fill(in,fd,sock_queued(fd))==0) { |
223 | 230 |
/* client has closed connection */ |
224 |
- wk_close((wk *) web, fd); |
|
231 |
+ wk_close((wk *) web, client->connid); |
|
232 |
+ continue; |
|
233 |
+ } |
|
234 |
+ if(wk_clientserviceread(web,client)==-1) { |
|
235 |
+ /* internal error, protocol error or no enough memory */ |
|
236 |
+ wk_close((wk *) web, client->connid); |
|
225 | 237 |
continue; |
226 | 238 |
} |
227 |
- wk_clientserviceread(web,client); |
|
228 | 239 |
} |
229 | 240 |
} |
230 | 241 |
while((n=sselect_getwritefiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
... | ... |
@@ -232,21 +243,30 @@ wk_service(wk *paramweb) |
232 | 243 |
fd=fds[i]; |
233 | 244 |
if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) |
234 | 245 |
continue; /* internal error */ |
235 |
- for(out=NULL,k=client->usedoutbufids-1;k>=0;k--) { |
|
236 |
- if((out=wk_sbufget((wk *) web,client->outbufids[k]))==NULL) { |
|
237 |
- k=-1; |
|
238 |
- break; /* internal error */ |
|
239 |
- } |
|
240 |
- } |
|
241 |
- if(k==-1 || out==NULL) { |
|
246 |
+ if((out=wk_sbufget((wk *) web,client->outbufids[0]))==NULL) { |
|
242 | 247 |
wk_close((wk *)web,client->connid); |
243 | 248 |
continue; /* internal error */ |
244 | 249 |
} |
245 | 250 |
sbuf_send(out,fd,sbuf_count(out)); |
251 |
+ /* if we are serving from file, load the next chunk */ |
|
252 |
+ if(client->fdtoserve!=-1 && client->usedoutbufids==1) { |
|
253 |
+ sbuf_discard(out); |
|
254 |
+ if(sbuf_unused(out)>0) { |
|
255 |
+ int n; |
|
256 |
+ n=sbuf_fill(out,client->fdtoserve,sbuf_unused(out)); |
|
257 |
+ if(n<=0) |
|
258 |
+ close(client->fdtoserve),client->fdtoserve=-1; |
|
259 |
+ } |
|
260 |
+ } |
|
261 |
+ /* free unused bufs, detect finished sending */ |
|
246 | 262 |
if(sbuf_count(out)==0) { |
247 |
- if(k>0) { |
|
263 |
+ if(client->usedoutbufids>1) { |
|
264 |
+ int sbufid; |
|
265 |
+ sbufid=client->outbufids[0]; |
|
248 | 266 |
client->usedoutbufids--; |
249 |
- wk_sbufrelease((wk *)web,client->outbufids[k]),client->outbufids[k]=-1; |
|
267 |
+ memmove(client->outbufids,client->outbufids+1,sizeof(int)*(MAXOUTBUF-1)); |
|
268 |
+ client->outbufids[MAXOUTBUF-1]=-1; |
|
269 |
+ wk_sbufrelease((wk *)web,sbufid),sbufid=-1; |
|
250 | 270 |
} else { |
251 | 271 |
sselect_delwrite(web->ssel,client->fd); |
252 | 272 |
if(client->continuationactive && web->callback_continuation!=NULL) { |
... | ... |
@@ -266,29 +286,117 @@ wk_service(wk *paramweb) |
266 | 286 |
int |
267 | 287 |
wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
268 | 288 |
{ |
269 |
- |
|
289 |
+ static const char *strcontenttype={"Content-Type: "}; |
|
290 |
+ _wk *web=(_wk *)paramweb; |
|
291 |
+ wk_client *client; |
|
292 |
+ char buf[256]; |
|
293 |
+ if(web==NULL) |
|
294 |
+ return(-1); |
|
295 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
296 |
+ return(-1); |
|
297 |
+ wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n"); |
|
298 |
+ sprintf(buf,"Content-Length: %i\r\n",datalen); |
|
299 |
+ wk_writestr((wk *)web,connid,buf); |
|
300 |
+ if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
301 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
302 |
+ else |
|
303 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
304 |
+ wk_writestr((wk *)web,connid,buf); |
|
305 |
+ if(client->keepalive) |
|
306 |
+ wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n"); |
|
307 |
+ wk_writestr((wk *)web,connid,"\r\n"); |
|
308 |
+ return(wk_write((wk *)web,connid,data,datalen)); |
|
270 | 309 |
} |
271 | 310 |
|
272 | 311 |
int |
273 | 312 |
wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime) |
274 | 313 |
{ |
275 |
- |
|
314 |
+ static const char *strcontenttype={"Content-Type: "}; |
|
315 |
+ _wk *web=(_wk *)paramweb; |
|
316 |
+ wk_client *client; |
|
317 |
+ char buf[256]; |
|
318 |
+ struct stat st; |
|
319 |
+ if(web==NULL || filename==NULL) |
|
320 |
+ return(-1); |
|
321 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
322 |
+ return(-1); |
|
323 |
+ if(client->fdtoserve!=-1) |
|
324 |
+ close(client->fdtoserve),client->fdtoserve=-1; |
|
325 |
+ if((client->fdtoserve=open(filename,O_RDONLY))==-1) { |
|
326 |
+ wk_serve_error((wk *)web,connid,wkerr_notfound); |
|
327 |
+ return(-1); |
|
328 |
+ } |
|
329 |
+ wk_writestr((wk *)web,connid,"HTTP/1.1 200 OK\r\n"); |
|
330 |
+ if(fstat(client->fdtoserve,&st)==0) { |
|
331 |
+ sprintf(buf,"Content-Length: %lld\r\n",(long long)st.st_size); |
|
332 |
+ wk_writestr((wk *)web,connid,buf); |
|
333 |
+ } else |
|
334 |
+ client->keepalive=0; |
|
335 |
+ if(mime!=NULL && strlen(mime)<(sizeof(buf)-sizeof(strcontenttype)-3)) |
|
336 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,mime); |
|
337 |
+ else |
|
338 |
+ sprintf(buf,"%s%s\r\n",strcontenttype,"application/octet-stream"); |
|
339 |
+ wk_writestr((wk *)web,connid,buf); |
|
340 |
+ if(client->keepalive) |
|
341 |
+ wk_writestr((wk *)web,connid,"Connection: keep-alive\r\n"); |
|
342 |
+ wk_writestr((wk *)web,connid,"\r\n"); |
|
343 |
+ return(0); |
|
276 | 344 |
} |
277 | 345 |
|
278 | 346 |
int |
279 | 347 |
wk_serve_error(wk *paramweb, int connid, wk_error wkerror) |
280 | 348 |
{ |
281 |
- |
|
349 |
+ static const char strnotfound[]={"\ |
|
350 |
+HTTP/1.1 404 Not found\r\n\ |
|
351 |
+Content-Type: text/html\r\n\ |
|
352 |
+Content-Length: 113\r\n\ |
|
353 |
+\r\n\ |
|
354 |
+<title>404 Not Found</title>\r\n\ |
|
355 |
+<h1>404 Not Found</h1>\r\n\ |
|
356 |
+The requested resource could not be found on this server.\r\n\ |
|
357 |
+"}; |
|
358 |
+ static const char strinternal[]={"\ |
|
359 |
+HTTP/1.1 500 Internal Server Error\r\n\ |
|
360 |
+Content-Type: text/html\r\n\ |
|
361 |
+Content-Length: 118\r\n\ |
|
362 |
+\r\n\ |
|
363 |
+<title>500 Internal Server Error</title>\r\n\ |
|
364 |
+<h1>500 Internal Server Error</h1>\r\n\ |
|
365 |
+Internal error processing the request.\r\n\ |
|
366 |
+"}; |
|
367 |
+ static const char strnotimplemented[]={"\ |
|
368 |
+HTTP/1.1 501 Not Implemented\r\n\ |
|
369 |
+Content-Type: text/html\r\n\ |
|
370 |
+Content-Length: 132\r\n\ |
|
371 |
+\r\n\ |
|
372 |
+<title>501 Not Implemented</title>\r\n\ |
|
373 |
+<h1>501 Not Implemented</h1>\r\n\ |
|
374 |
+The request was not understood or is not allowed by this server.\r\n\ |
|
375 |
+"}; |
|
376 |
+ int res; |
|
377 |
+ _wk *web=(_wk *)paramweb; |
|
378 |
+ wk_client *client; |
|
379 |
+ if(web==NULL) |
|
380 |
+ return(-1); |
|
381 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
382 |
+ return(-1); |
|
383 |
+ if(wkerror==wkerr_notfound) |
|
384 |
+ res=wk_write((wk *)web,connid,strnotfound,sizeof(strnotfound)-1); |
|
385 |
+ else if(wkerror==wkerr_notimplemented) |
|
386 |
+ res=wk_write((wk *)web,connid,strnotimplemented,sizeof(strnotimplemented)-1); |
|
387 |
+ else |
|
388 |
+ res=wk_write((wk *)web,connid,strinternal,sizeof(strinternal)-1); |
|
389 |
+ return(res); |
|
282 | 390 |
} |
283 | 391 |
|
284 | 392 |
int |
285 |
-wk_writestr(wk *paramweb, int connid, char *str) |
|
393 |
+wk_writestr(wk *paramweb, int connid, const char *str) |
|
286 | 394 |
{ |
287 | 395 |
return(wk_write(paramweb,connid,str,strlen(str))); |
288 | 396 |
} |
289 | 397 |
|
290 | 398 |
int |
291 |
-wk_write(wk *paramweb, int connid, void *data, int datalen) |
|
399 |
+wk_write(wk *paramweb, int connid, const void *data, int datalen) |
|
292 | 400 |
{ |
293 | 401 |
int k; |
294 | 402 |
_wk *web=(_wk *)paramweb; |
... | ... |
@@ -317,6 +425,8 @@ wk_write(wk *paramweb, int connid, void *data, int datalen) |
317 | 425 |
datalen-=added; |
318 | 426 |
total+=added; |
319 | 427 |
} |
428 |
+ if(total>0) |
|
429 |
+ sselect_addwrite(web->ssel,client->fd,(void *)client); |
|
320 | 430 |
return(total); |
321 | 431 |
} |
322 | 432 |
|
... | ... |
@@ -335,6 +445,8 @@ wk_close(wk *paramweb, int connid) |
335 | 445 |
FD_CLR(client->fd,&(web->fdset)); |
336 | 446 |
close(client->fd),client->fd=-1; |
337 | 447 |
} |
448 |
+ if(client->fdtoserve!=-1) |
|
449 |
+ close(client->fdtoserve),client->fdtoserve=-1; |
|
338 | 450 |
wk_clientrelease(web,connid); |
339 | 451 |
if(web->callback_event!=NULL) |
340 | 452 |
web->callback_event((wk *)web,connid,wke_closed,web->userptr); |
... | ... |
@@ -342,15 +454,32 @@ wk_close(wk *paramweb, int connid) |
342 | 454 |
} |
343 | 455 |
|
344 | 456 |
char * |
345 |
-wk_uri_getheader(wk_uri *wkuri, char *header, char *defaultvalue) |
|
457 |
+wk_uri_getheader(wk_uri *uri, char *header, char *defaultvalue) |
|
346 | 458 |
{ |
347 |
- |
|
459 |
+ int n,len; |
|
460 |
+ char *ptr; |
|
461 |
+ if(uri==NULL || uri->headers==NULL || header==NULL) |
|
462 |
+ return(NULL); |
|
463 |
+ len=strlen(header); |
|
464 |
+ for(n=0,ptr=uri->headers;*ptr!='\0';ptr++,n++) { |
|
465 |
+ if(memcmp(ptr,header,len)==0 && ptr[len]==':' && ptr[len+1]==' ') |
|
466 |
+ return(ptr+len+2); |
|
467 |
+ } |
|
468 |
+ return(defaultvalue); |
|
348 | 469 |
} |
349 | 470 |
|
350 | 471 |
char * |
351 |
-wk_uri_getheaderbynum(wk_uri *wkuri, int num) |
|
472 |
+wk_uri_getheaderbynum(wk_uri *uri, int num) |
|
352 | 473 |
{ |
353 |
- |
|
474 |
+ int n; |
|
475 |
+ char *ptr; |
|
476 |
+ if(uri==NULL || uri->headers==NULL) |
|
477 |
+ return(NULL); |
|
478 |
+ for(n=0,ptr=uri->headers;*ptr!='\0';ptr++,n++) { |
|
479 |
+ if(n==num) |
|
480 |
+ return(ptr); |
|
481 |
+ } |
|
482 |
+ return(NULL); |
|
354 | 483 |
} |
355 | 484 |
|
356 | 485 |
const char * |
... | ... |
@@ -584,6 +713,8 @@ wk_clientacquire(_wk *web) |
584 | 713 |
return(NULL); /* insufficient memory */ |
585 | 714 |
} |
586 | 715 |
client->usedoutbufids=1; |
716 |
+ client->fdtoserve=-1; |
|
717 |
+ client->headerbufid=-1; |
|
587 | 718 |
return(client); |
588 | 719 |
} |
589 | 720 |
|
... | ... |
@@ -604,6 +735,8 @@ wk_clientrelease(_wk *web, int connid) |
604 | 735 |
wk_sbufrelease((wk *)web,client->inbufid),client->inbufid=-1; |
605 | 736 |
for(w=0;w<client->usedoutbufids;w++) |
606 | 737 |
wk_sbufrelease((wk *)web,client->outbufids[w]),client->outbufids[w]=-1; |
738 |
+ if(client->headerbufid!=-1) |
|
739 |
+ wk_sbufrelease((wk *)web,client->headerbufid),client->headerbufid=-1; |
|
607 | 740 |
memset(client,0,sizeof(wk_client)); |
608 | 741 |
return(0); |
609 | 742 |
} |
... | ... |
@@ -624,9 +757,98 @@ wk_clientget(_wk *web, int connid) |
624 | 757 |
return(web->clientblocks[numblock].clients+j); |
625 | 758 |
} |
626 | 759 |
|
627 |
-static void |
|
760 |
+static char * |
|
761 |
+str_findfirstempty(char *ptr, int size) |
|
762 |
+{ |
|
763 |
+ int i; |
|
764 |
+ for(i=0;i<(size-3);i++) { |
|
765 |
+ if(ptr[0]=='\r' && ptr[1]=='\n' && ptr[2]=='\r' && ptr[3]=='\n') |
|
766 |
+ return(ptr); |
|
767 |
+ } |
|
768 |
+ return(NULL); |
|
769 |
+} |
|
770 |
+ |
|
771 |
+static int |
|
628 | 772 |
wk_clientserviceread(_wk *web, wk_client *client) |
629 | 773 |
{ |
630 |
-#warning TODO |
|
774 |
+ sbuf *in,*hbuf; |
|
775 |
+ char *end; |
|
776 |
+ char *ptr; |
|
777 |
+ char *lineend; |
|
778 |
+ char *sep; |
|
779 |
+ wk_uri *uri; |
|
780 |
+ /* check if we have all the headers */ |
|
781 |
+ if((in=wk_sbufget((wk *)web, client->inbufid))==NULL) |
|
782 |
+ return(-1); /* internal error */ |
|
783 |
+ sbuf_discard(in); |
|
784 |
+ if((end=str_findfirstempty(sbuf_ptr(in),sbuf_count(in)))==NULL) { |
|
785 |
+ if(sbuf_unused(in)==0) |
|
786 |
+ return(-1); /* header part too long */ |
|
787 |
+ /* uncomplete headers, have to wait for more data */ |
|
788 |
+ return(0); |
|
789 |
+ } |
|
790 |
+ /* get memory for the uri data */ |
|
791 |
+ if(client->headerbufid!=-1) |
|
792 |
+ wk_sbufrelease((wk *)web,client->headerbufid),client->headerbufid=-1; |
|
793 |
+ if((client->headerbufid=wk_sbufacquire((wk *)web))==-1) |
|
794 |
+ return(-1); /* insufficient memory */ |
|
795 |
+ if((hbuf=wk_sbufget((wk *)web,client->headerbufid))==NULL) |
|
796 |
+ return(-1); /* internal error */ |
|
797 |
+ /* prepare to fill the uri struct */ |
|
798 |
+ uri=&(client->uri); |
|
799 |
+ memset(uri,0,sizeof(wk_uri)); |
|
800 |
+ /* check that the method is supported */ |
|
801 |
+ ptr=sbuf_ptr(in); |
|
802 |
+ if(memcmp(ptr,"GET ",4)!=0 && memcmp(ptr,"PUT ",4)!=0 && memcmp(ptr,"POST ",5)!=0) |
|
803 |
+ return(-1); /* unknown method */ |
|
804 |
+ if((lineend=strchr(ptr,'\r'))!=NULL) |
|
805 |
+ *lineend='\0'; |
|
806 |
+ else |
|
807 |
+ lineend=end; |
|
808 |
+ /* method */ |
|
809 |
+ sep=strchr(ptr,' '); |
|
810 |
+ *sep='\0'; |
|
811 |
+ uri->method=sbuf_ptrunused(hbuf); |
|
812 |
+ sbuf_add(hbuf,ptr,strlen(ptr)+1); |
|
813 |
+ ptr+=strlen(ptr)+1; |
|
814 |
+ /* path */ |
|
815 |
+ if((sep=strchr(ptr,' '))==NULL) |
|
816 |
+ return(-1); /* no separator between path and protocol */ |
|
817 |
+ *sep='\0'; |
|
818 |
+ uri->path=sbuf_ptrunused(hbuf); |
|
819 |
+ sbuf_add(hbuf,ptr,strlen(ptr)+1); |
|
820 |
+ ptr+=strlen(ptr)+1; |
|
821 |
+ /* protocol */ |
|
822 |
+ uri->path=sbuf_ptrunused(hbuf); |
|
823 |
+ sbuf_add(hbuf,ptr,strlen(ptr)+1); |
|
824 |
+ ptr+=strlen(ptr)+1; |
|
825 |
+ /* headers */ |
|
826 |
+ *end='\0'; |
|
827 |
+ uri->headers=sbuf_ptrunused(hbuf); |
|
828 |
+ client->keepalive=0; |
|
829 |
+ while(ptr<end) { |
|
830 |
+ if(*ptr!='\n') |
|
831 |
+ return(-1); /* line is not ended with \r\n */ |
|
832 |
+ ptr++; |
|
833 |
+ if((lineend=strchr(ptr,'\r'))!=NULL) |
|
834 |
+ *lineend='\0'; |
|
835 |
+ else |
|
836 |
+ lineend=end; |
|
837 |
+ if((sep=strchr(ptr,':'))==NULL || sep[1]!=' ') |
|
838 |
+ return(-1); /* header not in format "name: value" */ |
|
839 |
+ /* check for keepalive header */ |
|
840 |
+ if(memcmp(ptr,"Connection: ",12)==0 && |
|
841 |
+ (strcmp(ptr+12,"keep-alive")==0 || strcmp(ptr+12,"Keep-Alive")==0)) |
|
842 |
+ client->keepalive=1; |
|
843 |
+ sbuf_add(hbuf,ptr,strlen(ptr)+1); |
|
844 |
+ ptr+=strlen(ptr)+1; |
|
845 |
+ } |
|
846 |
+ /* add header terminator */ |
|
847 |
+ sbuf_add(hbuf,"",1); |
|
848 |
+ /* call the http method */ |
|
849 |
+ client->serviced=1; |
|
850 |
+ client->continuationactive=0; |
|
851 |
+ client->continuationactive=web->callback_http((wk *)web, client->connid, uri, web->userptr); |
|
852 |
+ return(0); |
|
631 | 853 |
} |
632 | 854 |
|
... | ... |
@@ -255,7 +255,6 @@ wk_service(wk *paramweb) |
255 | 255 |
client->serviced=0; /* we have finished servicing this one */ |
256 | 256 |
if(!client->keepalive) |
257 | 257 |
wk_close((wk *)web, fd); /* all sent */ |
258 |
- |
|
259 | 258 |
} |
260 | 259 |
} |
261 | 260 |
} |
... | ... |
@@ -285,13 +284,40 @@ wk_serve_error(wk *paramweb, int connid, wk_error wkerror) |
285 | 284 |
int |
286 | 285 |
wk_writestr(wk *paramweb, int connid, char *str) |
287 | 286 |
{ |
288 |
- |
|
287 |
+ return(wk_write(paramweb,connid,str,strlen(str))); |
|
289 | 288 |
} |
290 | 289 |
|
291 | 290 |
int |
292 | 291 |
wk_write(wk *paramweb, int connid, void *data, int datalen) |
293 | 292 |
{ |
294 |
- |
|
293 |
+ int k; |
|
294 |
+ _wk *web=(_wk *)paramweb; |
|
295 |
+ wk_client *client; |
|
296 |
+ sbuf *out; |
|
297 |
+ long added; |
|
298 |
+ long total; |
|
299 |
+ if(web==NULL) |
|
300 |
+ return(-1); |
|
301 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
302 |
+ return(-1); |
|
303 |
+ total=0; |
|
304 |
+ for(k=(client->usedoutbufids>0)?client->usedoutbufids-1:0; |
|
305 |
+ datalen>0 && k<MAXOUTBUF;k++) { |
|
306 |
+ if(client->outbufids[k]==-1) { |
|
307 |
+ if((client->outbufids[k]=wk_sbufacquire((wk *)web))==-1) |
|
308 |
+ return(-1); /* insufficient memory */ |
|
309 |
+ client->usedoutbufids++; |
|
310 |
+ } |
|
311 |
+ if((out=wk_sbufget((wk *)web,client->outbufids[k]))==NULL) |
|
312 |
+ return(-1); /* internal error */ |
|
313 |
+ if(sbuf_unused(out)==0) |
|
314 |
+ continue; |
|
315 |
+ added=sbuf_add(out,data,datalen); |
|
316 |
+ data+=added; |
|
317 |
+ datalen-=added; |
|
318 |
+ total+=added; |
|
319 |
+ } |
|
320 |
+ return(total); |
|
295 | 321 |
} |
296 | 322 |
|
297 | 323 |
int |
... | ... |
@@ -33,6 +33,10 @@ typedef struct wk_client { |
33 | 33 |
int sizeoutbufids; |
34 | 34 |
int usedoutbufids; |
35 | 35 |
int outbufids[MAXOUTBUF]; |
36 |
+ int serviced; |
|
37 |
+ wk_uri uri; |
|
38 |
+ int continuationactive; |
|
39 |
+ int keepalive; |
|
36 | 40 |
} wk_client; |
37 | 41 |
|
38 | 42 |
typedef struct wk_clientblock { |
... | ... |
@@ -64,15 +68,20 @@ typedef struct _wk { |
64 | 68 |
int sizebufblocks; |
65 | 69 |
int usedbufblocks; |
66 | 70 |
wk_bufblock *bufblocks; |
71 |
+ void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/); |
|
72 |
+ wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
|
73 |
+ wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/); |
|
74 |
+ void *userptr; |
|
67 | 75 |
} _wk; |
68 | 76 |
|
69 |
-static int wk_accept(_wk *web); |
|
77 |
+static wk_client *wk_accept(_wk *web); |
|
70 | 78 |
static wk_client *wk_clientacquire(_wk *web); |
71 | 79 |
static int wk_clientrelease(_wk *web, int connid); |
72 | 80 |
static wk_client *wk_clientget(_wk *web, int connid); |
81 |
+static void wk_clientserviceread(_wk *web, wk_client *client); |
|
73 | 82 |
|
74 | 83 |
wk * |
75 |
-wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int connid, wk_event event, void *userptr*/), void (*callback_http)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void (*callback_continuation)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
84 |
+wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *web,int connid, wk_event event, void *userptr*/), wk_action (*callback_http)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), wk_action (*callback_continuation)(/*wk *web,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
76 | 85 |
{ |
77 | 86 |
_wk *web; |
78 | 87 |
if(ssel==NULL || callback_http==NULL) |
... | ... |
@@ -81,6 +90,10 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int conni |
81 | 90 |
return(NULL); |
82 | 91 |
memset(web,0,sizeof(_wk)); |
83 | 92 |
web->serverfd=-1; |
93 |
+ web->callback_event=callback_event; |
|
94 |
+ web->callback_http=callback_http; |
|
95 |
+ web->callback_continuation=callback_continuation; |
|
96 |
+ web->userptr=userptr; |
|
84 | 97 |
web->ssel=ssel; |
85 | 98 |
FD_ZERO(&(web->fdset)); |
86 | 99 |
if((web->serverfd=ipv4_server(port))==-1) { |
... | ... |
@@ -90,6 +103,8 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int conni |
90 | 103 |
sock_setunsafe(web->serverfd); |
91 | 104 |
FD_SET(web->serverfd,&(web->fdset)); |
92 | 105 |
sselect_addread(ssel,web->serverfd,NULL); |
106 |
+ if(web->callback_event!=NULL) |
|
107 |
+ web->callback_event((wk *)web,-1,wke_init,web->userptr); |
|
93 | 108 |
return((wk *)web); |
94 | 109 |
} |
95 | 110 |
|
... | ... |
@@ -103,6 +118,8 @@ wk_free(wk *paramweb) |
103 | 118 |
wk_bufblock *bb; |
104 | 119 |
if(web==NULL) |
105 | 120 |
return; |
121 |
+ if(web->callback_event!=NULL) |
|
122 |
+ web->callback_event((wk *)web,-1,wke_fini,web->userptr); |
|
106 | 123 |
/* release server fds */ |
107 | 124 |
if(web->serverfd!=-1) { |
108 | 125 |
sselect_delread(web->ssel,web->serverfd); |
... | ... |
@@ -137,7 +154,7 @@ wk_free(wk *paramweb) |
137 | 154 |
web->sizeclientblocks=0; |
138 | 155 |
if(web->clientblocks!=NULL) |
139 | 156 |
free(web->clientblocks),web->clientblocks=NULL; |
140 |
- /* release the used sbuf */ |
|
157 |
+ /* release the used sbuf */ |
|
141 | 158 |
for(i=0;i<web->usedbufblocks;i++) { |
142 | 159 |
bb=web->bufblocks+i; |
143 | 160 |
if(bb->bufs==NULL) |
... | ... |
@@ -157,7 +174,15 @@ wk_free(wk *paramweb) |
157 | 174 |
wk_uri * |
158 | 175 |
wk_geturi(wk *paramweb, int connid) |
159 | 176 |
{ |
160 |
- |
|
177 |
+ _wk *web=(_wk *)paramweb; |
|
178 |
+ wk_client *client; |
|
179 |
+ if(web==NULL) |
|
180 |
+ return(NULL); |
|
181 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
182 |
+ return(NULL); |
|
183 |
+ if(client->serviced==0) |
|
184 |
+ return(NULL); |
|
185 |
+ return(&(client->uri)); |
|
161 | 186 |
} |
162 | 187 |
|
163 | 188 |
int |
... | ... |
@@ -165,8 +190,9 @@ wk_service(wk *paramweb) |
165 | 190 |
{ |
166 | 191 |
int fds[FDBLOCK]; |
167 | 192 |
int fd; |
168 |
- int n; |
|
169 |
- int i; |
|
193 |
+ int n,i,k; |
|
194 |
+ sbuf *in; |
|
195 |
+ sbuf *out; |
|
170 | 196 |
_wk *web=(_wk *)paramweb; |
171 | 197 |
wk_client *client; |
172 | 198 |
if(web==NULL) |
... | ... |
@@ -176,14 +202,66 @@ wk_service(wk *paramweb) |
176 | 202 |
fd=fds[i]; |
177 | 203 |
if(fd==web->serverfd) { |
178 | 204 |
/* accept new connection */ |
179 |
- wk_accept(web); |
|
205 |
+ if((client=wk_accept(web))!=NULL && web->callback_event!=NULL) |
|
206 |
+ web->callback_event((wk *)web,client->connid,wke_connected,web->userptr); |
|
207 |
+ continue; /* all done here */ |
|
208 |
+ } |
|
209 |
+ if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) { |
|
210 |
+ wk_close((wk *)web,client->connid); |
|
211 |
+ continue; /* internal error */ |
|
212 |
+ } |
|
213 |
+ if((in=wk_sbufget((wk *) web,client->inbufid))==NULL) { |
|
214 |
+ wk_close((wk *)web,client->connid); |
|
215 |
+ continue; /* internal error */ |
|
216 |
+ } |
|
217 |
+ if(sbuf_unused(in)<=0) { |
|
218 |
+ /* no room for the new data */ |
|
219 |
+ sselect_delread(web->ssel,fd); |
|
220 |
+ continue; |
|
221 |
+ } |
|
222 |
+ if(sbuf_fill(in,fd,sock_queued(fd))==0) { |
|
223 |
+ /* client has closed connection */ |
|
224 |
+ wk_close((wk *) web, fd); |
|
180 | 225 |
continue; |
181 | 226 |
} |
227 |
+ wk_clientserviceread(web,client); |
|
228 |
+ } |
|
229 |
+ } |
|
230 |
+ while((n=sselect_getwritefiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
231 |
+ for(i=0;i<n;i++) { |
|
232 |
+ fd=fds[i]; |
|
182 | 233 |
if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) |
183 | 234 |
continue; /* internal error */ |
184 |
- |
|
235 |
+ for(out=NULL,k=client->usedoutbufids-1;k>=0;k--) { |
|
236 |
+ if((out=wk_sbufget((wk *) web,client->outbufids[k]))==NULL) { |
|
237 |
+ k=-1; |
|
238 |
+ break; /* internal error */ |
|
239 |
+ } |
|
240 |
+ } |
|
241 |
+ if(k==-1 || out==NULL) { |
|
242 |
+ wk_close((wk *)web,client->connid); |
|
243 |
+ continue; /* internal error */ |
|
244 |
+ } |
|
245 |
+ sbuf_send(out,fd,sbuf_count(out)); |
|
246 |
+ if(sbuf_count(out)==0) { |
|
247 |
+ if(k>0) { |
|
248 |
+ client->usedoutbufids--; |
|
249 |
+ wk_sbufrelease((wk *)web,client->outbufids[k]),client->outbufids[k]=-1; |
|
250 |
+ } else { |
|
251 |
+ sselect_delwrite(web->ssel,client->fd); |
|
252 |
+ if(client->continuationactive && web->callback_continuation!=NULL) { |
|
253 |
+ client->continuationactive=web->callback_continuation((wk *)web,client->connid,&(client->uri),web->userptr); |
|
254 |
+ } else { |
|
255 |
+ client->serviced=0; /* we have finished servicing this one */ |
|
256 |
+ if(!client->keepalive) |
|
257 |
+ wk_close((wk *)web, fd); /* all sent */ |
|
258 |
+ |
|
259 |
+ } |
|
260 |
+ } |
|
261 |
+ } |
|
185 | 262 |
} |
186 | 263 |
} |
264 |
+ return(0); |
|
187 | 265 |
} |
188 | 266 |
|
189 | 267 |
int |
... | ... |
@@ -219,7 +297,22 @@ wk_write(wk *paramweb, int connid, void *data, int datalen) |
219 | 297 |
int |
220 | 298 |
wk_close(wk *paramweb, int connid) |
221 | 299 |
{ |
222 |
- |
|
300 |
+ _wk *web=(_wk *)paramweb; |
|
301 |
+ wk_client *client; |
|
302 |
+ if(web==NULL) |
|
303 |
+ return(-1); |
|
304 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
305 |
+ return(-1); |
|
306 |
+ if(client->fd!=-1) { |
|
307 |
+ sselect_delread(web->ssel,client->fd); |
|
308 |
+ sselect_delwrite(web->ssel,client->fd); |
|
309 |
+ FD_CLR(client->fd,&(web->fdset)); |
|
310 |
+ close(client->fd),client->fd=-1; |
|
311 |
+ } |
|
312 |
+ wk_clientrelease(web,connid); |
|
313 |
+ if(web->callback_event!=NULL) |
|
314 |
+ web->callback_event((wk *)web,connid,wke_closed,web->userptr); |
|
315 |
+ return(0); |
|
223 | 316 |
} |
224 | 317 |
|
225 | 318 |
char * |
... | ... |
@@ -384,21 +477,21 @@ wk_bufget(wk *paramweb, int sbufid) |
384 | 477 |
|
385 | 478 |
|
386 | 479 |
/* local functions */ |
387 |
-static int |
|
480 |
+static wk_client * |
|
388 | 481 |
wk_accept(_wk *web) |
389 | 482 |
{ |
390 | 483 |
int newfd; |
391 | 484 |
wk_client *client; |
392 | 485 |
if((newfd=sock_accept(web->serverfd))==-1) |
393 |
- return(-1); |
|
486 |
+ return(NULL); |
|
394 | 487 |
if((client=wk_clientacquire(web))==NULL) { |
395 | 488 |
close(newfd),newfd=-1; |
396 |
- return(-1); |
|
489 |
+ return(NULL); |
|
397 | 490 |
} |
398 | 491 |
client->fd=newfd; |
399 | 492 |
FD_SET(client->fd,&(web->fdset)); |
400 | 493 |
sselect_addread(web->ssel,client->fd,(void *)client); |
401 |
- return(0); |
|
494 |
+ return(client); |
|
402 | 495 |
} |
403 | 496 |
|
404 | 497 |
static wk_client * |
... | ... |
@@ -483,7 +576,7 @@ wk_clientrelease(_wk *web, int connid) |
483 | 576 |
web->clientblocks[numblock].acquired[j>>3]&=(~bit); |
484 | 577 |
if(client->inbufid!=-1) |
485 | 578 |
wk_sbufrelease((wk *)web,client->inbufid),client->inbufid=-1; |
486 |
- for(w=0;w<client->usedoutbufids;w++) |
|
579 |
+ for(w=0;w<client->usedoutbufids;w++) |
|
487 | 580 |
wk_sbufrelease((wk *)web,client->outbufids[w]),client->outbufids[w]=-1; |
488 | 581 |
memset(client,0,sizeof(wk_client)); |
489 | 582 |
return(0); |
... | ... |
@@ -505,4 +598,9 @@ wk_clientget(_wk *web, int connid) |
505 | 598 |
return(web->clientblocks[numblock].clients+j); |
506 | 599 |
} |
507 | 600 |
|
601 |
+static void |
|
602 |
+wk_clientserviceread(_wk *web, wk_client *client) |
|
603 |
+{ |
|
604 |
+#warning TODO |
|
605 |
+} |
|
508 | 606 |
|
... | ... |
@@ -100,6 +100,7 @@ wk_free(wk *paramweb) |
100 | 100 |
_wk *web=(_wk *)paramweb; |
101 | 101 |
wk_clientblock *cb; |
102 | 102 |
wk_client *client; |
103 |
+ wk_bufblock *bb; |
|
103 | 104 |
if(web==NULL) |
104 | 105 |
return; |
105 | 106 |
/* release server fds */ |
... | ... |
@@ -136,6 +137,19 @@ wk_free(wk *paramweb) |
136 | 137 |
web->sizeclientblocks=0; |
137 | 138 |
if(web->clientblocks!=NULL) |
138 | 139 |
free(web->clientblocks),web->clientblocks=NULL; |
140 |
+ /* release the used sbuf */ |
|
141 |
+ for(i=0;i<web->usedbufblocks;i++) { |
|
142 |
+ bb=web->bufblocks+i; |
|
143 |
+ if(bb->bufs==NULL) |
|
144 |
+ continue; |
|
145 |
+ bb->usedbufs=0; |
|
146 |
+ bb->sizebufs=0; |
|
147 |
+ free(bb->bufs),bb->bufs=NULL; |
|
148 |
+ } |
|
149 |
+ web->usedbufblocks=0; |
|
150 |
+ web->sizebufblocks=0; |
|
151 |
+ if(web->bufblocks!=NULL) |
|
152 |
+ free(web->bufblocks),web->bufblocks=NULL; |
|
139 | 153 |
/* free the main struct */ |
140 | 154 |
free(web),web=NULL; |
141 | 155 |
} |
... | ... |
@@ -335,7 +349,7 @@ wk_bufrelease(wk *paramweb, int sbufid) |
335 | 349 |
sbuf *buf; |
336 | 350 |
int numblock,j,bit; |
337 | 351 |
_wk *web=(_wk *)paramweb; |
338 |
- if(web==NULL) |
|
352 |
+ if(web==NULL || sbufid<0) |
|
339 | 353 |
return(-1); |
340 | 354 |
numblock=sbufid/BUFBLOCK; |
341 | 355 |
j=sbufid%BUFBLOCK; |
... | ... |
@@ -393,6 +407,7 @@ wk_clientacquire(_wk *web) |
393 | 407 |
int i,j,k; |
394 | 408 |
wk_clientblock *cb; |
395 | 409 |
wk_client *client; |
410 |
+ int w; |
|
396 | 411 |
/* make sure there are free clientblocks */ |
397 | 412 |
if(web->usedclientblocks==web->sizeclientblocks) { |
398 | 413 |
wk_clientblock *newcb; |
... | ... |
@@ -439,6 +454,17 @@ wk_clientacquire(_wk *web) |
439 | 454 |
client->web=(wk *)web; |
440 | 455 |
client->connid=i*CLIENTBLOCK+j; |
441 | 456 |
client->fd=-1; |
457 |
+ if((client->inbufid=wk_sbufacquire((wk *)web))==-1) { |
|
458 |
+ wk_clientrelease(web,client->connid); |
|
459 |
+ return(NULL); /* insufficient memory */ |
|
460 |
+ } |
|
461 |
+ for(w=0;w<MAXOUTBUF;w++) |
|
462 |
+ client->outbufids[w]=-1; |
|
463 |
+ if((client->outbufids[0]=wk_sbufacquire((wk *)web))==-1) { |
|
464 |
+ wk_clientrelease(web,client->connid); |
|
465 |
+ return(NULL); /* insufficient memory */ |
|
466 |
+ } |
|
467 |
+ client->usedoutbufids=1; |
|
442 | 468 |
return(client); |
443 | 469 |
} |
444 | 470 |
|
... | ... |
@@ -447,6 +473,7 @@ wk_clientrelease(_wk *web, int connid) |
447 | 473 |
{ |
448 | 474 |
wk_client *client; |
449 | 475 |
int numblock,j,bit; |
476 |
+ int w; |
|
450 | 477 |
numblock=connid/CLIENTBLOCK; |
451 | 478 |
j=connid%CLIENTBLOCK; |
452 | 479 |
bit=0x1<<(j&3); |
... | ... |
@@ -454,6 +481,10 @@ wk_clientrelease(_wk *web, int connid) |
454 | 481 |
return(-1); |
455 | 482 |
web->clientblocks[numblock].usedclients--; |
456 | 483 |
web->clientblocks[numblock].acquired[j>>3]&=(~bit); |
484 |
+ if(client->inbufid!=-1) |
|
485 |
+ wk_sbufrelease((wk *)web,client->inbufid),client->inbufid=-1; |
|
486 |
+ for(w=0;w<client->usedoutbufids;w++) |
|
487 |
+ wk_sbufrelease((wk *)web,client->outbufids[w]),client->outbufids[w]=-1; |
|
457 | 488 |
memset(client,0,sizeof(wk_client)); |
458 | 489 |
return(0); |
459 | 490 |
} |
... | ... |
@@ -12,18 +12,27 @@ |
12 | 12 |
#include <stdlib.h> |
13 | 13 |
#include <unistd.h> |
14 | 14 |
#include <string.h> |
15 |
+#include "sbuf.h" |
|
15 | 16 |
#include "socklib.h" |
16 | 17 |
#include "webkernel.h" |
17 | 18 |
|
18 | 19 |
#define FDBLOCK 256 |
19 | 20 |
#define CLIENTBLOCK 1024 |
20 | 21 |
#define CLIENTBLOCKBLOCK 256 |
22 |
+#define MAXOUTBUF 128 |
|
23 |
+#define BUFSIZE 8192 |
|
24 |
+#define BUFBLOCK 128 |
|
25 |
+#define BUFBLOCKBLOCK 256 |
|
21 | 26 |
|
22 | 27 |
|
23 | 28 |
typedef struct wk_client { |
24 | 29 |
wk *web; |
25 |
- int connid; /* it is numblock*CLIENTBLOCK+offset_in_block */ |
|
30 |
+ int connid; /* this is numblock*CLIENTBLOCK+offset_in_block */ |
|
26 | 31 |
int fd; |
32 |
+ int inbufid; |
|
33 |
+ int sizeoutbufids; |
|
34 |
+ int usedoutbufids; |
|
35 |
+ int outbufids[MAXOUTBUF]; |
|
27 | 36 |
} wk_client; |
28 | 37 |
|
29 | 38 |
typedef struct wk_clientblock { |
... | ... |
@@ -33,6 +42,18 @@ typedef struct wk_clientblock { |
33 | 42 |
wk_client *clients; |
34 | 43 |
} wk_clientblock; |
35 | 44 |
|
45 |
+typedef struct wk_buf { |
|
46 |
+ sbuf buf; |
|
47 |
+ char bufdata[BUFSIZE]; |
|
48 |
+} wk_buf; |
|
49 |
+ |
|
50 |
+typedef struct wk_bufblock { |
|
51 |
+ int sizebufs; |
|
52 |
+ int usedbufs; |
|
53 |
+ unsigned char acquired[BUFBLOCK/8]; |
|
54 |
+ wk_buf *bufs; |
|
55 |
+} wk_bufblock; |
|
56 |
+ |
|
36 | 57 |
typedef struct _wk { |
37 | 58 |
int serverfd; |
38 | 59 |
fd_set fdset; |
... | ... |
@@ -40,6 +61,9 @@ typedef struct _wk { |
40 | 61 |
int sizeclientblocks; |
41 | 62 |
int usedclientblocks; |
42 | 63 |
wk_clientblock *clientblocks; |
64 |
+ int sizebufblocks; |
|
65 |
+ int usedbufblocks; |
|
66 |
+ wk_bufblock *bufblocks; |
|
43 | 67 |
} _wk; |
44 | 68 |
|
45 | 69 |
static int wk_accept(_wk *web); |
... | ... |
@@ -63,6 +87,7 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int conni |
63 | 87 |
wk_free((wk *)web),web=NULL; |
64 | 88 |
return(NULL); |
65 | 89 |
} |
90 |
+ sock_setunsafe(web->serverfd); |
|
66 | 91 |
FD_SET(web->serverfd,&(web->fdset)); |
67 | 92 |
sselect_addread(ssel,web->serverfd,NULL); |
68 | 93 |
return((wk *)web); |
... | ... |
@@ -129,6 +154,7 @@ wk_service(wk *paramweb) |
129 | 154 |
int n; |
130 | 155 |
int i; |
131 | 156 |
_wk *web=(_wk *)paramweb; |
157 |
+ wk_client *client; |
|
132 | 158 |
if(web==NULL) |
133 | 159 |
return(-1); |
134 | 160 |
while((n=sselect_getreadfiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
... | ... |
@@ -139,6 +165,9 @@ wk_service(wk *paramweb) |
139 | 165 |
wk_accept(web); |
140 | 166 |
continue; |
141 | 167 |
} |
168 |
+ if((client=(wk_client *)sselect_getuserptr(web->ssel,fd))==NULL || client->web!=(wk *)web) |
|
169 |
+ continue; /* internal error */ |
|
170 |
+ |
|
142 | 171 |
} |
143 | 172 |
} |
144 | 173 |
} |
... | ... |
@@ -245,18 +274,101 @@ mime_getdefault(const char *filename, const char *defaultmime) |
245 | 274 |
return(defaultmime); |
246 | 275 |
} |
247 | 276 |
|
248 |
-siobuf * |
|
249 |
-wk_iobufget(wk *paramweb) |
|
277 |
+int |
|
278 |
+wk_sbufacquire(wk *paramweb) |
|
250 | 279 |
{ |
251 |
- |
|
280 |
+ int i,j,k; |
|
281 |
+ wk_bufblock *bb; |
|
282 |
+ sbuf *buf; |
|
283 |
+ _wk *web=(_wk *)paramweb; |
|
284 |
+ if(web==NULL) |
|
285 |
+ return(-1); |
|
286 |
+ /* make sure there are free bufblocks */ |
|
287 |
+ if(web->usedbufblocks==web->sizebufblocks) { |
|
288 |
+ wk_bufblock *newbb; |
|
289 |
+ if((newbb=(wk_bufblock *)realloc(web->bufblocks,web->sizebufblocks+BUFBLOCKBLOCK))==NULL) |
|
290 |
+ return(-1); /* insufficient memory */ |
|
291 |
+ web->bufblocks=newbb; |
|
292 |
+ memset(web->bufblocks+web->sizebufblocks,0,BUFBLOCKBLOCK*sizeof(wk_bufblock)); |
|
293 |
+ web->sizebufblocks+=BUFBLOCKBLOCK; |
|
294 |
+ } |
|
295 |
+ /* search for a block with unused sbufs (or the first unalloc'd block) */ |
|
296 |
+ for(i=0;i<web->sizebufblocks;i++) { |
|
297 |
+ bb=web->bufblocks+i; |
|
298 |
+ if(bb->bufs==NULL || bb->usedbufs<bb->sizebufs) |
|
299 |
+ break; |
|
300 |
+ } |
|
301 |
+ if(i>=web->sizebufblocks) |
|
302 |
+ return(-1); /* internal error */ |
|
303 |
+ /* alloc block if not alloc'd */ |
|
304 |
+ if(bb->bufs==NULL) { |
|
305 |
+ if((bb->bufs=malloc(sizeof(wk_buf)*BUFBLOCK))==NULL) |
|
306 |
+ return(-1); /* insufficient memory */ |
|
307 |
+ memset(bb->bufs,0,sizeof(wk_buf)*BUFBLOCK); |
|
308 |
+ bb->sizebufs=BUFBLOCK; |
|
309 |
+ bb->usedbufs=0; |
|
310 |
+ } |
|
311 |
+ /* get first unused sbuf */ |
|
312 |
+ for(j=0;j<bb->sizebufs;j+=8) { |
|
313 |
+ if(bb->acquired[j>>3]!=0xff) |
|
314 |
+ break; |
|
315 |
+ } |
|
316 |
+ if(j>=bb->sizebufs) |
|
317 |
+ return(-1); /* internal error */ |
|
318 |
+ for(k=0x01;k<0x100;k<<=1,j++) { |
|
319 |
+ if((bb->acquired[j>>3]&k)==0) |
|
320 |
+ break; |
|
321 |
+ } |
|
322 |
+ if(k>=0x100) |
|
323 |
+ return(-1); /* internal error */ |
|
324 |
+ bb->acquired[j>>3]|=k; |
|
325 |
+ bb->usedbufs++; |
|
326 |
+ /* initialize sbuf and return it */ |
|
327 |
+ buf=&(bb->bufs[j].buf); |
|
328 |
+ sbuf_staticinit(buf,BUFSIZE,bb->bufs[j].bufdata); |
|
329 |
+ return(i*BUFBLOCK+j); |
|
252 | 330 |
} |
253 | 331 |
|
254 |
-void |
|
255 |
-wk_iobuffree(wk *paramweb, int iobufnum) |
|
332 |
+int |
|
333 |
+wk_bufrelease(wk *paramweb, int sbufid) |
|
256 | 334 |
{ |
335 |
+ sbuf *buf; |
|
336 |
+ int numblock,j,bit; |
|
337 |
+ _wk *web=(_wk *)paramweb; |
|
338 |
+ if(web==NULL) |
|
339 |
+ return(-1); |
|
340 |
+ numblock=sbufid/BUFBLOCK; |
|
341 |
+ j=sbufid%BUFBLOCK; |
|
342 |
+ bit=0x1<<(j&3); |
|
343 |
+ if((buf=wk_sbufget(web,sbufid))==NULL) |
|
344 |
+ return(-1); |
|
345 |
+ web->bufblocks[numblock].usedbufs--; |
|
346 |
+ web->bufblocks[numblock].acquired[j>>3]&=(~bit); |
|
347 |
+ sbuf_staticfree(buf); |
|
348 |
+ memset(web->bufblocks[numblock].bufs[j].bufdata,0,sizeof(BUFSIZE)); |
|
349 |
+ return(0); |
|
350 |
+} |
|
257 | 351 |
|
352 |
+sbuf * |
|
353 |
+wk_bufget(wk *paramweb, int sbufid) |
|
354 |
+{ |
|
355 |
+ int numblock,j,bit; |
|
356 |
+ _wk *web=(_wk *)paramweb; |
|
357 |
+ if(web==NULL) |
|
358 |
+ return(NULL); |
|
359 |
+ numblock=sbufid/BUFBLOCK; |
|
360 |
+ j=sbufid%BUFBLOCK; |
|
361 |
+ bit=0x1<<(j&3); |
|
362 |
+ if(web==NULL || |
|
363 |
+ web->bufblocks==NULL || |
|
364 |
+ web->sizebufblocks<=numblock || |
|
365 |
+ web->bufblocks[numblock].bufs==NULL || |
|
366 |
+ (web->bufblocks[numblock].acquired[j>>3]&bit)!=bit) |
|
367 |
+ return(NULL); |
|
368 |
+ return(&(web->bufblocks[numblock].bufs[j].buf)); |
|
258 | 369 |
} |
259 | 370 |
|
371 |
+ |
|
260 | 372 |
/* local functions */ |
261 | 373 |
static int |
262 | 374 |
wk_accept(_wk *web) |
... | ... |
@@ -304,6 +416,7 @@ wk_clientacquire(_wk *web) |
304 | 416 |
return(NULL); /* insufficient memory */ |
305 | 417 |
memset(cb->clients,0,sizeof(wk_client)*CLIENTBLOCK); |
306 | 418 |
cb->sizeclients=CLIENTBLOCK; |
419 |
+ cb->usedclients=0; |
|
307 | 420 |
} |
308 | 421 |
/* get first unused client */ |
309 | 422 |
for(j=0;j<cb->sizeclients;j+=8) { |
... | ... |
@@ -361,3 +474,4 @@ wk_clientget(_wk *web, int connid) |
361 | 474 |
return(web->clientblocks[numblock].clients+j); |
362 | 475 |
} |
363 | 476 |
|
477 |
+ |
... | ... |
@@ -29,6 +29,7 @@ typedef struct wk_client { |
29 | 29 |
typedef struct wk_clientblock { |
30 | 30 |
int sizeclients; |
31 | 31 |
int usedclients; |
32 |
+ unsigned char acquired[CLIENTBLOCKBLOCK/8]; |
|
32 | 33 |
wk_client *clients; |
33 | 34 |
} wk_clientblock; |
34 | 35 |
|
... | ... |
@@ -44,7 +45,7 @@ typedef struct _wk { |
44 | 45 |
static int wk_accept(_wk *web); |
45 | 46 |
static wk_client *wk_clientacquire(_wk *web); |
46 | 47 |
static int wk_clientrelease(_wk *web, int connid); |
47 |
-wk_client *wk_clientget(_wk *web, int connid); |
|
48 |
+static wk_client *wk_clientget(_wk *web, int connid); |
|
48 | 49 |
|
49 | 50 |
wk * |
50 | 51 |
wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int connid, wk_event event, void *userptr*/), void (*callback_http)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void (*callback_continuation)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
... | ... |
@@ -70,14 +71,47 @@ wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int conni |
70 | 71 |
void |
71 | 72 |
wk_free(wk *paramweb) |
72 | 73 |
{ |
74 |
+ int i,j,k,n; |
|
73 | 75 |
_wk *web=(_wk *)paramweb; |
76 |
+ wk_clientblock *cb; |
|
77 |
+ wk_client *client; |
|
74 | 78 |
if(web==NULL) |
75 | 79 |
return; |
80 |
+ /* release server fds */ |
|
76 | 81 |
if(web->serverfd!=-1) { |
77 | 82 |
sselect_delread(web->ssel,web->serverfd); |
78 | 83 |
FD_CLR(web->serverfd,&(web->fdset)); |
79 | 84 |
close(web->serverfd),web->serverfd=-1; |
80 | 85 |
} |
86 |
+ /* release client fds and free clients */ |
|
87 |
+ for(i=0;i<web->usedclientblocks;i++) { |
|
88 |
+ cb=web->clientblocks+i; |
|
89 |
+ if(cb->clients==NULL) |
|
90 |
+ continue; |
|
91 |
+ for(j=0;j<cb->sizeclients;j+=8) { |
|
92 |
+ if(cb->acquired[j>>3]==0) |
|
93 |
+ continue; |
|
94 |
+ for(k=0x1,n=0;n<8;n++,k<<=1) { |
|
95 |
+ if(!(cb->acquired[j>>3]&k)) |
|
96 |
+ continue; |
|
97 |
+ client=cb->clients+j+k; |
|
98 |
+ if(client->fd!=-1) { |
|
99 |
+ sselect_delread(web->ssel,client->fd); |
|
100 |
+ sselect_delwrite(web->ssel,client->fd); |
|
101 |
+ FD_CLR(client->fd,&(web->fdset)); |
|
102 |
+ close(client->fd),client->fd=-1; |
|
103 |
+ } |
|
104 |
+ } |
|
105 |
+ } |
|
106 |
+ cb->usedclients=0; |
|
107 |
+ cb->sizeclients=0; |
|
108 |
+ free(cb->clients),cb->clients=NULL; |
|
109 |
+ } |
|
110 |
+ web->usedclientblocks=0; |
|
111 |
+ web->sizeclientblocks=0; |
|
112 |
+ if(web->clientblocks!=NULL) |
|
113 |
+ free(web->clientblocks),web->clientblocks=NULL; |
|
114 |
+ /* free the main struct */ |
|
81 | 115 |
free(web),web=NULL; |
82 | 116 |
} |
83 | 117 |
|
... | ... |
@@ -244,24 +278,86 @@ wk_accept(_wk *web) |
244 | 278 |
static wk_client * |
245 | 279 |
wk_clientacquire(_wk *web) |
246 | 280 |
{ |
247 |
-#warning TODO |
|
281 |
+ int i,j,k; |
|
282 |
+ wk_clientblock *cb; |
|
283 |
+ wk_client *client; |
|
284 |
+ /* make sure there are free clientblocks */ |
|
285 |
+ if(web->usedclientblocks==web->sizeclientblocks) { |
|
286 |
+ wk_clientblock *newcb; |
|
287 |
+ if((newcb=(wk_clientblock *)realloc(web->clientblocks,web->sizeclientblocks+CLIENTBLOCKBLOCK))==NULL) |
|
288 |
+ return(NULL); /* insufficient memory */ |
|
289 |
+ web->clientblocks=newcb; |
|
290 |
+ memset(web->clientblocks+web->sizeclientblocks,0,CLIENTBLOCKBLOCK*sizeof(wk_clientblock)); |
|
291 |
+ web->sizeclientblocks+=CLIENTBLOCKBLOCK; |
|
292 |
+ } |
|
293 |
+ /* search for a block with unused clients (or the first unalloc'd block) */ |
|
294 |
+ for(i=0;i<web->sizeclientblocks;i++) { |
|
295 |
+ cb=web->clientblocks+i; |
|
296 |
+ if(cb->clients==NULL || cb->usedclients<cb->sizeclients) |
|
297 |
+ break; |
|
298 |
+ } |
|
299 |
+ if(i>=web->sizeclientblocks) |
|
300 |
+ return(NULL); /* internal error */ |
|
301 |
+ /* alloc block if not alloc'd */ |
|
302 |
+ if(cb->clients==NULL) { |
|
303 |
+ if((cb->clients=malloc(sizeof(wk_client)*CLIENTBLOCK))==NULL) |
|
304 |
+ return(NULL); /* insufficient memory */ |
|
305 |
+ memset(cb->clients,0,sizeof(wk_client)*CLIENTBLOCK); |
|
306 |
+ cb->sizeclients=CLIENTBLOCK; |
|
307 |
+ } |
|
308 |
+ /* get first unused client */ |
|
309 |
+ for(j=0;j<cb->sizeclients;j+=8) { |
|
310 |
+ if(cb->acquired[j>>3]!=0xff) |
|
311 |
+ break; |
|
312 |
+ } |
|
313 |
+ if(j>=cb->sizeclients) |
|
314 |
+ return(NULL); /* internal error */ |
|
315 |
+ for(k=0x01;k<0x100;k<<=1,j++) { |
|
316 |
+ if((cb->acquired[j>>3]&k)==0) |
|
317 |
+ break; |
|
318 |
+ } |
|
319 |
+ if(k>=0x100) |
|
320 |
+ return(NULL); /* internal error */ |
|
321 |
+ cb->acquired[j>>3]|=k; |
|
322 |
+ cb->usedclients++; |
|
323 |
+ /* initialize client and return it */ |
|
324 |
+ client=cb->clients+j; |
|
325 |
+ memset(client,0,sizeof(wk_client)); |
|
326 |
+ client->web=(wk *)web; |
|
327 |
+ client->connid=i*CLIENTBLOCK+j; |
|
328 |
+ client->fd=-1; |
|
329 |
+ return(client); |
|
248 | 330 |
} |
249 | 331 |
|
250 | 332 |
static int |
251 | 333 |
wk_clientrelease(_wk *web, int connid) |
252 | 334 |
{ |
335 |
+ wk_client *client; |
|
336 |
+ int numblock,j,bit; |
|
337 |
+ numblock=connid/CLIENTBLOCK; |
|
338 |
+ j=connid%CLIENTBLOCK; |
|
339 |
+ bit=0x1<<(j&3); |
|
340 |
+ if((client=wk_clientget(web,connid))==NULL) |
|
341 |
+ return(-1); |
|
342 |
+ web->clientblocks[numblock].usedclients--; |
|
343 |
+ web->clientblocks[numblock].acquired[j>>3]&=(~bit); |
|
344 |
+ memset(client,0,sizeof(wk_client)); |
|
345 |
+ return(0); |
|
253 | 346 |
} |
254 | 347 |
|
255 |
-wk_client * |
|
348 |
+static wk_client * |
|
256 | 349 |
wk_clientget(_wk *web, int connid) |
257 | 350 |
{ |
258 |
- int numblock; |
|
351 |
+ int numblock,j,bit; |
|
259 | 352 |
numblock=connid/CLIENTBLOCK; |
353 |
+ j=connid%CLIENTBLOCK; |
|
354 |
+ bit=0x1<<(j&3); |
|
260 | 355 |
if(web==NULL || |
261 | 356 |
web->clientblocks==NULL || |
262 | 357 |
web->sizeclientblocks<=numblock || |
263 |
- web->clientblocks[numblock].clients==NULL) |
|
358 |
+ web->clientblocks[numblock].clients==NULL || |
|
359 |
+ (web->clientblocks[numblock].acquired[j>>3]&bit)!=bit) |
|
264 | 360 |
return(NULL); |
265 |
- return(web->clientblocks[numblock].clients+(connid%CLIENTBLOCK)); |
|
361 |
+ return(web->clientblocks[numblock].clients+j); |
|
266 | 362 |
} |
267 | 363 |
|
... | ... |
@@ -12,19 +12,58 @@ |
12 | 12 |
#include <stdlib.h> |
13 | 13 |
#include <unistd.h> |
14 | 14 |
#include <string.h> |
15 |
+#include "socklib.h" |
|
15 | 16 |
#include "webkernel.h" |
16 | 17 |
|
18 |
+#define FDBLOCK 256 |
|
19 |
+#define CLIENTBLOCK 1024 |
|
20 |
+#define CLIENTBLOCKBLOCK 256 |
|
21 |
+ |
|
22 |
+ |
|
23 |
+typedef struct wk_client { |
|
24 |
+ wk *web; |
|
25 |
+ int connid; /* it is numblock*CLIENTBLOCK+offset_in_block */ |
|
26 |
+ int fd; |
|
27 |
+} wk_client; |
|
28 |
+ |
|
29 |
+typedef struct wk_clientblock { |
|
30 |
+ int sizeclients; |
|
31 |
+ int usedclients; |
|
32 |
+ wk_client *clients; |
|
33 |
+} wk_clientblock; |
|
34 |
+ |
|
17 | 35 |
typedef struct _wk { |
18 |
- int dummy; |
|
36 |
+ int serverfd; |
|
37 |
+ fd_set fdset; |
|
38 |
+ sselect *ssel; |
|
39 |
+ int sizeclientblocks; |
|
40 |
+ int usedclientblocks; |
|
41 |
+ wk_clientblock *clientblocks; |
|
19 | 42 |
} _wk; |
20 | 43 |
|
44 |
+static int wk_accept(_wk *web); |
|
45 |
+static wk_client *wk_clientacquire(_wk *web); |
|
46 |
+static int wk_clientrelease(_wk *web, int connid); |
|
47 |
+wk_client *wk_clientget(_wk *web, int connid); |
|
48 |
+ |
|
21 | 49 |
wk * |
22 | 50 |
wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int connid, wk_event event, void *userptr*/), void (*callback_http)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void (*callback_continuation)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
23 | 51 |
{ |
24 | 52 |
_wk *web; |
53 |
+ if(ssel==NULL || callback_http==NULL) |
|
54 |
+ return(NULL); |
|
25 | 55 |
if((web=malloc(sizeof(_wk)))==NULL) |
26 | 56 |
return(NULL); |
27 | 57 |
memset(web,0,sizeof(_wk)); |
58 |
+ web->serverfd=-1; |
|
59 |
+ web->ssel=ssel; |
|
60 |
+ FD_ZERO(&(web->fdset)); |
|
61 |
+ if((web->serverfd=ipv4_server(port))==-1) { |
|
62 |
+ wk_free((wk *)web),web=NULL; |
|
63 |
+ return(NULL); |
|
64 |
+ } |
|
65 |
+ FD_SET(web->serverfd,&(web->fdset)); |
|
66 |
+ sselect_addread(ssel,web->serverfd,NULL); |
|
28 | 67 |
return((wk *)web); |
29 | 68 |
} |
30 | 69 |
|
... | ... |
@@ -34,6 +73,11 @@ wk_free(wk *paramweb) |
34 | 73 |
_wk *web=(_wk *)paramweb; |
35 | 74 |
if(web==NULL) |
36 | 75 |
return; |
76 |
+ if(web->serverfd!=-1) { |
|
77 |
+ sselect_delread(web->ssel,web->serverfd); |
|
78 |
+ FD_CLR(web->serverfd,&(web->fdset)); |
|
79 |
+ close(web->serverfd),web->serverfd=-1; |
|
80 |
+ } |
|
37 | 81 |
free(web),web=NULL; |
38 | 82 |
} |
39 | 83 |
|
... | ... |
@@ -46,7 +90,23 @@ wk_geturi(wk *paramweb, int connid) |
46 | 90 |
int |
47 | 91 |
wk_service(wk *paramweb) |
48 | 92 |
{ |
49 |
- |
|
93 |
+ int fds[FDBLOCK]; |
|
94 |
+ int fd; |
|
95 |
+ int n; |
|
96 |
+ int i; |
|
97 |
+ _wk *web=(_wk *)paramweb; |
|
98 |
+ if(web==NULL) |
|
99 |
+ return(-1); |
|
100 |
+ while((n=sselect_getreadfiltered(web,&(web->fdset),fds,sizeof(fds)/sizeof(fds[0])))>0) { |
|
101 |
+ for(i=0;i<n;i++) { |
|
102 |
+ fd=fds[i]; |
|
103 |
+ if(fd==web->serverfd) { |
|
104 |
+ /* accept new connection */ |
|
105 |
+ wk_accept(web); |
|
106 |
+ continue; |
|
107 |
+ } |
|
108 |
+ } |
|
109 |
+ } |
|
50 | 110 |
} |
51 | 111 |
|
52 | 112 |
int |
... | ... |
@@ -98,12 +158,14 @@ wk_uri_getheaderbynum(wk_uri *wkuri, int num) |
98 | 158 |
} |
99 | 159 |
|
100 | 160 |
const char * |
101 |
-mime_getdefault(char *filename) |
|
161 |
+mime_getdefault(const char *filename, const char *defaultmime) |
|
102 | 162 |
{ |
163 |
+ const char *dotptr,*dotdotptr; |
|
164 |
+ int i; |
|
103 | 165 |
struct { |
104 |
- char *ext; |
|
105 |
- char *mime; |
|
106 |
- } dotdot[]={{".tar.gz","application/x-tgz"}}, |
|
166 |
+ const char *ext; |
|
167 |
+ const char *mime; |
|
168 |
+ } dotdot[]={{"tar.gz","application/x-tgz"}}, |
|
107 | 169 |
dot[]={ |
108 | 170 |
{"html","text/html"}, |
109 | 171 |
{"htm","text/html"}, |
... | ... |
@@ -130,7 +192,23 @@ mime_getdefault(char *filename) |
130 | 192 |
{"mp4","video/mp4"}, |
131 | 193 |
{"webm","video/webm"}, |
132 | 194 |
{"avi","video/x-msvideo"}}; |
133 |
-#warning TODO |
|
195 |
+ if(filename==NULL || (dotptr=strrchr(filename,'.'))==NULL) |
|
196 |
+ return(defaultmime); |
|
197 |
+ if(dotptr>filename) { |
|
198 |
+ for(dotdotptr=(dotptr-1);dotdotptr>filename && *dotdotptr!='.';dotdotptr--) |
|
199 |
+ ; |
|
200 |
+ if(*dotdotptr=='.') { |
|
201 |
+ for(i=0;i<(sizeof(dotdot)/sizeof(dotdot[0]));i++) { |
|
202 |
+ if(strcmp(dotdotptr+1,dotdot[i].ext)==0) |
|
203 |
+ return(dotdot[i].mime); |
|
204 |
+ } |
|
205 |
+ } |
|
206 |
+ } |
|
207 |
+ for(i=0;i<(sizeof(dot)/sizeof(dot[0]));i++) { |
|
208 |
+ if(strcmp(dotptr+1,dot[i].ext)==0) |
|
209 |
+ return(dot[i].mime); |
|
210 |
+ } |
|
211 |
+ return(defaultmime); |
|
134 | 212 |
} |
135 | 213 |
|
136 | 214 |
siobuf * |
... | ... |
@@ -145,3 +223,45 @@ wk_iobuffree(wk *paramweb, int iobufnum) |
145 | 223 |
|
146 | 224 |
} |
147 | 225 |
|
226 |
+/* local functions */ |
|
227 |
+static int |
|
228 |
+wk_accept(_wk *web) |
|
229 |
+{ |
|
230 |
+ int newfd; |
|
231 |
+ wk_client *client; |
|
232 |
+ if((newfd=sock_accept(web->serverfd))==-1) |
|
233 |
+ return(-1); |
|
234 |
+ if((client=wk_clientacquire(web))==NULL) { |
|
235 |
+ close(newfd),newfd=-1; |
|
236 |
+ return(-1); |
|
237 |
+ } |
|
238 |
+ client->fd=newfd; |
|
239 |
+ FD_SET(client->fd,&(web->fdset)); |
|
240 |
+ sselect_addread(web->ssel,client->fd,(void *)client); |
|
241 |
+ return(0); |
|
242 |
+} |
|
243 |
+ |
|
244 |
+static wk_client * |
|
245 |
+wk_clientacquire(_wk *web) |
|
246 |
+{ |
|
247 |
+#warning TODO |
|
248 |
+} |
|
249 |
+ |
|
250 |
+static int |
|
251 |
+wk_clientrelease(_wk *web, int connid) |
|
252 |
+{ |
|
253 |
+} |
|
254 |
+ |
|
255 |
+wk_client * |
|
256 |
+wk_clientget(_wk *web, int connid) |
|
257 |
+{ |
|
258 |
+ int numblock; |
|
259 |
+ numblock=connid/CLIENTBLOCK; |
|
260 |
+ if(web==NULL || |
|
261 |
+ web->clientblocks==NULL || |
|
262 |
+ web->sizeclientblocks<=numblock || |
|
263 |
+ web->clientblocks[numblock].clients==NULL) |
|
264 |
+ return(NULL); |
|
265 |
+ return(web->clientblocks[numblock].clients+(connid%CLIENTBLOCK)); |
|
266 |
+} |
|
267 |
+ |
... | ... |
@@ -1,36 +1,147 @@ |
1 | 1 |
/* |
2 |
- * webkernel.v |
|
2 |
+ * webkernel.c |
|
3 | 3 |
* |
4 | 4 |
* A small embeddable web server. |
5 | 5 |
* |
6 |
- * 21/01/2014 Creation. |
|
7 |
- * |
|
8 | 6 |
* Author: Dario Rodriguez dario@softhome.net |
9 | 7 |
* This library is licensed on the terms of the GNU LGPL v2+ |
10 | 8 |
*/ |
11 | 9 |
|
12 | 10 |
|
13 |
-typedef struct { |
|
11 |
+#include <stdio.h> |
|
12 |
+#include <stdlib.h> |
|
13 |
+#include <unistd.h> |
|
14 |
+#include <string.h> |
|
15 |
+#include "webkernel.h" |
|
16 |
+ |
|
17 |
+typedef struct _wk { |
|
14 | 18 |
int dummy; |
15 |
-} swk; |
|
19 |
+} _wk; |
|
16 | 20 |
|
17 | 21 |
wk * |
18 |
-wk_init(int port) |
|
22 |
+wk_init(int port, sselect *ssel, void (*callback_event)(/*wk *paramweb,int connid, wk_event event, void *userptr*/), void (*callback_http)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void (*callback_continuation)(/*wk *paramweb,int connid, wk_uri *uri, void *userptr*/), void *userptr) |
|
19 | 23 |
{ |
24 |
+ _wk *web; |
|
25 |
+ if((web=malloc(sizeof(_wk)))==NULL) |
|
26 |
+ return(NULL); |
|
27 |
+ memset(web,0,sizeof(_wk)); |
|
28 |
+ return((wk *)web); |
|
20 | 29 |
} |
21 | 30 |
|
22 | 31 |
void |
23 |
-wk_free(wk *web) |
|
32 |
+wk_free(wk *paramweb) |
|
33 |
+{ |
|
34 |
+ _wk *web=(_wk *)paramweb; |
|
35 |
+ if(web==NULL) |
|
36 |
+ return; |
|
37 |
+ free(web),web=NULL; |
|
38 |
+} |
|
39 |
+ |
|
40 |
+wk_uri * |
|
41 |
+wk_geturi(wk *paramweb, int connid) |
|
42 |
+{ |
|
43 |
+ |
|
44 |
+} |
|
45 |
+ |
|
46 |
+int |
|
47 |
+wk_service(wk *paramweb) |
|
48 |
+{ |
|
49 |
+ |
|
50 |
+} |
|
51 |
+ |
|
52 |
+int |
|
53 |
+wk_serve_buffer_as_file(wk *paramweb, int connid, void *data, int datalen, const char *mime) |
|
54 |
+{ |
|
55 |
+ |
|
56 |
+} |
|
57 |
+ |
|
58 |
+int |
|
59 |
+wk_serve_file(wk *paramweb, int connid, char *filename, const char *mime) |
|
60 |
+{ |
|
61 |
+ |
|
62 |
+} |
|
63 |
+ |
|
64 |
+int |
|
65 |
+wk_serve_error(wk *paramweb, int connid, wk_error wkerror) |
|
66 |
+{ |
|
67 |
+ |
|
68 |
+} |
|
69 |
+ |
|
70 |
+int |
|
71 |
+wk_writestr(wk *paramweb, int connid, char *str) |
|
72 |
+{ |
|
73 |
+ |
|
74 |
+} |
|
75 |
+ |
|
76 |
+int |
|
77 |
+wk_write(wk *paramweb, int connid, void *data, int datalen) |
|
78 |
+{ |
|
79 |
+ |
|
80 |
+} |
|
81 |
+ |
|
82 |
+int |
|
83 |
+wk_close(wk *paramweb, int connid) |
|
84 |
+{ |
|
85 |
+ |
|
86 |
+} |
|
87 |
+ |
|
88 |
+char * |
|
89 |
+wk_uri_getheader(wk_uri *wkuri, char *header, char *defaultvalue) |
|
90 |
+{ |
|
91 |
+ |
|
92 |
+} |
|
93 |
+ |
|
94 |
+char * |
|
95 |
+wk_uri_getheaderbynum(wk_uri *wkuri, int num) |
|
24 | 96 |
{ |
25 | 97 |
|
26 | 98 |
} |
27 | 99 |
|
28 |
-int wk_select(wk *web, int timemoutms,...); |
|
29 |
-int wk_httpaccept(wk *web, int *httpnum); |
|
30 |
-int wk_httpisrequest(char *line); |
|
31 |
-int wk_httpfromdisk(wk *web, int httpnum,char *firstline); |
|
32 |
-int wk_httpreset(wk *web, int httpnum); |
|
33 |
-int wk_httpclose(wk *web, int httpnum); |
|
34 |
-int wk_iobufget(wk *web); |
|
35 |
-int wk_iobuffree(wk *web, int iobufnum); |
|
100 |
+const char * |
|
101 |
+mime_getdefault(char *filename) |
|
102 |
+{ |
|
103 |
+ struct { |
|
104 |
+ char *ext; |
|
105 |
+ char *mime; |
|
106 |
+ } dotdot[]={{".tar.gz","application/x-tgz"}}, |
|
107 |
+ dot[]={ |
|
108 |
+ {"html","text/html"}, |
|
109 |
+ {"htm","text/html"}, |
|
110 |
+ {"shtml","text/html"}, |
|
111 |
+ {"css","text/css"}, |
|
112 |
+ {"gif","image/gif"}, |
|
113 |
+ {"jpeg","image/jpeg"}, |
|
114 |
+ {"jpg","image/jpeg"}, |
|
115 |
+ {"png","image/png"}, |
|
116 |
+ {"tiff","image/tiff"}, |
|
117 |
+ {"tif","image/tiff"}, |
|
118 |
+ {"bmp","image/x-ms-bmp"}, |
|
119 |
+ {"svg","image/svg+xml"}, |
|
120 |
+ {"svgz","image/svg+xml"}, |
|
121 |
+ {"js","application/x-javascript"}, |
|
122 |
+ {"atom","application/atom+xml"}, |
|
123 |
+ {"txt","text/plain"}, |
|
124 |
+ {"json","application/json"}, |
|
125 |
+ {"pdf","application/pdf"}, |
|
126 |
+ {"zip","application/zip"}, |
|
127 |
+ {"mp3","audio/mpeg"}, |
|
128 |
+ {"wav","audio/x-wav"}, |
|
129 |
+ {"ogg","audio/ogg"}, |
|
130 |
+ {"mp4","video/mp4"}, |
|
131 |
+ {"webm","video/webm"}, |
|
132 |
+ {"avi","video/x-msvideo"}}; |
|
133 |
+#warning TODO |
|
134 |
+} |
|
135 |
+ |
|
136 |
+siobuf * |
|
137 |
+wk_iobufget(wk *paramweb) |
|
138 |
+{ |
|
139 |
+ |
|
140 |
+} |
|
141 |
+ |
|
142 |
+void |
|
143 |
+wk_iobuffree(wk *paramweb, int iobufnum) |
|
144 |
+{ |
|
145 |
+ |
|
146 |
+} |
|
36 | 147 |
|
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,36 @@ |
1 |
+/* |
|
2 |
+ * webkernel.v |
|
3 |
+ * |
|
4 |
+ * A small embeddable web server. |
|
5 |
+ * |
|
6 |
+ * 21/01/2014 Creation. |
|
7 |
+ * |
|
8 |
+ * Author: Dario Rodriguez dario@softhome.net |
|
9 |
+ * This library is licensed on the terms of the GNU LGPL v2+ |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+ |
|
13 |
+typedef struct { |
|
14 |
+ int dummy; |
|
15 |
+} swk; |
|
16 |
+ |
|
17 |
+wk * |
|
18 |
+wk_init(int port) |
|
19 |
+{ |
|
20 |
+} |
|
21 |
+ |
|
22 |
+void |
|
23 |
+wk_free(wk *web) |
|
24 |
+{ |
|
25 |
+ |
|
26 |
+} |
|
27 |
+ |
|
28 |
+int wk_select(wk *web, int timemoutms,...); |
|
29 |
+int wk_httpaccept(wk *web, int *httpnum); |
|
30 |
+int wk_httpisrequest(char *line); |
|
31 |
+int wk_httpfromdisk(wk *web, int httpnum,char *firstline); |
|
32 |
+int wk_httpreset(wk *web, int httpnum); |
|
33 |
+int wk_httpclose(wk *web, int httpnum); |
|
34 |
+int wk_iobufget(wk *web); |
|
35 |
+int wk_iobuffree(wk *web, int iobufnum); |
|
36 |
+ |