客户端和web服务器交互的基本结构如下:
(1)客户端发送请求
GET filename HTTP/version
可选参数
空行
(2)服务器发送应答
HTTP/version status-code status-message
附加信息
空行
内容
webserv.c
1 /* webserv.c a minimal web server (version 0.2) 2 * usage : webserv portnumber 3 */ 4 #include <stdio.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <netinet/in.h> 10 #include <netdb.h> 11 12 int make_server_socket(int); 13 14 int main(int argc, char* argv[]) { 15 int sock, fd; 16 FILE * fpin; 17 char request[BUFSIZ]; 18 19 if(argc==1) { 20 fprintf(stderr , "usage :webserv portnum.\n"); 21 exit(1); 22 } 23 sock=make_server_socket(atoi(argv[1])); 24 if(sock==-1) 25 exit(2); 26 while(1) { 27 /* take a call and buffer it */ 28 fd=accept(sock, NULL, NULL); 29 fpin=fdopen(fd, "r"); 30 /* read request */ 31 fgets(request, BUFSIZ, fpin); 32 printf("get a call ; request = %s", request); 33 read_til_crnl(fpin); 34 /* do what client asks */ 35 process_rq(request, fd); 36 37 fclose(fpin); 38 } 39 return 0; 40 } 41 42 int make_server_socket(int portnum) { 43 int sock; 44 struct sockaddr_in saddr; 45 struct hostent *hp; 46 char hostname[BUFSIZ]; 47 48 sock=socket(PF_INET, SOCK_STREAM, 0); 49 if(sock==-1) 50 return -1; 51 52 gethostname(hostname, BUFSIZ); 53 hp=gethostbyname(hostname); 54 bzero(&saddr, sizeof(saddr)); 55 bcopy((void*)hp->h_addr, (void*)&saddr.sin_addr, hp->h_length); 56 saddr.sin_port=htons(portnum); 57 saddr.sin_family=AF_INET; 58 59 if(bind(sock, (struct sockaddr*)&saddr, sizeof(saddr))!=0) 60 return -1; 61 if(listen(sock ,1)!=0) 62 return -1; 63 return sock; 64 } 65 66 /********************************************************************** 67 * read_til_crnl(FILE* ) 68 * skip over all request info until a CRNL is seen 69 *********************************************************************/ 70 read_til_crnl(FILE* fp) { 71 char buf[BUFSIZ]; 72 while(fgets(buf, BUFSIZ, fp)!=NULL && strcmp(buf, "\r\n")!=0) 73 ; 74 } 75 76 /********************************************************************* 77 * process_rq(char* rq, int fd) 78 * do what the request asks for and write reply to fd 79 * handles request in a new process 80 * rq is HTTP command: GET /foo/bar.html HTTP/1.0 81 ********************************************************************/ 82 process_rq(char *rq, int fd) { 83 char cmd[BUFSIZ], arg[BUFSIZ]; 84 /*creat a new process and return if not the child*/ 85 if(fork()!=0) 86 return ; 87 strcpy(arg, "./"); /* precede args with .*/ 88 if(sscanf(rq, "%s %s", cmd, arg+2)!=2) 89 return ; 90 if(strcmp(cmd, "GET")!=0) 91 cannot_do(fd); 92 else if(not_exist(arg)) 93 do_404(arg, fd); 94 else if(isadir(arg)) 95 do_ls(arg, fd); 96 else if(ends_in_cgi(arg)) 97 do_exec(arg, fd); 98 else 99 do_cat(arg, fd); 100 } 101 102 103 104 /********************************************************* 105 * the reply header thing: all functions need one 106 * if content_type is NULL then don‘t send content type 107 ********************************************************/ 108 header(FILE* fp, char * content_type) { 109 fprintf(fp, "HTTP/1.0 200 OK\r\n"); 110 if(content_type) 111 fprintf(fp, "Content-type: %s\r\n", content_type); 112 } 113 114 /********************************************************* 115 * simple functions first: 116 * cannot_do(fd): unimplemented HTTP command 117 * and do_404*(item ,fd) no such object 118 ********************************************************/ 119 120 cannot_do(fd) { 121 FILE *fp=fdopen(fd, "w"); 122 123 fprintf(fp, "HTTP/1.0 501 Not Implemented\r\n"); 124 fprintf(fp, "Content-type: text/plain\r\n"); 125 fprintf(fp, "\r\n"); 126 127 fprintf(fp, "That command is not yet implemented\r\n"); 128 fclose(fp); 129 } 130 131 do_404(char* item, int fd) { 132 FILE* fp=fdopen(fd, "w"); 133 134 fprintf(fp, "HTTP/1.0 404 Not Found\r\n"); 135 fprintf(fp, "Content-type:text/plain\r\n"); 136 fprintf(fp, "\r\n" ); 137 138 fprintf(fp, "The item you requested: %s\r\nis not found\r\n", item); 139 fclose(fp); 140 } 141 142 /****************************************************************** 143 * the directory listing sectoin 144 * isadir() uses stat, not_exist() uses stat 145 * do_ls runs ls. It should not 146 *****************************************************************/ 147 148 isadir(char *f) { 149 struct stat info; 150 return (stat(f, &info)!=-1 && S_ISDIR(info.st_mode)); 151 } 152 153 not_exist(char *f) { 154 struct stat info; 155 return (stat(f, &info)==-1); 156 } 157 158 do_ls(char *dir, int fd) { 159 FILE* fp; 160 fp=fdopen(fd, "w"); 161 header(fp, "text/plain"); 162 fprintf(fp, "\r\n"); 163 fflush(fp); 164 165 dup2(fd, 1); 166 dup2(fd, 2); 167 close(fd); 168 execlp("ls", "ls", "-l",dir, NULL); 169 perror(dir); 170 exit(1); 171 } 172 173 /******************************************************* 174 * the cgi stuff function to check extension and 175 * one to run the program. 176 ******************************************************/ 177 char * file_type(char* f) { 178 /* returns ‘extension‘ of file */ 179 char *cp; 180 if((cp=strrchr(f, ‘.‘))!=NULL) 181 return cp+1; 182 return ""; 183 } 184 185 ends_in_cgi(char* f) { 186 return (strcmp(file_type(f) , "cgi")==0); 187 } 188 189 do_exec(char *prog, int fd) { 190 FILE *fp; 191 192 fp=fdopen(fd, "w"); 193 header(fp, NULL); 194 fflush(fp); 195 dup2(fd, 1); 196 dup2(fd, 2); 197 close(fd); 198 execl(prog, prog, NULL); 199 perror(prog); 200 } 201 202 /******************************************************************* 203 * do_cat(filename, fd) 204 * sends back contents after a header 205 ******************************************************************/ 206 do_cat(char* f, int fd) { 207 char *extension = file_type(f); 208 char *content = "text/plain"; 209 FILE *fpsock, *fpfile; 210 int c; 211 212 if(strcmp(extension, "html")==0) 213 content = "text/html"; 214 else if(strcmp(extension, "gif")==0) 215 content = "image/gif"; 216 else if(strcmp(extension, "jpg")==0) 217 content = "image/jpeg"; 218 else if(strcmp(extension, "jpeg")==0) 219 content = "image/jpeg"; 220 221 fpsock = fdopen(fd, "w"); 222 fpfile = fopen(f, "r"); 223 if(fpsock != NULL && fpfile!=NULL) { 224 header(fpsock, content); 225 fprintf(fpsock, "\r\n"); 226 while((c=getc(fpfile))!=EOF) 227 putc(c, fpsock); 228 fclose(fpfile); 229 fclose(fpsock); 230 } 231 exit(0); 232 }
时间: 2024-10-11 03:33:29