Try   HackMD

HTTP server (jpg image, AJAX, POST and html pthread vserion)

Author: WhoAmI
email: kccddb@gmail.com
Date: 20230531
Copyright: CC BY-NC-SA

/* *Author: WhoAmI *Date: 20230524 * */ //Simple HTTP server #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/socket.h> #include <resolv.h> #include <arpa/inet.h> #include <pthread.h> #include <fcntl.h> #define MAXFILENAME 256 #define MAXLEN 768 #define MAXNAMELEN 512 #define debugx(x) x void PANIC(char* msg); #define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); } #define SERVER_PORT 22222 #define INFO(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "=%d\n",EXP); } \ while (0) #define LONGSTRING(...) #__VA_ARGS__ const char *indexhtml = LONGSTRING(HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n <!DOCTYPE html> <html> <style> table, th, td { border:1px solid black; } </style> <body> <h2>A basic HTML table</h2> <table style="width:100%"> <tr> <th>Company</th> <th>Contact</th> <th>Name</th> </tr> <tr> <td>John </td> <td>Maria</td> <td>Joe</td> </tr> <tr> <td>FoodPanda</td> <td>Chang</td> <td>Beer</td> </tr> </table> <p>we have added borders to the table.</p> <img src="apple.jpg"> </body> </html> ); /* *Referer: http://127.0.0.1:22222/dir/w.jpg * * * GET /favicon.ico HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive Sec-Fetch-Site: same-origin Sec-Fetch-Mode: no-cors Sec-Fetch-Dest: image Referer: http://127.0.0.1:22222/w.jpg Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 * */ char *find_content_type (char *filename) { char *p; // pointer to the type found int i; //return "image/jpeg"; p=strrchr(filename,'.'); if(strcasestr(".jpg .jpeg",p))return "image/jpeg"; if(strcasestr(".html .HTML .htm .HTM",p))return "text/html"; return p; } int find_type (char *filename) { char *p; // pointer to the type found int i; debugx(printf("filename=%s\n",filename)); p=strrchr(filename,'.'); if(p){ if(strcasestr(".jpg .jpeg",p))return 2; if(strcasestr(".html .HTML .htm .HTM",p))return 1; } return 0; } int response_generator (int sfd, char *filename) { void *p; // pointer to the whole response char *content_type; // pointer to the content type char data [MAXLEN]; /* vars needed for finding the length of the file */ struct stat filestat; FILE *fp; int fd,n; int headerlen,datasize; off_t size; char filesize[6], name[256]; strcpy (name, filename); if ( ((fd = open (filename, O_RDONLY)) < -1) || (fstat(fd, &filestat) < 0) ) { printf ("Error in measuring the size of the file"); }else { sprintf (filesize, "%d", filestat.st_size); // put the file size of buffer, so we can add it to the response header p=malloc(filestat.st_size); read(fd,p,filestat.st_size); datasize=filestat.st_size; printf("name=%s, size=%d\n\n",filename,datasize ); sprintf (data, "HTTP/1.1 200 OK\nContent-Length: %d \nContent-Type: %s \nConnection: keep-alive\r\n\r\n",datasize, find_content_type (name) ); } headerlen=strlen(data); data[headerlen] = '\0'; debugx(printf("--->%s",data)); //send http header write (sfd, data, headerlen); printf("--->send\n%s",data); n=write(sfd, p,datasize); printf("---->send %d bytes\n",n); free(p); return n; } /* * Format: --------- HTTP/1.1 200 OK Content-Length: 49657 Content-Type: image/jpeg Connection: keep-alive binary data --------- * * e.g., browser send: GET /apple.jpg HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive sec-ch-ua: "Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24" sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 sec-ch-ua-platform: "Windows" Sec-Fetch-Site: same-origin Sec-Fetch-Mode: no-cors Sec-Fetch-Dest: image Referer: http://127.0.0.1:22222/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 * * */ //------------------------------------------- static char *findget(char *buf,char *getname) { char *ph,*pg; int i; ph=strstr(buf,"HTTP/1.1" ); if(ph){ printf("Find HTTP/1.1\n"); pg=strstr(buf,"GET"); if(pg){ printf("Find GET: %s<----\n\n",pg); for(i=0;i<MAXNAMELEN;i++){ if(*(pg+5+i)!=' ')getname[i]=*(pg+5+i); else {getname[i]=0;break;} } printf("-->%s\n\n",getname); return getname; } }else return NULL; return getname; } static void sig_pipe(int signum) { printf(" Broken Pipe!\n"); } static void HandleSignal(void){ //handle all signals signal(SIGPIPE, sig_pipe); } void* ServerThread(void* arg) { char buf[2048]; int bytes_read; int len=0; int *fd = (int *)arg; //Get Client's FD char getname[MAXNAMELEN]; char *p; int is=0; printf("Client %d\n",*fd); for(;;) { bytes_read = read(*fd, buf, sizeof(buf)-1); if(bytes_read<=0)break; buf[bytes_read]=0; INFO(bytes_read); p=findget(buf,getname); printf("p=%s\n",p); if(p==NULL){ strcpy(getname,"index.html"); p=getname; } if(p){ is=find_type(getname); printf("--->[GET %s] is=%d\n\n",p,is); len=strlen(indexhtml); debugx(printf("read: %d bytes:\n%s\n", bytes_read, buf)); //if(is==1)write(*fd, indexhtml, len+1); if(is==1)response_generator(*fd,getname); debugx(printf("%s\n\n",indexhtml)); //if(is==2) response_generator(*fd,"apple.jpg"); if(is==2) response_generator(*fd,getname); if(strncmp(buf, "quit", 4)==0)break; } //else break; } printf("Connection Close!\n"); close(*fd); free(fd); return arg; } int main(void) { int fd; struct sockaddr_in server_addr; int yes=1; pthread_t my_thread; int *client_fd, addr_size; HandleSignal(); if ( (fd= socket(PF_INET, SOCK_STREAM, 0)) < 0 ) PANIC("Socket"); if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) PANIC("setsockopt"); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = INADDR_ANY; if ( bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr))!= 0 )PANIC("bind"); if ( listen(fd, 20)!=0 )PANIC("listen"); for(;;) { addr_size = sizeof(server_addr); client_fd = malloc(sizeof (int)); printf("Waiting\n"); *client_fd = accept(fd, (struct sockaddr *)&server_addr, &addr_size); printf("Connected: %s:%d\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); if ( pthread_create(&my_thread, NULL, ServerThread, client_fd) != 0 ) //unstable! FIXIT! perror("Thread creation"); else pthread_detach(my_thread); } exit(0); }

