Browse code

webkernel: finished POST variables for application/x-www-form-urlencoded

Dario Rodriguez authored on 24/06/2014 12:02:23
Showing 1 changed files
... ...
@@ -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;