Chinaunix首页 | 论坛 | 博客
  • 博客访问: 360439
  • 博文数量: 60
  • 博客积分: 15
  • 博客等级: 民兵
  • 技术积分: 1138
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-20 16:18
个人简介

最多140个字

文章分类

全部博文(60)

文章存档

2016年(1)

2015年(34)

2014年(25)

分类: C/C++

2015-08-25 21:00:57


  1. /* J. David's webserver */
  2. /* This is a simple webserver.
  3.  * Created November 1999 by J. David Blackstone.
  4.  * CSE 4344 (Network concepts), Prof. Zeigler
  5.  * University of Texas at Arlington
  6.  */
  7. /* This program compiles for Sparc Solaris 2.6.
  8.  * To compile for Linux:
  9.  * 1) Comment out the #include <pthread.h> line.
  10.  * 2) Comment out the line that defines the variable newthread.
  11.  * 3) Comment out the two lines that run pthread_create().
  12.  * 4) Uncomment the line that runs accept_request().
  13.  * 5) Remove -lsocket from the Makefile.
  14.  */
  15. #include <stdio.h>
  16. #include<errno.h>
  17. #include <sys/socket.h>
  18. #include <sys/types.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <unistd.h>
  22. #include <ctype.h>
  23. #include <strings.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <pthread.h>
  27. #include <sys/wait.h>
  28. #include <stdlib.h>


  29. #define ISspace(x) isspace((int)(x))


  30. #define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"


  31. void* accept_request(void*);
  32. void bad_request(int);
  33. void cat(int, FILE *);
  34. void cannot_execute(int);
  35. void error_die(const char *);
  36. void execute_cgi(int, const char *, const char *, const char *);
  37. int get_line(int, char *, int);
  38. void headers(int, const char *);
  39. void not_found(int);
  40. void serve_file(int, const char *);
  41. int startup(u_short *);
  42. void unimplemented(int);


  43. /**********************************************************************/
  44. /* A request has caused a call to accept() on the server port to
  45.  * return. Process the request appropriately.
  46.  * Parameters: the socket connected to the client */
  47. /**********************************************************************/
  48. void* accept_request(void* arg)
  49. {
  50. int client=(int)arg;
  51. char buf[1024];
  52. int numchars;
  53. char method[255];
  54. char url[255];
  55. char path[512];
  56. size_t i, j;
  57. struct stat st;
  58. int cgi = 0;/* becomes true if server decides this is a CGI
  59.                     * program */
  60. char *query_string = NULL;


  61. numchars = get_line(client, buf, sizeof(buf));
  62. i = 0; j = 0;
  63. //解析method:GET OR POST?
  64. while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
  65. {
  66. method[i] = buf[j];
  67. i++; j++;
  68. }
  69. method[i] = '\0';


  70. if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
  71. {
  72. unimplemented(client);
  73. return NULL;
  74. }
  75. //如果method为POST,则开启CGI;
  76. if (strcasecmp(method, "POST") == 0)
  77. cgi = 1;


  78. i = 0;
  79. while (ISspace(buf[j]) && (j < sizeof(buf)))
  80. j++;
  81. //获取method对应的url,例如:url=/color.cgi?color=red;
  82. while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
  83. {
  84. url[i] = buf[j];
  85. i++; j++;
  86. }
  87. url[i] = '\0';


  88. //如果method为GET,判断url中是否有CGI;
  89. if (strcasecmp(method, "GET") == 0)
  90. {
  91. query_string = url;
  92. while ((*query_string != '?') && (*query_string != '\0'))
  93. query_string++;
  94. if (*query_string == '?')
  95. {
  96. cgi = 1;
  97. *query_string = '\0';
  98. query_string++;
  99. }
  100. }


  101. sprintf(path, "htdocs%s", url);
  102. if (path[strlen(path) - 1] == '/')
  103. strcat(path, "index.html");
  104. if (stat(path, &st) == -1) {
  105. while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
  106. numchars = get_line(client, buf, sizeof(buf));
  107. not_found(client);
  108. }
  109. else
  110. {
  111. if ((st.st_mode & S_IFMT) == S_IFDIR)
  112. strcat(path, "/index.html");
  113. //如果path指定的文件为可执行文件,则CGI置位;
  114. if ((st.st_mode & S_IXUSR) ||
  115. (st.st_mode & S_IXGRP) ||
  116. (st.st_mode & S_IXOTH) )
  117. cgi = 1;
  118. if (!cgi)
  119. serve_file(client, path);
  120. else
  121. execute_cgi(client, path, method, query_string);
  122. }


  123. close(client);
  124. return NULL;
  125. }


  126. /**********************************************************************/
  127. /* Inform the client that a request it has made has a problem.
  128.  * Parameters: client socket */
  129. /**********************************************************************/
  130. void bad_request(int client)
  131. {
  132.  char buf[1024];


  133.  sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
  134.  send(client, buf, sizeof(buf), 0);
  135.  sprintf(buf, "Content-type: text/html\r\n");
  136.  send(client, buf, sizeof(buf), 0);
  137.  sprintf(buf, "\r\n");
  138.  send(client, buf, sizeof(buf), 0);
  139.  sprintf(buf, "<P>Your browser sent a bad request, ");
  140.  send(client, buf, sizeof(buf), 0);
  141.  sprintf(buf, "such as a POST without a Content-Length.\r\n");
  142.  send(client, buf, sizeof(buf), 0);
  143. }


  144. /**********************************************************************/
  145. /* Put the entire contents of a file out on a socket. This function
  146.  * is named after the UNIX "cat" command, because it might have been
  147.  * easier just to do something like pipe, fork, and exec("cat").
  148.  * Parameters: the client socket descriptor
  149.  * FILE pointer for the file to cat */
  150. /**********************************************************************/
  151. void cat(int client, FILE *resource)
  152. {
  153.  char buf[1024];


  154.  fgets(buf, sizeof(buf), resource);
  155.  while (!feof(resource))
  156.  {
  157.   send(client, buf, strlen(buf), 0);
  158.   fgets(buf, sizeof(buf), resource);
  159.  }
  160. }


  161. /**********************************************************************/
  162. /* Inform the client that a CGI script could not be executed.
  163.  * Parameter: the client socket descriptor. */
  164. /**********************************************************************/
  165. void cannot_execute(int client)
  166. {
  167.  char buf[1024];


  168.  sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
  169.  send(client, buf, strlen(buf), 0);
  170.  sprintf(buf, "Content-type: text/html\r\n");
  171.  send(client, buf, strlen(buf), 0);
  172.  sprintf(buf, "\r\n");
  173.  send(client, buf, strlen(buf), 0);
  174.  sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
  175.  send(client, buf, strlen(buf), 0);
  176. }


  177. /**********************************************************************/
  178. /* Print out an error message with perror() (for system errors; based
  179.  * on value of errno, which indicates system call errors) and exit the
  180.  * program indicating an error. */
  181. /**********************************************************************/
  182. void error_die(const char *sc)
  183. {
  184.  perror(sc);
  185.  exit(1);
  186. }


  187. /**********************************************************************/
  188. /* Execute a CGI script. Will need to set environment variables as
  189.  * appropriate.
  190.  * Parameters: client socket descriptor
  191.  * path to the CGI script */
  192. /**********************************************************************/
  193. void execute_cgi(int client, const char *path,
  194.                  const char *method, const char *query_string)
  195. {
  196. char buf[1024];
  197. int cgi_output[2];
  198. int cgi_input[2];
  199. pid_t pid;
  200. int status;
  201. int i;
  202. char c;
  203. int numchars = 1;
  204. int content_length = -1;


  205. buf[0] = 'A'; buf[1] = '\0';
  206. //读取其他http headers,并且丢弃;
  207. if (strcasecmp(method, "GET") == 0)
  208. while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
  209. numchars = get_line(client, buf, sizeof(buf));
  210. else /* POST */ //例如 Content-Length: 10
  211. {
  212. numchars = get_line(client, buf, sizeof(buf));
  213. while ((numchars > 0) && strcmp("\n", buf))
  214. {
  215. buf[15] = '\0';
  216. if (strcasecmp(buf, "Content-Length:") == 0)
  217. content_length = atoi(&(buf[16]));
  218. numchars = get_line(client, buf, sizeof(buf));
  219. }
  220. if (content_length == -1) {
  221. bad_request(client);
  222. return;
  223. }
  224. }


  225. sprintf(buf, "HTTP/1.0 200 OK\r\n");
  226. send(client, buf, strlen(buf), 0);


  227. if (pipe(cgi_output) < 0) {
  228. cannot_execute(client);
  229. return;
  230. }
  231. if (pipe(cgi_input) < 0) {
  232. cannot_execute(client);
  233. return;
  234. }


  235. if ( (pid = fork()) < 0 ) {
  236. cannot_execute(client);
  237. return;
  238. }
  239. if (pid == 0) /* child: CGI script */
  240. {
  241. char meth_env[255];
  242. char query_env[255];
  243. char length_env[255];


  244. dup2(cgi_output[1], 1);//文件描述符1作为管道cgi_output的输入;
  245. dup2(cgi_input[0], 0);//文件描述符0作为管道cgi_input的输出;
  246. close(cgi_output[0]);
  247. close(cgi_input[1]);
  248. sprintf(meth_env, "REQUEST_METHOD=%s", method);
  249. putenv(meth_env);
  250. if (strcasecmp(method, "GET") == 0) {
  251. sprintf(query_env, "QUERY_STRING=%s", query_string);
  252. putenv(query_env);
  253. }
  254. else { /* POST */
  255. sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
  256. putenv(length_env);
  257. }
  258. execl(path, path, NULL);
  259. exit(0);
  260. }
  261. else { /* parent */
  262. close(cgi_output[1]);
  263. close(cgi_input[0]);
  264. if (strcasecmp(method, "POST") == 0)//读取Content,并且发送给CGI;
  265. for (i = 0; i < content_length; i++) {
  266. recv(client, &c, 1, 0);
  267. write(cgi_input[1], &c, 1);
  268. }
  269. while (read(cgi_output[0], &c, 1) > 0)//读取CGI的输出,并且发送给客户端;
  270. send(client, &c, 1, 0);
  271. close(cgi_output[0]);
  272. close(cgi_input[1]);
  273. waitpid(pid, &status, 0);//等待CGI程序执行结束;
  274. }
  275. }


  276. /**********************************************************************/
  277. /* Get a line from a socket, whether the line ends in a newline,
  278.  * carriage return, or a CRLF combination. Terminates the string read
  279.  * with a null character. If no newline indicator is found before the
  280.  * end of the buffer, the string is terminated with a null. If any of
  281.  * the above three line terminators is read, the last character of the
  282.  * string will be a linefeed and the string will be terminated with a
  283.  * null character.
  284.  * Parameters: the socket descriptor
  285.  * the buffer to save the data in
  286.  * the size of the buffer
  287.  * Returns: the number of bytes stored (excluding null) */
  288. /**********************************************************************/
  289. int get_line(int sock, char *buf, int size)
  290. {
  291.  int i = 0;
  292.  char c = '\0';
  293.  int n;


  294.  while ((i < size - 1) && (c != '\n'))
  295.  {
  296.   n = recv(sock, &c, 1, 0);
  297.   /* DEBUG printf("%02X\n", c); */
  298.   if (n > 0)
  299.   {
  300.    if (c == '\r')
  301.    {
  302.     n = recv(sock, &c, 1, MSG_PEEK);
  303.     /* DEBUG printf("%02X\n", c); */
  304.     if ((n > 0) && (c == '\n'))
  305.      recv(sock, &c, 1, 0);
  306.     else
  307.      c = '\n';
  308.    }
  309.    buf[i] = c;
  310.    i++;
  311.   }
  312.   else
  313.    c = '\n';
  314.  }
  315.  buf[i] = '\0';
  316.  
  317.  return(i);
  318. }


  319. /**********************************************************************/
  320. /* Return the informational HTTP headers about a file. */
  321. /* Parameters: the socket to print the headers on
  322.  * the name of the file */
  323. /**********************************************************************/
  324. void headers(int client, const char *filename)
  325. {
  326.  char buf[1024];
  327.  (void)filename; /* could use filename to determine file type */


  328.  strcpy(buf, "HTTP/1.0 200 OK\r\n");
  329.  send(client, buf, strlen(buf), 0);
  330.  strcpy(buf, SERVER_STRING);
  331.  send(client, buf, strlen(buf), 0);
  332.  sprintf(buf, "Content-Type: text/html\r\n");
  333.  send(client, buf, strlen(buf), 0);
  334.  strcpy(buf, "\r\n");
  335.  send(client, buf, strlen(buf), 0);
  336. }


  337. /**********************************************************************/
  338. /* Give a client a 404 not found status message. */
  339. /**********************************************************************/
  340. void not_found(int client)
  341. {
  342.  char buf[1024];


  343.  sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
  344.  send(client, buf, strlen(buf), 0);
  345.  sprintf(buf, SERVER_STRING);
  346.  send(client, buf, strlen(buf), 0);
  347.  sprintf(buf, "Content-Type: text/html\r\n");
  348.  send(client, buf, strlen(buf), 0);
  349.  sprintf(buf, "\r\n");
  350.  send(client, buf, strlen(buf), 0);
  351.  sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
  352.  send(client, buf, strlen(buf), 0);
  353.  sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
  354.  send(client, buf, strlen(buf), 0);
  355.  sprintf(buf, "your request because the resource specified\r\n");
  356.  send(client, buf, strlen(buf), 0);
  357.  sprintf(buf, "is unavailable or nonexistent.\r\n");
  358.  send(client, buf, strlen(buf), 0);
  359.  sprintf(buf, "</BODY></HTML>\r\n");
  360.  send(client, buf, strlen(buf), 0);
  361. }


  362. /**********************************************************************/
  363. /* Send a regular file to the client. Use headers, and report
  364.  * errors to client if they occur.
  365.  * Parameters: a pointer to a file structure produced from the socket
  366.  * file descriptor
  367.  * the name of the file to serve */
  368. /**********************************************************************/
  369. void serve_file(int client, const char *filename)//读取文件,发送给客户端;
  370. {
  371.  FILE *resource = NULL;
  372.  int numchars = 1;
  373.  char buf[1024];


  374.  buf[0] = 'A'; buf[1] = '\0';
  375.  while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
  376.   numchars = get_line(client, buf, sizeof(buf));


  377.  resource = fopen(filename, "r");
  378.  if (resource == NULL)
  379.   not_found(client);
  380.  else
  381.  {
  382.   headers(client, filename);
  383.   cat(client, resource);
  384.  }
  385.  fclose(resource);
  386. }


  387. /**********************************************************************/
  388. /* This function starts the process of listening for web connections
  389.  * on a specified port. If the port is 0, then dynamically allocate a
  390.  * port and modify the original port variable to reflect the actual
  391.  * port.
  392.  * Parameters: pointer to variable containing the port to connect on
  393.  * Returns: the socket */
  394. /**********************************************************************/
  395. int startup(u_short *port)
  396. {
  397.  int httpd = 0;
  398.  struct sockaddr_in name;


  399.  httpd = socket(PF_INET, SOCK_STREAM, 0);
  400.  if (httpd == -1)
  401.   error_die("socket");
  402.  memset(&name, 0, sizeof(name));
  403.  name.sin_family = AF_INET;
  404.  name.sin_port = htons(*port);
  405.  name.sin_addr.s_addr = htonl(INADDR_ANY);
  406.  if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
  407.   error_die("bind");
  408.  if (*port == 0) /* if dynamically allocating a port */
  409.  {
  410.   socklen_t namelen = sizeof(name);
  411.   if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
  412.    error_die("getsockname");
  413.   *port = ntohs(name.sin_port);
  414.  }
  415.  if (listen(httpd, 5) < 0)
  416.   error_die("listen");
  417.  return(httpd);
  418. }


  419. /**********************************************************************/
  420. /* Inform the client that the requested web method has not been
  421.  * implemented.
  422.  * Parameter: the client socket */
  423. /**********************************************************************/
  424. void unimplemented(int client)
  425. {
  426.  char buf[1024];


  427.  sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
  428.  send(client, buf, strlen(buf), 0);
  429.  sprintf(buf, SERVER_STRING);
  430.  send(client, buf, strlen(buf), 0);
  431.  sprintf(buf, "Content-Type: text/html\r\n");
  432.  send(client, buf, strlen(buf), 0);
  433.  sprintf(buf, "\r\n");
  434.  send(client, buf, strlen(buf), 0);
  435.  sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
  436.  send(client, buf, strlen(buf), 0);
  437.  sprintf(buf, "</TITLE></HEAD>\r\n");
  438.  send(client, buf, strlen(buf), 0);
  439.  sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
  440.  send(client, buf, strlen(buf), 0);
  441.  sprintf(buf, "</BODY></HTML>\r\n");
  442.  send(client, buf, strlen(buf), 0);
  443. }


  444. /**********************************************************************/


  445. int main(void)
  446. {
  447. int server_sock = -1;
  448. u_short port = 0;
  449. int client_sock = -1;
  450. struct sockaddr_in client_name;
  451. socklen_t client_name_len = sizeof(client_name);
  452. pthread_t newthread;


  453. server_sock = startup(&port);
  454. printf("httpd running on port %d\n", port);


  455. while (1)
  456. {
  457. client_sock = accept(server_sock,
  458.                        (struct sockaddr *)&client_name,
  459.                        &client_name_len);
  460. if (client_sock == -1)
  461. error_die("accept");
  462. /* accept_request(client_sock); */
  463. //创建一个新的线程处理TCP连接;
  464. if (pthread_create(&newthread , NULL, accept_request, (void*)client_sock) != 0)
  465. perror("pthread_create");
  466. }


  467. close(server_sock);


  468. return(0);
  469. }



1,GET /

2,GET /color.cgi?color=red


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