httpserver2.c

1. decode POST data
2. 但有 thread 增加問題, 如何解決?
HINT: select+timeout+partial read+partial write+timeout

https://hackmd.io/@pingulinux/server-class-callback-non-blocking

H.W. 設定 timeout 解決 此thread 增加的問題

/* *Author: WhoAmI *Date: 20230524 *File: httpserver2.c */ //Simple HTTP server #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/socket.h> #include <resolv.h> #include <arpa/inet.h> #include <pthread.h> #include <fcntl.h> #include <ctype.h> #define MAXFILENAME 256 #define MAXLEN 768 #define MAXNAMELEN 512 #ifdef DEBUG #define debugx(x) x #define debugy(x) x #else #define debugx(x) #define debugy(x) #endif void PANIC(char* msg); #define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); } #define SERVER_PORT 22222 #define INFO(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "=%d\n",EXP); } \ while (0) #define LONGSTRING(...) #__VA_ARGS__ //demo LONGSTRING const char *indexhtml = LONGSTRING(HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n <!DOCTYPE html> <html> <style> table, th, td { border:1px solid black; } </style> <body> <h2>A basic HTML table</h2> <table style="width:100%"> <tr> <th>Company</th> <th>Contact</th> <th>Name</th> </tr> <tr> <td>John </td> <td>Maria</td> <td>Joe</td> </tr> <tr> <td>FoodPanda</td> <td>Chang</td> <td>Beer</td> </tr> </table> <p>we have added borders to the table.</p> <img src="apple.jpg"> </body> </html> ); /* *Information: * *Referer: http://127.0.0.1:22222/dir/w.jpg * * * GET /favicon.ico HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive * */ //Based on ThomasH (Stackoverflow) static void urldecode2(char *dst, const char *src) { char a, b; while(*src) { if((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) { if(a >= 'a') a -= 'a'-'A'; if(a >= 'A') a -= ('A' - 10); else a -= '0'; if(b >= 'a') b -= 'a'-'A'; if(b >= 'A') b -= ('A' - 10); else b -= '0'; *dst++ = 16*a+b; src+=3; } else if(*src == '+') { *dst++ = ' '; src++; } else { *dst++ = *src++; } } *dst++ = '\0'; } static char *find_content_type (char *filename) { char *p; // pointer to the type found int i; p=strrchr(filename,'.'); if(strcasestr(".jpg .jpeg .jpe",p))return "image/jpeg"; if(strcasestr(".html .HTML .htm .HTM",p))return "text/html"; if(strcasestr(".gif .GIF",p))return "image/gif"; if(strcasestr(".png .PNG",p))return "image/png"; if(strcasestr(".ico .ICO",p)) return "image/x-icon"; if(strcasestr(".mpeg .MPEG",p)) return "video/mpg"; if(strcasestr(".mp4 .MP4",p)) return "video/mpeg4"; return p; } static int find_type (char *filename) { char *p; // pointer to the type found int i; debugx(printf("filename=%s\n",filename)); p=strrchr(filename,'.'); if(p){ if(strcasestr(".jpg .jpeg",p))return 2; if(strcasestr(".html .HTML .htm .HTM",p))return 1; } return 0; } static int response_generator (int sfd, char *filename) { void *p; // pointer to the whole response char *content_type; // pointer to the content type char data [MAXLEN]; /* vars needed for finding the length of the file */ struct stat filestat; FILE *fp; int fd,n; int headerlen,datasize; off_t size; char filesize[6], name[256]; strcpy (name, filename); if ( ((fd = open (filename, O_RDONLY)) < -1) || (fstat(fd, &filestat) < 0) ) { printf ("Error in measuring the size of the file"); }else { sprintf (filesize, "%d", filestat.st_size); // put the file size of buffer, so we can add it to the response header p=malloc(filestat.st_size); read(fd,p,filestat.st_size); datasize=filestat.st_size; debugx(printf("name=%s, size=%d\n\n",filename,datasize )); sprintf (data, "HTTP/1.1 200 OK\nContent-Length: %d \nContent-Type: %s \nConnection: keep-alive\r\n\r\n",datasize, find_content_type (name) ); } headerlen=strlen(data); data[headerlen] = '\0'; debugx(printf("--->%s",data)); //send http header write (sfd, data, headerlen); debugx(printf("--->send\n%s",data)); n=write(sfd, p,datasize); debugx(printf("---->send %d bytes\n",n)); free(p); return n; } /* * Format: --------- HTTP/1.1 200 OK Content-Length: 49657 Content-Type: image/jpeg Connection: keep-alive binary data --------- * * e.g., browser send: GET /apple.jpg HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive sec-ch-ua: "Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24" sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 sec-ch-ua-platform: "Windows" Sec-Fetch-Site: same-origin Sec-Fetch-Mode: no-cors Sec-Fetch-Dest: image Referer: http://127.0.0.1:22222/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 * * */ //------------------------------------------- static char *findget(char *buf,char *getname) { char *ph,*pg, *pp,*p; char getname2[MAXNAMELEN]; int i; ph=strstr(buf,"HTTP/1.1" ); if(ph){ debugx(printf("Find HTTP/1.1\n")); pg=strstr(buf,"GET"); if(pg){ debugx(printf("Find GET: %s<----\n\n",pg)); for(i=0;i<MAXNAMELEN;i++){ if(*(pg+5+i)!=' ')getname[i]=*(pg+5+i); else {getname[i]=0;break;} } debugy(printf("-->%s\n\n",getname)); return getname; }else { pp-strstr(buf,"POST"); if(pp){ p=strstr(buf,"\r\n\r\n"); for(i=0;i<MAXNAMELEN;i++){ if(*(p+4+i)!=' ')getname2[i]=*(p+4+i); else {getname2[i]=0;break;} } debugy(printf("POST-->%s\n\n",getname2)); urldecode2( getname,getname2); debugy(printf("POST decode=%s\n",getname)); } } }else return NULL; return getname; } static void sig_pipe(int signum) { printf(" Broken Pipe!\n"); } static void HandleSignal(void){ //handle all signals signal(SIGPIPE, sig_pipe); } static void* ServerThread(void* arg) { char buf[2048]; int bytes_read; int len=0; int *fd = (int *)arg; //Get Client's FD char getname[MAXNAMELEN]; char *p; int is=0; INFO(*fd); for(;;) { bytes_read = read(*fd, buf, sizeof(buf)-1); if(bytes_read<=0)break; buf[bytes_read]=0; // INFO(bytes_read); p=findget(buf,getname); debugy(printf("p=%s\n",p)); if(p==NULL){ strcpy(getname,"index.html"); p=getname; } if(p){ is=find_type(getname); debugy(printf("--->[GET %s] is=%d\n\n",p,is)); len=strlen(indexhtml); debugx(printf("read: %d bytes:\n%s\n", bytes_read, buf)); //if(is==1)write(*fd, indexhtml, len+1); if(is==1)response_generator(*fd,getname); debugx(printf("%s\n\n",indexhtml)); //if(is==2) response_generator(*fd,"apple.jpg"); if(is==2) response_generator(*fd,getname); if(strncmp(buf, "quit", 4)==0)break; //The poocess must check timeout, then close connection! } //else break; } printf("Connection Close!\n"); close(*fd); free(fd); return arg; } int main(int argc, char *argv[]) { int fd; struct sockaddr_in server_addr; int yes=1; pthread_t my_thread; int *client_fd, addr_size; int port=SERVER_PORT; if(argc>1){ port=atoi(argv[1]); } HandleSignal(); if ( (fd= socket(PF_INET, SOCK_STREAM, 0)) < 0 ) PANIC("Socket"); if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) PANIC("setsockopt"); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = INADDR_ANY; if ( bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr))!= 0 )PANIC("bind"); if ( listen(fd, 20)!=0 )PANIC("listen"); for(;;) { addr_size = sizeof(server_addr); client_fd = malloc(sizeof (int)); printf("%s waiting on port %d\n",argv[0],port); *client_fd = accept(fd, (struct sockaddr *)&server_addr, &addr_size); printf("Connected: %s:%d\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); if ( pthread_create(&my_thread, NULL, ServerThread, client_fd) != 0 ) //unstable! FIXIT! perror("Thread creation"); else pthread_detach(my_thread); } exit(0); }

