Guest User

Untitled

a guest
Feb 20th, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.31 KB | None | 0 0
  1. /* $begin tinymain */
  2. /*
  3. * tiny.c - A simple, iterative HTTP/1.0 Web server that uses the
  4. * GET method to serve static and dynamic content.
  5. */
  6. #include "csapp.h"
  7.  
  8. // DEBUG Value
  9. // Used for reading debug statements
  10. #define DEBUG 1
  11.  
  12. void doit(int fd);
  13. void read_requesthdrs(rio_t *rp);
  14. int parse_uri(char *uri, char *filename, char *cgiargs);
  15. void serve_static(int fd, char *filename, int filesize);
  16. void get_filetype(char *filename, char *filetype);
  17. void serve_dynamic(int fd, char *filename, char *cgiargs);
  18. void clienterror(int fd, char *cause, char *errnum,
  19. char *shortmsg, char *longmsg);
  20.  
  21. void reaper(int sig);
  22.  
  23. int main(int argc, char **argv)
  24. {
  25. int listenfd, connfd, port, clientlen;
  26. struct sockaddr_in clientaddr;
  27.  
  28. /* Check command line args */
  29. if (argc != 2) {
  30. fprintf(stderr, "usage: %s <port>\n", argv[0]);
  31. exit(1);
  32. }
  33. port = atoi(argv[1]);
  34.  
  35. listenfd = Open_listenfd(port);
  36. while (1) {
  37. clientlen = sizeof(clientaddr);
  38. connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
  39. doit(connfd);
  40. Close(connfd);
  41. }
  42. }
  43. /* $end tinymain */
  44.  
  45. /*
  46. * doit - handle one HTTP request/response transaction
  47. */
  48. /* $begin doit */
  49. void doit(int fd)
  50. {
  51. int is_static;
  52. struct stat sbuf;
  53. char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
  54. char filename[MAXLINE], cgiargs[MAXLINE];
  55. rio_t rio;
  56.  
  57. /* Read request line and headers */
  58. Rio_readinitb(&rio, fd);
  59. Rio_readlineb(&rio, buf, MAXLINE);
  60. sscanf(buf, "%s %s %s", method, uri, version);
  61.  
  62.  
  63. // Print out each Request made from the client
  64. printf("REQUEST: \n %s", buf);
  65.  
  66. if (strcasecmp(method, "GET")) {
  67. clienterror(fd, method, "501", "Not Implemented",
  68. "Tiny does not implement this method");
  69. return;
  70. }
  71. read_requesthdrs(&rio);
  72.  
  73. /* Parse URI from GET request */
  74. is_static = parse_uri(uri, filename, cgiargs);
  75. if (stat(filename, &sbuf) < 0) {
  76. clienterror(fd, filename, "404", "Not found",
  77. "Tiny couldn't find this file");
  78. return;
  79. }
  80.  
  81. if (is_static) { /* Serve static content */
  82. if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
  83. clienterror(fd, filename, "403", "Forbidden",
  84. "Tiny couldn't read the file");
  85. return;
  86. }
  87. serve_static(fd, filename, sbuf.st_size);
  88. }
  89. else { /* Serve dynamic content */
  90. if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
  91. clienterror(fd, filename, "403", "Forbidden",
  92. "Tiny couldn't run the CGI program");
  93. return;
  94. }
  95. serve_dynamic(fd, filename, cgiargs);
  96. }
  97. }
  98. /* $end doit */
  99.  
  100. /*
  101. * read_requesthdrs - read and parse HTTP request headers
  102. */
  103. /* $begin read_requesthdrs */
  104. void read_requesthdrs(rio_t *rp)
  105. {
  106. char buf[MAXLINE];
  107.  
  108. Rio_readlineb(rp, buf, MAXLINE);
  109.  
  110. // Print out the request headers
  111. printf("REQUEST HEADERS: \n %s", buf);
  112.  
  113. while(strcmp(buf, "\r\n"))
  114. {
  115. Rio_readlineb(rp, buf, MAXLINE);
  116.  
  117. // Print out each line of the headers
  118. // untill you find a blank line.
  119. printf("%s", buf);
  120. }
  121. return;
  122. }
  123. /* $end read_requesthdrs */
  124.  
  125. /*
  126. * parse_uri - parse URI into filename and CGI args
  127. * return 0 if dynamic content, 1 if static
  128. */
  129. /* $begin parse_uri */
  130. int parse_uri(char *uri, char *filename, char *cgiargs)
  131. {
  132. char *ptr;
  133.  
  134. if (!strstr(uri, "cgi-bin")) { /* Static content */
  135. strcpy(cgiargs, "");
  136. strcpy(filename, ".");
  137. strcat(filename, uri);
  138. if (uri[strlen(uri)-1] == '/')
  139. strcat(filename, "home.html");
  140. return 1;
  141. }
  142. else { /* Dynamic content */
  143. ptr = index(uri, '?');
  144. if (ptr) {
  145. strcpy(cgiargs, ptr+1);
  146. *ptr = '\0';
  147. }
  148. else
  149. strcpy(cgiargs, "");
  150. strcpy(filename, ".");
  151. strcat(filename, uri);
  152. return 0;
  153. }
  154. }
  155. /* $end parse_uri */
  156.  
  157. /*
  158. * serve_static - copy a file back to the client
  159. */
  160. /* $begin serve_static */
  161. void serve_static(int fd, char *filename, int filesize)
  162. {
  163. int srcfd;
  164. char *srcp, filetype[MAXLINE], buf[MAXBUF];
  165.  
  166. /* Send response headers to client */
  167. get_filetype(filename, filetype);
  168. sprintf(buf, "HTTP/1.0 200 OK\r\n");
  169. sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
  170. sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
  171. sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
  172. Rio_writen(fd, buf, strlen(buf));
  173.  
  174. // Print out the Response headers.
  175. printf("RESPONSE LINE & HEADERS: \n %s", buf);
  176.  
  177. /* Send response body to client */
  178. srcfd = Open(filename, O_RDONLY, 0);
  179. srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
  180. Close(srcfd);
  181. Rio_writen(fd, srcp, filesize);
  182.  
  183. Munmap(srcp, filesize);
  184. }
  185.  
  186. /*
  187. * get_filetype - derive file type from file name
  188. */
  189. void get_filetype(char *filename, char *filetype)
  190. {
  191. if (strstr(filename, ".html"))
  192. strcpy(filetype, "text/html");
  193. else if (strstr(filename, ".gif"))
  194. strcpy(filetype, "image/gif");
  195. else if (strstr(filename, ".jpg"))
  196. strcpy(filetype, "image/jpeg");
  197. else if (strstr(filename, ".mpeg"))
  198. strcpy(filetype, "video/mpeg");
  199. else if (strstr(filename, ".png"))
  200. strcpy(filetype, "image/png");
  201. else
  202. strcpy(filetype, "text/plain");
  203. }
  204. /* $end serve_static */
  205.  
  206. /*
  207. * serve_dynamic - run a CGI program on behalf of the client
  208. */
  209. /* $begin serve_dynamic */
  210. void serve_dynamic(int fd, char *filename, char *cgiargs)
  211. {
  212. char buf[MAXLINE], *emptylist[] = { NULL };
  213.  
  214. // SIGCHLD signal handler
  215. if (signal(SIGCHLD, reaper) == SIG_ERR)
  216. unix_error("signal error");
  217.  
  218. /* Return first part of HTTP response */
  219. sprintf(buf, "HTTP/1.0 200 OK\r\n");
  220. Rio_writen(fd, buf, strlen(buf));
  221. sprintf(buf, "Server: Tiny Web Server\r\n");
  222. Rio_writen(fd, buf, strlen(buf));
  223.  
  224. if (Fork() == 0) { /* child */
  225. /* Real server would set all CGI vars here */
  226. setenv("QUERY_STRING", cgiargs, 1);
  227. Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */
  228. Execve(filename, emptylist, environ); /* Run CGI program */
  229. }
  230. // Now handled by signal handler, reaper()
  231. // Wait(NULL); /* Parent waits for and reaps child */
  232. }
  233. /* $end serve_dynamic */
  234.  
  235. /*
  236. * clienterror - returns an error message to the client
  237. */
  238. /* $begin clienterror */
  239. void clienterror(int fd, char *cause, char *errnum,
  240. char *shortmsg, char *longmsg)
  241. {
  242. char buf[MAXLINE], body[MAXBUF];
  243.  
  244. /* Build the HTTP response body */
  245. sprintf(body, "<html><title>Tiny Error</title>");
  246. sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
  247. sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
  248. sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
  249. sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);
  250.  
  251. /* Print the HTTP response */
  252. sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
  253. Rio_writen(fd, buf, strlen(buf));
  254. sprintf(buf, "Content-type: text/html\r\n");
  255. Rio_writen(fd, buf, strlen(buf));
  256. sprintf(buf, "Content-length: %d\r\n\r\n", strlen(body));
  257. Rio_writen(fd, buf, strlen(buf));
  258. Rio_writen(fd, body, strlen(body));
  259. }
  260. /* $end clienterror */
  261.  
  262.  
  263. /*
  264. * SIGCHLD signal handler
  265. */
  266. void reaper(int sig)
  267. {
  268. pid_t pid;
  269.  
  270. while((pid = waitpid(-1, NULL, 0)) > 0 )
  271. if DEBUG
  272. printf("Handler reaped child %d\n", (int)pid);
  273. if( errno != ECHILD)
  274. unix_error("waitpid error");
  275. return;
  276. }
Add Comment
Please, Sign In to add comment