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>
Authors: CrazyDog, CrazyMonkeyemail: kccddb@gmail.comDate: 20230222
Mar 14, 2025Author: \mathcal{CrazyDog}, Ph.D. in Electrical Engineering, NCTUemail: kccddb@gmail.comDate: 20230910
Nov 4, 2024Author: WhoAmI Date: 20230523 email:kccddb@gmail.com Copyright: CC BY-NC-SA 《荀子‧勸學》不積跬步,無以至千里;不積小流,無以成江海。 I. Mutex variables MUST be declared with type pthread_mutex_t, and must be initialized before they can be used. II. 了解 pthread_mutex_lock / pthread_mutex_unlock 與可能問題和代價 III. 程式執行效率與startvation 等問題
Jul 11, 2024Author: WhoAmIemail: kccddb@gmail.com
Dec 6, 2023or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up