20230525 改良版

/* *Author: WhoAmI *Date: 20230525 *File: httpserver3.c */ //Simple HTTP server #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/socket.h> #include <resolv.h> #include <arpa/inet.h> #include <pthread.h> #include <fcntl.h> #include <ctype.h> #include <errno.h> #define MAXFILENAME 256 #define MAXLEN 768 #define MAXNAMELEN 512 #ifdef DEBUG #define debugx(x) x #define debugy(x) x #else #define debugx(x) #define debugy(x) #endif #define debug000(x) x #define debugz(x) x #define TIMEOUT 1000 void PANIC(char* msg); #define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); } #define SERVER_PORT 22222 #define INFO(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "=%d\n",EXP); } \ while (0) #define LONGSTRING(...) #__VA_ARGS__ //demo LONGSTRING const char *indexhtml = LONGSTRING(HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> table, th, td { border:1px solid black; } </style> </head> <body> <p>Apple</p> <img src="apple.jpg"> </body> </html> ); /* *Information: * *Referer: http://127.0.0.1:22222/dir/w.jpg * * * GET /favicon.ico HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive * */ //partial write static int writet(int fd,char *buf,int len,int msecs) { fd_set w_fds; struct timeval tv; int n; int m,j; tv.tv_sec = msecs/1000; tv.tv_usec = msecs*1000; FD_ZERO(&w_fds); FD_SET(fd,&w_fds); m=0; j=0; do { FD_SET(fd,&w_fds); if(msecs<=0) { n = select(fd+1, NULL, &w_fds, NULL, NULL ); } else { n = select(fd+1, NULL, &w_fds, NULL, &tv ); } switch(n) { case 0: //#include <errno.h> errno = ETIMEDOUT; debug000(printf("Write timeout!\n")); return j; //20191215 break; case -1: return -1; default: if( FD_ISSET(fd,&w_fds)) { m=write(fd,buf+j,len-j); j=j+m; if(j==len)return j; } break; } } while(m>0); } //partial read static int readt(int fd,char *buf,int len,int msecs) { fd_set r_fds; struct timeval tv; int n; int m,j; tv.tv_sec = msecs/1000; tv.tv_usec = msecs*1000; FD_ZERO(&r_fds); FD_SET(fd,&r_fds); m=0; j=0; do { FD_SET(fd,&r_fds); if(msecs<=0) { n = select(fd+1, &r_fds, NULL, NULL, NULL ); } { n = select(fd+1, &r_fds, NULL, NULL, &tv ); } debugy(printf("Read [%d] %d:%d usecs\n",n, tv.tv_sec,tv.tv_usec)); switch(n) { case 0: errno = ETIMEDOUT; debugy(printf("Read timeout!\n")); return j; //20191215 break; case -1: return -1; default: if( FD_ISSET(fd,&r_fds)) { m=read(fd,buf+j,len-j); j=j+m; if(j==len)return j; } break; } } while(m>0); return j; } //Based on ThomasH (Stackoverflow) static void urldecode2(char *dst, const char *src) { char a, b; while(*src) { if((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) { if(a >= 'a') a -= 'a'-'A'; if(a >= 'A') a -= ('A' - 10); else a -= '0'; if(b >= 'a') b -= 'a'-'A'; if(b >= 'A') b -= ('A' - 10); else b -= '0'; *dst++ = 16*a+b; src+=3; } else if(*src == '+') { *dst++ = ' '; src++; } else { *dst++ = *src++; } } *dst++ = '\0'; } //check Content-Type static char *find_content_type (char *filename) { char *p; // pointer to the type found int i; p=strrchr(filename,'.'); if(strcasestr(".jpg .jpeg .jpe",p))return "image/jpeg"; if(strcasestr(".html .HTML .htm .HTM",p))return "text/html"; if(strcasestr(".gif .GIF",p))return "image/gif"; if(strcasestr(".png .PNG",p))return "image/png"; if(strcasestr(".ico .ICO",p)) return "image/x-icon"; if(strcasestr(".mpeg .MPEG",p)) return "video/mpg"; if(strcasestr(".mp4 .MP4",p)) return "video/mpeg4"; return p; } static int find_type (char *filename) { char *p; // pointer to the type found int i; debugx(printf("filename=%s\n",filename)); p=strrchr(filename,'.'); if(p){ if(strcasestr(".jpg .jpeg",p))return 2; if(strcasestr(".html .HTML .htm .HTM",p))return 1; } return 0; } //send HTTP body static int response_generator (int sfd, char *filename) { void *p; // pointer to the whole response char *content_type; // pointer to the content type char data [MAXLEN]; /* vars needed for finding the length of the file */ struct stat filestat; FILE *fp; int fd,n; int headerlen,datasize; off_t size; char filesize[12], name[256]; strcpy (name, filename); if ( ((fd = open (filename, O_RDONLY)) < -1) || (fstat(fd, &filestat) < 0) ) { printf ("Error in measuring the size of the file"); }else { sprintf (filesize, "%d", filestat.st_size); // put the file size of buffer, so we can add it to the response header p=malloc(filestat.st_size); read(fd,p,filestat.st_size); datasize=filestat.st_size; debugx(printf("name=%s, size=%d\n\n",filename,datasize )); sprintf (data, "HTTP/1.1 200 OK\nContent-Length: %d \nContent-Type: %s \nConnection: keep-alive\r\n\r\n",datasize, find_content_type (name) ); } headerlen=strlen(data); data[headerlen] = '\0'; debugx(printf("--->%s",data)); //send http header writet (sfd, data, headerlen,TIMEOUT); debugx(printf("--->send\n%s",data)); n=writet(sfd, p,datasize,TIMEOUT); debugx(printf("--->send %d bytes\n",n)); free(p); return n; } /* * Format: --------- HTTP/1.1 200 OK Content-Length: 49657 Content-Type: image/jpeg Connection: keep-alive binary data --------- * * e.g., browser send: GET /apple.jpg HTTP/1.1 Host: 127.0.0.1:22222 Connection: keep-alive sec-ch-ua: "Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24" sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 * * */ //------------------------------------------- static char *findget(char *buf,char *getname) { char *ph,*pg, *pp,*p; char getname2[MAXNAMELEN]; int i; ph=strstr(buf,"HTTP/1.1" ); if(ph){ debugx(printf("Find HTTP/1.1\n")); pg=strstr(buf,"GET"); if(pg){ debugx(printf("Find GET: %s<----\n\n",pg)); for(i=0;i<MAXNAMELEN;i++){ if(*(pg+5+i)!=' ')getname[i]=*(pg+5+i); else {getname[i]=0;break;} } debugy(printf("-->%s\n\n",getname)); return getname; }else { pp-strstr(buf,"POST"); if(pp){ p=strstr(buf,"\r\n\r\n"); for(i=0;i<MAXNAMELEN;i++){ if(*(p+4+i)!=' ')getname2[i]=*(p+4+i); else {getname2[i]=0;break;} } debugy(printf("POST-->%s\n\n",getname2)); urldecode2( getname,getname2); debugz(printf("POST decode=%s\n",getname)); } } }else return NULL; return getname; } static void sig_pipe(int signum) { printf(" Broken Pipe!\n"); } static void HandleSignal(void){ //handle all signals signal(SIGPIPE, sig_pipe); } static void* ServerThread(void* arg) { char buf[2048]; int bytes_read; int len=0; int *fd = (int *)arg; //Get Client's FD char getname[MAXNAMELEN]; char *p; int is=0; INFO(*fd); for(;;) { //bytes_read = read(*fd, buf, sizeof(buf)-1); bytes_read=readt(*fd, buf, sizeof(buf)-1,TIMEOUT); if(bytes_read<=0)break; buf[bytes_read]=0; // INFO(bytes_read); p=findget(buf,getname); debugy(printf("p=%s\n",p)); if(p==NULL){ strcpy(getname,"index.html"); p=getname; } if(p){ is=find_type(getname); debugy(printf("--->[GET %s] is=%d\n\n",p,is)); len=strlen(indexhtml); debugx(printf("read: %d bytes:\n%s\n", bytes_read, buf)); //if(is==1)write(*fd, indexhtml, len+1); if(is==1)response_generator(*fd,getname); debugx(printf("%s\n\n",indexhtml)); //if(is==2) response_generator(*fd,"apple.jpg"); if(is==2) response_generator(*fd,getname); if(strncmp(buf, "quit", 4)==0)break; //The poocess must check timeout, then close connection! } //else break; } printf("Connection Close! File descriptor=%d\n", *fd); close(*fd); free(fd); return arg; } int main(int argc, char *argv[]) { int fd; struct sockaddr_in server_addr; int yes=1; pthread_t my_thread; int *client_fd, addr_size; int port=SERVER_PORT; if(argc>1){ port=atoi(argv[1]); } HandleSignal(); if ( (fd= socket(PF_INET, SOCK_STREAM, 0)) < 0 ) PANIC("Socket"); if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) PANIC("setsockopt"); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = INADDR_ANY; if ( bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr))!= 0 )PANIC("bind"); if ( listen(fd, 20)!=0 )PANIC("listen"); for(;;) { addr_size = sizeof(server_addr); client_fd = malloc(sizeof (int)); printf("%s waiting on port %d\n",argv[0],port); *client_fd = accept(fd, (struct sockaddr *)&server_addr, &addr_size); printf("Connected: %s:%d\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); if ( pthread_create(&my_thread, NULL, ServerThread, client_fd) != 0 ) //unstable! FIXIT! perror("Thread creation"); else pthread_detach(my_thread); } exit(0); }

