Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4524320
  • 博文数量: 1148
  • 博客积分: 25453
  • 博客等级: 上将
  • 技术积分: 11949
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-06 21:14
文章分类

全部博文(1148)

文章存档

2012年(15)

2011年(1078)

2010年(58)

分类: 嵌入式

2011-03-24 22:23:06

  1. /*
  2. * web_server.c - A primary Web server .
  3. */

  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include

  15. #define MAXLINE 150

  16. typedef struct sockaddr SA;


  17. extern char **environ; /* defined by libc */


  18. void handle_req(int fd);
  19. int parse_uri(char *uri, char *filename, char *cgiargs);
  20. void serve_static(int fd, char *filename, int filesize);
  21. void get_filetype(char *filename, char *filetype);
  22. void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs);
  23. void error_msg(int fd, char *cause, char *errnum,
  24. char *shortmsg, char *longmsg);

  25. int main(int argc, char **argv)
  26. {
  27. /* Check command line args */
  28. if (argc != 2) {
  29. fprintf(stderr, "usage: %s \n", argv[0]);
  30. exit(1);
  31. }

  32. signal(SIGCHLD, SIG_IGN);
  33. signal(SIGPIPE, SIG_IGN);

  34. int port = atoi(argv[1]);

  35. int listen_fd;
  36. struct sockaddr_in client_addr;
  37. struct sockaddr_in server_addr;

  38. if((listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  39. perror("Unable to obtain network");
  40. exit(1);
  41. }

  42. int optval = 1;
  43. if((setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval,
  44. sizeof(int))) < 0) {
  45. perror("setsockopt failed");
  46. exit(1);
  47. }

  48. server_addr.sin_family = AF_INET;
  49. server_addr.sin_port = htons(port);
  50. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  51. if(bind(listen_fd, (SA *)&server_addr,
  52. sizeof(server_addr)) < 0) {
  53. perror("Unable to bind socket");
  54. exit(1);
  55. }

  56. if(listen(listen_fd, 1024) < 0) {
  57. perror("Unable to listen");
  58. exit(1);
  59. }

  60. #ifdef DEBUG
  61. printf("listening... s=%d \n", listen_fd);
  62. #endif

  63. int conn_fd, len;
  64. while (1) {
  65. len = sizeof(client_addr);
  66. if((conn_fd = accept(listen_fd, (SA *)&client_addr, &len)) < 0) {
  67. exit(1);
  68. close(listen_fd);
  69. }
  70. #ifdef DEBUG
  71. printf("connected. fd=%d \n", conn_fd);
  72. #endif
  73. handle_req(conn_fd);
  74. close(conn_fd);
  75. }
  76. }

  77. /*
  78. * handle one HTTP request/response transaction
  79. */
  80. void handle_req(int fd)
  81. {
  82. char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
  83. char filename[MAXLINE], cgiargs[MAXLINE];

  84. FILE *f = fdopen(fd, "r");
  85. if (!f) {
  86. perror("Unable to open input fd");
  87. close(fd);
  88. return;
  89. }
  90. setbuf(f, 0);

  91. /* Get HTTP command line*/
  92. if (!fgets(buf, MAXLINE, f)) {
  93. perror("Error reading buffer");
  94. fclose(f);
  95. return;
  96. }

  97. sscanf(buf, "%s %s %s", method, uri, version);
  98. #ifdef DEBUG
  99. printf("method: %s, uri: %s, version: %s \n", method, uri, version);
  100. #endif

  101. if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) {
  102. error_msg(fd, method, "501", "Not Implemented",
  103. "MiniWebServer does not support this method yet!");
  104. return;
  105. }

  106. /* read headers and parse "Content-length"*/
  107. char buf_header[MAXLINE];
  108. int content_length = 0;
  109. while (fgets(buf_header, 150, f) && (strlen(buf_header) > 2)) {
  110. if (strncasecmp(buf_header, "Content-length:", 15) == 0) {
  111. content_length = atoi(buf_header + 15);
  112. }
  113. }
  114. #ifdef DEBUG
  115. printf("content length: %d \n", content_length);
  116. #endif

  117. /* Parse URI */
  118. int is_cgi = parse_uri(uri, filename, cgiargs);
  119. struct stat sbuf;
  120. if (stat(filename, &sbuf) < 0) {
  121. error_msg(fd, filename, "404", "Not found",
  122. "Couldn't find this file");
  123. return;
  124. }

  125. if (is_cgi) { /* Serve CGI request */
  126. if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
  127. error_msg(fd, filename, "403", "Forbidden",
  128. "You have no permission to run the CGI program");
  129. return;
  130. }
  131. exec_cgi(fd, method, content_length, filename, cgiargs);
  132. }
  133. else { /* Serve static content */
  134. if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
  135. error_msg(fd, filename, "403", "Forbidden",
  136. "You have no permission to read the file");
  137. return;
  138. }
  139. serve_static(fd, filename, sbuf.st_size);
  140. }
  141. }

  142. /*
  143. * parse_uri - parse URI into filename and CGI args
  144. * return 1 if cgi request, 0 if static
  145. */
  146. int parse_uri(char *uri, char *filename, char *cgiargs)
  147. {
  148. char *ptr;

  149. if (!strstr(uri, "cgi-bin")) { /* Static content */
  150. strcpy(cgiargs, "");
  151. strcpy(filename, "."); /*serve the current directory*/
  152. strcat(filename, uri);
  153. if (uri[strlen(uri)-1] == '/')
  154. strcat(filename, "index.html");
  155. return 0;
  156. }
  157. else { /* CGI request */
  158. ptr = index(uri, '?');
  159. if (ptr) {
  160. strcpy(cgiargs, ptr+1);
  161. *ptr = '\0';
  162. }
  163. else
  164. strcpy(cgiargs, "");

  165. strcpy(filename, ".");
  166. strcat(filename, uri);
  167. return 1;
  168. }
  169. }

  170. /*
  171. * serve_static - copy a file back to the client
  172. */
  173. void serve_static(int fd, char *filename, int filesize)
  174. {
  175. #ifdef DEBUG
  176. printf("serve static file: %s \n", filename);
  177. #endif
  178. int srcfd;
  179. char *srcp, filetype[MAXLINE], buf[MAXLINE];

  180. /* Send response headers to client */
  181. get_filetype(filename, filetype);
  182. sprintf(buf, "HTTP/1.0 200 OK\r\n");
  183. sprintf(buf, "%sServer: Mini Web Server\r\n", buf);
  184. sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
  185. sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
  186. write(fd, buf, strlen(buf));

  187. /* Send response body to client */
  188. srcfd = open(filename, O_RDONLY, 0);
  189. srcp = mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
  190. close(srcfd);
  191. write(fd, srcp, filesize);
  192. munmap(srcp, filesize);
  193. }

  194. /*
  195. * get_filetype - derive file type from file name
  196. */
  197. void get_filetype(char *filename, char *filetype)
  198. {
  199. if (strstr(filename, ".html"))
  200. strcpy(filetype, "text/html");
  201. else if (strstr(filename, ".gif"))
  202. strcpy(filetype, "image/gif");
  203. else if (strstr(filename, ".jpg"))
  204. strcpy(filetype, "image/jpeg");
  205. else
  206. strcpy(filetype, "text/plain");
  207. }

  208. /*
  209. * exec_cgi - run a CGI program on behalf of the client
  210. */
  211. void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs)
  212. {
  213. char buf[MAXLINE], *emptylist[] = { NULL };

  214. /* Return first part of HTTP response */
  215. sprintf(buf, "HTTP/1.1 200 OK\r\n");
  216. write(fd, buf, strlen(buf));
  217. sprintf(buf, "Server: Mini Web Server\r\n");
  218. write(fd, buf, strlen(buf));

  219. if (fork() == 0) { /* child */
  220. /*handle POST method*/
  221. if (strcasecmp(method, "POST") == 0) {
  222. int pfd[2];
  223. int rc = pipe(pfd);
  224. if (rc < 0) {
  225. perror("pipe in POST failed");
  226. exit(1);
  227. }
  228. int post_pid = fork();
  229. if (post_pid == 0) {
  230. close(pfd[0]);
  231. int n = 0, bytes_read = 0;
  232. /*only read length of "content_length"*/
  233. while (n < content_length) {
  234. bytes_read = read(fd, buf, sizeof(buf)-1);
  235. printf("content read: %s \n", buf);
  236. if (bytes_read > 0) {
  237. write(pfd[1], buf, bytes_read);
  238. n += bytes_read;
  239. }
  240. }
  241. exit(0);
  242. }

  243. close(pfd[1]);
  244. /*redirect to STDIN*/
  245. dup2(pfd[0],STDIN_FILENO);
  246. }

  247. /* set CGI vars, only support "QUERY_STRING" and "CONTENT_LENGTH" */
  248. setenv("QUERY_STRING", cgiargs, 1);
  249. sprintf(buf, "%d", content_length);
  250. setenv("CONTENT_LENGTH", buf);
  251. dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */
  252. execve(filename, emptylist, environ); /* Run CGI program */
  253. }
  254. wait(NULL); /* Parent waits for and reaps child */
  255. }

  256. /*
  257. * error_msg - returns an error message to the client
  258. */
  259. void error_msg(int fd, char *cause, char *errnum,
  260. char *shortmsg, char *longmsg)
  261. {
  262. char buf[MAXLINE], body[MAXLINE];

  263. /* Build the HTTP response body */
  264. sprintf(body, "Error");
  265. sprintf(body, "%s\r\n", body);
  266. sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
  267. sprintf(body, "%s

    %s: %s\r\n", body, longmsg, cause);

  268. sprintf(body, "%s
    Mini Web server\r\n", body);

  269. /* Print the HTTP response */
  270. sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
  271. write(fd, buf, strlen(buf));
  272. sprintf(buf, "Content-type: text/html\r\n");
  273. write(fd, buf, strlen(buf));
  274. sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
  275. write(fd, buf, strlen(buf));
  276. write(fd, body, strlen(body));
  277. }






阅读(1735) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~