index.html +AJAX+POST

<!DOCTYPE html> <html> <style> table, th, td { border:1px solid black; } .redButton { background-color:red; } </style> <body> <h2>A basic HTML table</h2> <table style="width:100%"> <tr> <th>Company</th> <th>Contact</th> <th>Name</th> </tr> <tr> <td>John </td> <td>Maria</td> <td>Joe</td> </tr> <tr> <td>FoodPanda</td> <td>Chang</td> <td>Beer</td> </tr> </table> <img src="apple.jpg"> <p>we have added borders to the table.</p> <img src="apple.jpg"> <img src="snoopy.gif"> <h2>AJAX POST, callback and getElementsByName (call tdemo.php)</h2> First Name: <input name="tName" type="text" value="Linux"><br> First Name: <input name="tName" type="text" value="John"><br> city: <input name="cName" type="text" value="taichung"><br> city : <input name="cName" type="text" value="taipei"> <button onclick="searchdb()" class="redButton" >AJAX POST</button> <!-- Display Server Response --> <div id="result"></div> <script> //AJAX //callback function function myCallback(xmldoc){ document.getElementById("result").innerHTML=xmldoc.responseText; } function myPost(url, data, callback) { var xmlDoc = new XMLHttpRequest(); xmlDoc.open('POST', url, true); xmlDoc.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlDoc.onreadystatechange = function() { if (xmlDoc.readyState === 4 && xmlDoc.status === 200) { callback(xmlDoc); } } xmlDoc.send(data); } //setup POST data function searchdb() { //getElementsByName():returns a collection of all elements ( NodeList ) list=document.getElementsByName("tName"); console.error(list); var tvalue=[]; list.forEach( function(currentValue, currentIndex, listObj) { tvalue.push(currentValue.value); console.error(tvalue+' ::'+currentValue + ', ' + currentIndex + ', ' + this); }, 'myThisArg' ); list=document.getElementsByName("cName"); console.error(list); var cvalue=[]; list.forEach( function(currentValue, currentIndex, listObj) { cvalue.push(currentValue.value); console.error(cvalue+' ::'+currentValue + ', ' + currentIndex + ', ' + this); }, 'myThisArg' ); query='tName='+tvalue+'&cName='+cvalue; //write your jdemo.php myPost('tdemo.php',query,myCallback); } </script> </body> </html>