Advertisement
ProjectFi

server.c

Jun 20th, 2016
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 30.10 KB | None | 0 0
  1. //
  2. // server.c
  3. //
  4. // Computer Science 50
  5. // Problem Set 6
  6. //
  7.  
  8. // feature test macro requirements
  9. #define _GNU_SOURCE
  10. #define _XOPEN_SOURCE 700
  11. #define _XOPEN_SOURCE_EXTENDED
  12.  
  13. // limits on an HTTP request's size, based on Apache's
  14. // http://httpd.apache.org/docs/2.2/mod/core.html
  15. #define LimitRequestFields 50
  16. #define LimitRequestFieldSize 4094
  17. #define LimitRequestLine 8190
  18.  
  19.  
  20. // number of bytes for buffers
  21. #define BYTES 512
  22.  
  23. // header files
  24. #include <arpa/inet.h>
  25. #include <dirent.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #include <math.h>
  29. #include <signal.h>
  30. #include <stdbool.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <strings.h>
  35. #include <sys/socket.h>
  36. #include <sys/stat.h>
  37. #include <sys/types.h>
  38. #include <unistd.h>
  39.  
  40. // types
  41. typedef char BYTE;
  42.  
  43. // prototypes
  44. bool connected(void);
  45. void error(unsigned short code);
  46. void freedir(struct dirent** namelist, int n);
  47. void handler(int signal);
  48. char* htmlspecialchars(const char* s);
  49. char* indexes(const char* path);
  50. void interpret(const char* path, const char* query);
  51. void list(const char* path);
  52. bool load(FILE* file, BYTE** content, size_t* length);
  53. const char* lookup(const char* path);
  54. bool parse(const char* line, char* path, char* query);
  55. const char* reason(unsigned short code);
  56. void redirect(const char* uri);
  57. bool request(char** message, size_t* length);
  58. void respond(int code, const char* headers, const char* body, size_t length);
  59. void start(short port, const char* path);
  60. void stop(void);
  61. void transfer(const char* path, const char* type);
  62. char* urldecode(const char* s);
  63.  
  64. // server's root
  65. char* root = NULL;
  66.  
  67. // file descriptor for sockets
  68. int cfd = -1, sfd = -1;
  69.  
  70. // flag indicating whether control-c has been heard
  71. bool signaled = false;
  72.  
  73. int main(int argc, char* argv[])
  74. {
  75.     // a global variable defined in errno.h that's "set by system
  76.     // calls and some library functions [to a nonzero value]
  77.     // in the event of an error to indicate what went wrong"
  78.     errno = 0;
  79.  
  80.     // default to port 8080
  81.     int port = 8080;
  82.  
  83.     // usage
  84.     const char* usage = "Usage: server [-p port] /path/to/root";
  85.  
  86.     // parse command-line arguments
  87.     int opt;
  88.     while ((opt = getopt(argc, argv, "hp:")) != -1)
  89.     {
  90.         switch (opt)
  91.         {
  92.             // -h
  93.             case 'h':
  94.                 printf("%s\n", usage);
  95.                 return 0;
  96.  
  97.             // -p port
  98.             case 'p':
  99.                 port = atoi(optarg);
  100.                 break;
  101.         }
  102.     }
  103.  
  104.     // ensure port is a non-negative short and path to server's root is specified
  105.     if (port < 0 || port > SHRT_MAX || argv[optind] == NULL || strlen(argv[optind]) == 0)
  106.     {
  107.         // announce usage
  108.         printf("%s\n", usage);
  109.  
  110.         // return 2 just like bash's builtins
  111.         return 2;
  112.     }
  113.  
  114.     // start server
  115.     start(port, argv[optind]);
  116.  
  117.     // listen for SIGINT (aka control-c)
  118.     struct sigaction act;
  119.     act.sa_handler = handler;
  120.     act.sa_flags = 0;
  121.     sigemptyset(&act.sa_mask);
  122.     sigaction(SIGINT, &act, NULL);
  123.  
  124.     // a message and its length
  125.     char* message = NULL;
  126.     size_t length = 0;
  127.  
  128.     // path requested
  129.     char* path = NULL;
  130.  
  131.     // accept connections one at a time
  132.     while (true)
  133.     {
  134.         // free last path, if any
  135.         if (path != NULL)
  136.         {
  137.             free(path);
  138.             path = NULL;
  139.         }
  140.  
  141.         // free last message, if any
  142.         if (message != NULL)
  143.         {
  144.             free(message);
  145.             message = NULL;
  146.         }
  147.         length = 0;
  148.  
  149.         // close last client's socket, if any
  150.         if (cfd != -1)
  151.         {
  152.             close(cfd);
  153.             cfd = -1;
  154.         }
  155.  
  156.         // check for control-c
  157.         if (signaled)
  158.         {
  159.             stop();
  160.         }
  161.  
  162.         // check whether client has connected
  163.         if (connected())
  164.         {
  165.             // check for request
  166.             if (request(&message, &length))
  167.             {
  168.                 // extract message's request-line
  169.                 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
  170.                 const char* haystack = message;
  171.                 const char* needle = strstr(haystack, "\r\n");
  172.                 if (needle == NULL)
  173.                 {
  174.                     error(500);
  175.                     continue;
  176.                 }
  177.                 char line[needle - haystack + 2 + 1];
  178.                 strncpy(line, haystack, needle - haystack + 2);
  179.                 line[needle - haystack + 2] = '\0';
  180.  
  181.                 // log request-line
  182.                 printf("%s", line);
  183.  
  184.                 // parse request-line
  185.                 char abs_path[LimitRequestLine + 1];
  186.                 char query[LimitRequestLine + 1];
  187.                 if (parse(line, abs_path, query))
  188.                 {
  189.                     // URL-decode absolute-path
  190.                     char* p = urldecode(abs_path);
  191.                     if (p == NULL)
  192.                     {
  193.                         error(500);
  194.                         continue;
  195.                     }
  196.  
  197.                     // resolve absolute-path to local path
  198.                     path = malloc(strlen(root) + strlen(p) + 1);
  199.                     if (path == NULL)
  200.                     {
  201.                         error(500);
  202.                         continue;
  203.                     }
  204.                     strcpy(path, root);
  205.                     strcat(path, p);
  206.                     free(p);
  207.  
  208.                     // ensure path exists
  209.                     if (access(path, F_OK) == 1)
  210.                     {
  211.                         error(404);
  212.                         continue;
  213.                     }
  214.  
  215.                     // if path to directory
  216.                     struct stat sb;
  217.                     if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode))
  218.                     {
  219.                         // redirect from absolute-path to absolute-path/
  220.                         if (abs_path[strlen(abs_path) - 1] != '/')
  221.                         {
  222.                             char uri[strlen(abs_path) + 1 + 1];
  223.                             strcpy(uri, abs_path);
  224.                             strcat(uri, "/");
  225.                             redirect(uri);
  226.                             continue;
  227.                         }
  228.  
  229.                         // use path/index.php or path/index.html, if present, instead of directory's path
  230.                         char* index = indexes(path);
  231.                         if (index != NULL)
  232.                         {
  233.                             free(path);
  234.                             path = index;
  235.                         }
  236.  
  237.                         // list contents of directory
  238.                         else
  239.                         {
  240.                             list(path);
  241.                             continue;
  242.                         }
  243.                     }
  244.  
  245.                     // look up MIME type for file at path
  246.                     const char* type = lookup(path);
  247.                     if (type == NULL)
  248.                     {
  249.                         error(501);
  250.                         continue;
  251.                     }
  252.  
  253.                     // interpret PHP script at path
  254.                     if (strcasecmp("text/x-php", type) == 0)
  255.                     {
  256.                         interpret(path, query);
  257.                     }
  258.  
  259.                     // transfer file at path
  260.                     else
  261.                     {
  262.                         transfer(path, type);
  263.                     }
  264.                 }
  265.             }
  266.         }
  267.     }
  268. }
  269.  
  270. /**
  271.  * Checks (without blocking) whether a client has connected to server.
  272.  * Returns true iff so.
  273.  */
  274. bool connected(void)
  275. {
  276.     struct sockaddr_in cli_addr;
  277.     memset(&cli_addr, 0, sizeof(cli_addr));
  278.     socklen_t cli_len = sizeof(cli_addr);
  279.     cfd = accept(sfd, (struct sockaddr*) &cli_addr, &cli_len);
  280.     if (cfd == -1)
  281.     {
  282.         return false;
  283.     }
  284.     return true;
  285. }
  286.  
  287. /**
  288.  * Responds to client with specified status code.
  289.  */
  290. void error(unsigned short code)
  291. {
  292.     // determine code's reason-phrase
  293.     const char* phrase = reason(code);
  294.     if (phrase == NULL)
  295.     {
  296.         return;
  297.     }
  298.  
  299.     // template for response's content
  300.     char* template = "<html><head><title>%i %s</title></head><body><h1>%i %s</h1></body></html>";
  301.  
  302.     // render template
  303.     char body[(strlen(template) - 2 - ((int) log10(code) + 1) - 2 + strlen(phrase)) * 2 + 1];
  304.     int length = sprintf(body, template, code, phrase, code, phrase);
  305.     if (length < 0)
  306.     {
  307.         body[0] = '\0';
  308.         length = 0;
  309.     }
  310.  
  311.     // respond with error
  312.     char* headers = "Content-Type: text/html\r\n";
  313.     respond(code, headers, body, length);
  314. }
  315.  
  316. /**
  317.  * Frees memory allocated by scandir.
  318.  */
  319. void freedir(struct dirent** namelist, int n)
  320. {
  321.     if (namelist != NULL)
  322.     {
  323.         for (int i = 0; i < n; i++)
  324.         {
  325.             free(namelist[i]);
  326.         }
  327.         free(namelist);
  328.     }
  329. }
  330.  
  331. /**
  332.  * Handles signals.
  333.  */
  334. void handler(int signal)
  335. {
  336.     // control-c
  337.     if (signal == SIGINT)
  338.     {
  339.         signaled = true;
  340.     }
  341. }
  342.  
  343. /**
  344.  * Escapes string for HTML. Returns dynamically allocated memory for escaped
  345.  * string that must be deallocated by caller.
  346.  */
  347. char* htmlspecialchars(const char* s)
  348. {
  349.     // ensure s is not NULL
  350.     if (s == NULL)
  351.     {
  352.         return NULL;
  353.     }
  354.  
  355.     // allocate enough space for an unescaped copy of s
  356.     char* t = malloc(strlen(s) + 1);
  357.     if (t == NULL)
  358.     {
  359.         return NULL;
  360.     }
  361.     t[0] = '\0';
  362.  
  363.     // iterate over characters in s, escaping as needed
  364.     for (int i = 0, old = strlen(s), new = old; i < old; i++)
  365.     {
  366.         // escape &
  367.         if (s[i] == '&')
  368.         {
  369.             const char* entity = "&amp;";
  370.             new += strlen(entity);
  371.             t = realloc(t, new);
  372.             if (t == NULL)
  373.             {
  374.                 return NULL;
  375.             }
  376.             strcat(t, entity);
  377.         }
  378.  
  379.         // escape "
  380.         else if (s[i] == '"')
  381.         {
  382.             const char* entity = "&quot;";
  383.             new += strlen(entity);
  384.             t = realloc(t, new);
  385.             if (t == NULL)
  386.             {
  387.                 return NULL;
  388.             }
  389.             strcat(t, entity);
  390.         }
  391.  
  392.         // escape '
  393.         else if (s[i] == '\'')
  394.         {
  395.             const char* entity = "&#039;";
  396.             new += strlen(entity);
  397.             t = realloc(t, new);
  398.             if (t == NULL)
  399.             {
  400.                 return NULL;
  401.             }
  402.             strcat(t, entity);
  403.         }
  404.  
  405.         // escape <
  406.         else if (s[i] == '<')
  407.         {
  408.             const char* entity = "&lt;";
  409.             new += strlen(entity);
  410.             t = realloc(t, new);
  411.             if (t == NULL)
  412.             {
  413.                 return NULL;
  414.             }
  415.             strcat(t, entity);
  416.         }
  417.  
  418.         // escape >
  419.         else if (s[i] == '>')
  420.         {
  421.             const char* entity = "&gt;";
  422.             new += strlen(entity);
  423.             t = realloc(t, new);
  424.             if (t == NULL)
  425.             {
  426.                 return NULL;
  427.             }
  428.             strcat(t, entity);
  429.         }
  430.  
  431.         // don't escape
  432.         else
  433.         {
  434.             strncat(t, s + i, 1);
  435.         }
  436.     }
  437.  
  438.     // escaped string
  439.     return t;
  440. }
  441.  
  442. /**
  443.  * Checks, in order, whether index.php or index.html exists inside of path.
  444.  * Returns path to first match if so, else NULL.
  445.  */
  446. char* indexes(const char* path)
  447. {
  448.     // TODO
  449.         if (path != NULL) {
  450.         FILE *file;
  451.         //allocate memory for output
  452.         char* directory = malloc(sizeof(char*));
  453.         //check if index.php exists
  454.         file = fopen("index.php", "r");
  455.         //if exists, return directory
  456.         if (file != NULL) return directory = "/path/to/a/directory/index.php";
  457.         //check if index.html exists
  458.         else {
  459.             fclose(file);
  460.             file = fopen("index.html", "r");
  461.             //if exists, return directory
  462.             if (file != NULL) return directory = "/path/to/a/directory/index.html";
  463.         }
  464.         fclose(file);
  465.         //free memory
  466.         free(directory);
  467.     }
  468.     //if there is no path, return NULL
  469.     return NULL;
  470. }
  471.  
  472. /**
  473.  * Interprets PHP file at path using query string.
  474.  */
  475. void interpret(const char* path, const char* query)
  476. {
  477.     // ensure path is readable
  478.     if (access(path, R_OK) == -1)
  479.     {
  480.         error(403);
  481.         return;
  482.     }
  483.  
  484.     // open pipe to PHP interpreter
  485.     char* format = "QUERY_STRING=\"%s\" REDIRECT_STATUS=200 SCRIPT_FILENAME=\"%s\" php-cgi";
  486.     char command[strlen(format) + (strlen(path) - 2) + (strlen(query) - 2) + 1];
  487.     if (sprintf(command, format, query, path) < 0)
  488.     {
  489.         error(500);
  490.         return;
  491.     }
  492.     FILE* file = popen(command, "r");
  493.     if (file == NULL)
  494.     {
  495.         error(500);
  496.         return;
  497.     }
  498.  
  499.     // load interpreter's content
  500.     char* content;
  501.     size_t length;
  502.     if (load(file, &content, &length) == false)
  503.     {
  504.         error(500);
  505.         return;
  506.     }
  507.  
  508.     // close pipe
  509.     pclose(file);
  510.  
  511.     // subtract php-cgi's headers from content's length to get body's length
  512.     char* haystack = content;
  513.     char* needle = strstr(haystack, "\r\n\r\n");
  514.     if (needle == NULL)
  515.     {
  516.         free(content);
  517.         error(500);
  518.         return;
  519.     }
  520.  
  521.     // extract headers
  522.     char headers[needle + 2 - haystack + 1];
  523.     strncpy(headers, content, needle + 2 - haystack);
  524.     headers[needle + 2 - haystack] = '\0';
  525.  
  526.     // respond with interpreter's content
  527.     respond(200, headers, needle + 4, length - (needle - haystack + 4));
  528.  
  529.     // free interpreter's content
  530.     free(content);
  531. }
  532.  
  533. /**
  534.  * Responds to client with directory listing of path.
  535.  */
  536. void list(const char* path)
  537. {
  538.     // ensure path is readable and executable
  539.     if (access(path, R_OK | X_OK) == -1)
  540.     {
  541.         error(403);
  542.         return;
  543.     }
  544.  
  545.     // open directory
  546.     DIR* dir = opendir(path);
  547.     if (dir == NULL)
  548.     {
  549.         return;
  550.     }
  551.  
  552.     // buffer for list items
  553.     char* list = malloc(1);
  554.     list[0] = '\0';
  555.  
  556.     // iterate over directory entries
  557.     struct dirent** namelist = NULL;
  558.     int n = scandir(path, &namelist, NULL, alphasort);
  559.     for (int i = 0; i < n; i++)
  560.     {
  561.         // omit . from list
  562.         if (strcmp(namelist[i]->d_name, ".") == 0)
  563.         {
  564.             continue;
  565.         }
  566.  
  567.         // escape entry's name
  568.         char* name = htmlspecialchars(namelist[i]->d_name);
  569.         if (name == NULL)
  570.         {
  571.             free(list);
  572.             freedir(namelist, n);
  573.             error(500);
  574.             return;
  575.         }
  576.  
  577.         // append list item to buffer
  578.         char* template = "<li><a href=\"%s\">%s</a></li>";
  579.         list = realloc(list, strlen(list) + strlen(template) - 2 + strlen(name) - 2 + strlen(name) + 1);
  580.         if (list == NULL)
  581.         {
  582.             free(name);
  583.             freedir(namelist, n);
  584.             error(500);
  585.             return;
  586.         }
  587.         if (sprintf(list + strlen(list), template, name, name) < 0)
  588.         {
  589.             free(name);
  590.             freedir(namelist, n);
  591.             free(list);
  592.             error(500);
  593.             return;
  594.         }
  595.  
  596.         // free escaped name
  597.         free(name);
  598.     }
  599.  
  600.     // free memory allocated by scandir
  601.     freedir(namelist, n);
  602.  
  603.     // prepare response
  604.     const char* relative = path + strlen(root);
  605.     char* template = "<html><head><title>%s</title></head><body><h1>%s</h1><ul>%s</ul></body></html>";
  606.     char body[strlen(template) - 2 + strlen(relative) - 2 + strlen(relative) - 2 + strlen(list) + 1];
  607.     int length = sprintf(body, template, relative, relative, list);
  608.     if (length < 0)
  609.     {
  610.         free(list);
  611.         closedir(dir);
  612.         error(500);
  613.         return;
  614.     }
  615.  
  616.     // free buffer
  617.     free(list);
  618.  
  619.     // close directory
  620.     closedir(dir);
  621.  
  622.     // respond with list
  623.     char* headers = "Content-Type: text/html\r\n";
  624.     respond(200, headers, body, length);
  625. }
  626.  
  627. /**
  628.  * Loads a file into memory dynamically allocated on heap.
  629.  * Stores address thereof in *content and length thereof in *length.
  630.  */
  631. bool load(FILE* file, BYTE** content, size_t* length)
  632. {
  633.  
  634.     // read bytes from file
  635.     // malloc them
  636.     // store addresses in *content
  637.     // store #bytes (bytlen) in *length
  638.  
  639.     int bytlen = 0;
  640.     content = malloc(512);
  641.     while (fread(content, 1, 1, file) == 1)
  642.     {
  643.         if (bytlen == 512)
  644.         {
  645.             content = realloc(content, 512);
  646.         }
  647.         fread (content, 1, 1, file);
  648.         bytlen++;
  649.     }
  650.     *length = bytlen;
  651.     printf("The length is %i/n", bytlen);
  652.     return false;
  653. }
  654.  
  655. /**
  656.  * Returns MIME type for supported extensions, else NULL.
  657.  */
  658. const char* lookup(const char* path)
  659. {
  660.     // Reads into path to find the . indicating a file extesnion to follow
  661.     char* extension = strrchr (".", *path);
  662.  
  663.     // Check if extension is nonnull (if null, return NULL)
  664.     if (extension != NULL)
  665.     {
  666.         // Compare the included file types against the extension file type and
  667.         // return the corresponding MIME type
  668.         if (strncmp("css", &path[extension - path + 1], 3) == 0)
  669.         return "text/css";
  670.  
  671.         if (strncmp("html", &path[extension - path + 1], 3) == 0)
  672.         return "text/html";
  673.  
  674.         if (strncmp("gif", &path[extension - path + 1], 3) == 0)
  675.         return "image/gif";
  676.  
  677.         if (strncmp("ico", &path[extension - path + 1], 3) == 0)
  678.         return "image/x-icon";
  679.  
  680.         if (strncmp("jpg", &path[extension - path + 1], 3) == 0)
  681.         return "image/jpeg";
  682.  
  683.         if (strncmp("js", &path[extension - path + 1], 3) == 0)
  684.         return "text/javascript";
  685.  
  686.         if (strncmp("php", &path[extension - path + 1], 3) == 0)
  687.         return "text/x-php";
  688.  
  689.         if (strncmp("png", &path[extension - path + 1], 3) == 0)
  690.         return "image/png";
  691.     }
  692.     return NULL;
  693. }
  694.  
  695. /**
  696.  * Parses a request-line, storing its absolute-path at abs_path
  697.  * and its query string at query, both of which are assumed
  698.  * to be at least of length LimitRequestLine + 1.
  699.  */
  700. bool parse(const char* line, char* abs_path, char* query)
  701.     {
  702.     // declaring arrays for holding all these strings (and feels)
  703.     char abpathholder[LimitRequestLine + 1];
  704.     char queryholder[LimitRequestLine + 1];
  705.     char httpholder[9];
  706.     memset(abpathholder, 0, LimitRequestLine + 1);
  707.     memset(queryholder, 0, LimitRequestLine + 1);
  708.     memset(httpholder, 0, 9);
  709.     // getting the start of absolut path and the start of HTTP version - 1  
  710.     char* abpathstart = strchr(line, '/');
  711.     char* lastspace = strrchr(line, ' ');
  712.     char* querystart = strchr(line, '?');
  713.     // setting up an int to see where the path and query ends
  714.     int pathend;
  715.     int queryend;
  716.     // checks if there is a query and sets difference in strings accordingly, also gets the thin
  717.     if (querystart == NULL)
  718.     {
  719.         pathend = strlen(abpathstart) - strlen(lastspace);
  720.         queryholder[0] = '\0';
  721.     }
  722.     else
  723.     {
  724.         pathend = strlen(abpathstart) - strlen(querystart);
  725.         queryend = strlen(querystart) - strlen(lastspace) - 1;
  726.         for ( int i = 0; i < queryend; i++)
  727.         {
  728.             queryholder[i] = querystart[i + 1];
  729.         }
  730.     }
  731.     // copies accurate number of chars for abpath
  732.     for (int i = 0; i < pathend; i++)
  733.     {
  734.         abpathholder[i] = abpathstart[i];
  735.     }
  736.     //for (int i = 0; i < strlen(abpathholder); i++)
  737.     //    printf("This is in abpathholder: %c\n", abpathholder[i]);
  738.    
  739.     for (int i = 1; i < strlen(lastspace); i++)
  740.     {
  741.         if (lastspace[i] == '\r')
  742.         {
  743.             break;
  744.         }
  745.         else
  746.         {
  747.             httpholder[i - 1] = lastspace[i];
  748.         }
  749.     }
  750.     //for (int i = 0; i < strlen(httpholder); i++)
  751.     //    printf("This is in httpholder: %c\n", httpholder[i]);
  752.     // error checking begins here
  753.     // checking simply if line starts with GET
  754.     if (strncmp(line, "GET", 3) != 0)
  755.     {
  756.         error(405);
  757.         return false;
  758.     }
  759.     // cheking for any " in line
  760.     for (int i = 0; i < strlen(line); i++)
  761.     {
  762.         if (line[i] == '"')
  763.         {
  764.             error(400);
  765.             return false;
  766.         }
  767.     }
  768.     // checking if request-target really begiins with a /
  769.     if (abpathholder[0] != '/' || abpathholder[0] == 93)
  770.     {
  771.         error(501);
  772.         return false;
  773.     }
  774.     // checking if HTTP version is correct
  775.     if (strcasecmp(httpholder, "HTTP/1.1") != 0)
  776.     {
  777.         error(505);
  778.         return false;
  779.     }
  780.     abs_path = abpathholder;
  781.     query = queryholder;
  782.     for (int i = 0; i < strlen(abs_path); i++)
  783.         printf("This is in abs_path: %c\n", abs_path[i]);
  784.     for (int i = 0; i < strlen(query); i++)
  785.         printf("This is in query: %c\n", query[i]);
  786.     printf("Reached true!\n");
  787.     return true;
  788.     }
  789. /**
  790.  * Returns status code's reason phrase.
  791.  *
  792.  * http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6
  793.  * https://tools.ietf.org/html/rfc2324
  794.  */
  795. const char* reason(unsigned short code)
  796. {
  797.     switch (code)
  798.     {
  799.         case 200: return "OK";
  800.         case 301: return "Moved Permanently";
  801.         case 400: return "Bad Request";
  802.         case 403: return "Forbidden";
  803.         case 404: return "Not Found";
  804.         case 405: return "Method Not Allowed";
  805.         case 414: return "Request-URI Too Long";
  806.         case 418: return "I'm a teapot";
  807.         case 500: return "Internal Server Error";
  808.         case 501: return "Not Implemented";
  809.         case 505: return "HTTP Version Not Supported";
  810.         default: return NULL;
  811.     }
  812. }
  813.  
  814. /**
  815.  * Redirects client to uri.
  816.  */
  817. void redirect(const char* uri)
  818. {
  819.     char* template = "Location: %s\r\n";
  820.     char headers[strlen(template) - 2 + strlen(uri) + 1];
  821.     if (sprintf(headers, template, uri) < 0)
  822.     {
  823.         error(500);
  824.         return;
  825.     }
  826.     respond(301, headers, NULL, 0);
  827. }
  828.  
  829. /**
  830.  * Reads (without blocking) an HTTP request's headers into memory dynamically allocated on heap.
  831.  * Stores address thereof in *message and length thereof in *length.
  832.  */
  833. bool request(char** message, size_t* length)
  834. {
  835.     // ensure socket is open
  836.     if (cfd == -1)
  837.     {
  838.         return false;
  839.     }
  840.  
  841.     // initialize message and its length
  842.     *message = NULL;
  843.     *length = 0;
  844.  
  845.     // read message
  846.     while (*length < LimitRequestLine + LimitRequestFields * LimitRequestFieldSize + 4)
  847.     {
  848.         // read from socket
  849.         BYTE buffer[BYTES];
  850.         ssize_t bytes = read(cfd, buffer, BYTES);
  851.         if (bytes < 0)
  852.         {
  853.             if (*message != NULL)
  854.             {
  855.                 free(*message);
  856.                 *message = NULL;
  857.             }
  858.             *length = 0;
  859.             break;
  860.         }
  861.  
  862.         // append bytes to message
  863.         *message = realloc(*message, *length + bytes + 1);
  864.         if (*message == NULL)
  865.         {
  866.             *length = 0;
  867.             break;
  868.         }
  869.         memcpy(*message + *length, buffer, bytes);
  870.         *length += bytes;
  871.  
  872.         // null-terminate message thus far
  873.         *(*message + *length) = '\0';
  874.  
  875.         // search for CRLF CRLF
  876.         int offset = (*length - bytes < 3) ? *length - bytes : 3;
  877.         char* haystack = *message + *length - bytes - offset;
  878.         char* needle = strstr(haystack, "\r\n\r\n");
  879.         if (needle != NULL)
  880.         {
  881.             // trim to one CRLF and null-terminate
  882.             *length = needle - *message + 2;
  883.             *message = realloc(*message, *length + 1);
  884.             if (*message == NULL)
  885.             {
  886.                 break;
  887.             }
  888.             *(*message + *length) = '\0';
  889.  
  890.             // ensure request-line is no longer than LimitRequestLine
  891.             haystack = *message;
  892.             needle = strstr(haystack, "\r\n");
  893.             if (needle == NULL || (needle - haystack + 2) > LimitRequestLine)
  894.             {
  895.                 break;
  896.             }
  897.  
  898.             // count fields in message
  899.             int fields = 0;
  900.             haystack = needle + 2;
  901.             while (*haystack != '\0')
  902.             {
  903.                 // look for CRLF
  904.                 needle = strstr(haystack, "\r\n");
  905.                 if (needle == NULL)
  906.                 {
  907.                     break;
  908.                 }
  909.  
  910.                 // ensure field is no longer than LimitRequestFieldSize
  911.                 if (needle - haystack + 2 > LimitRequestFieldSize)
  912.                 {
  913.                     break;
  914.                 }
  915.  
  916.                 // look beyond CRLF
  917.                 haystack = needle + 2;
  918.             }
  919.  
  920.             // if we didn't get to end of message, we must have erred
  921.             if (*haystack != '\0')
  922.             {
  923.                 break;
  924.             }
  925.  
  926.             // ensure message has no more than LimitRequestFields
  927.             if (fields > LimitRequestFields)
  928.             {
  929.                 break;
  930.             }
  931.  
  932.             // valid
  933.             return true;
  934.         }
  935.     }
  936.  
  937.     // invalid
  938.     if (*message != NULL)
  939.     {
  940.         free(*message);
  941.     }
  942.     *message = NULL;
  943.     *length = 0;
  944.     return false;
  945. }
  946.  
  947. /**
  948.  * Responds to a client with status code, headers, and body of specified length.
  949.  */
  950. void respond(int code, const char* headers, const char* body, size_t length)
  951. {
  952.     // determine Status-Line's phrase
  953.     // http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
  954.     const char* phrase = reason(code);
  955.     if (phrase == NULL)
  956.     {
  957.         return;
  958.     }
  959.  
  960.     // respond with Status-Line
  961.     if (dprintf(cfd, "HTTP/1.1 %i %s\r\n", code, phrase) < 0)
  962.     {
  963.         return;
  964.     }
  965.  
  966.     // respond with headers
  967.     if (dprintf(cfd, "%s", headers) < 0)
  968.     {
  969.         return;
  970.     }
  971.  
  972.     // respond with CRLF
  973.     if (dprintf(cfd, "\r\n") < 0)
  974.     {
  975.         return;
  976.     }
  977.  
  978.     // respond with body
  979.     if (write(cfd, body, length) == -1)
  980.     {
  981.         return;
  982.     }
  983.  
  984.     // log response line
  985.     if (code == 200)
  986.     {
  987.         // green
  988.         printf("\033[32m");
  989.     }
  990.     else
  991.     {
  992.         // red
  993.         printf("\033[33m");
  994.     }
  995.     printf("HTTP/1.1 %i %s", code, phrase);
  996.     printf("\033[39m\n");
  997. }
  998.  
  999. /**
  1000.  * Starts server on specified port rooted at path.
  1001.  */
  1002. void start(short port, const char* path)
  1003. {
  1004.     // path to server's root
  1005.     root = realpath(path, NULL);
  1006.     if (root == NULL)
  1007.     {
  1008.         stop();
  1009.     }
  1010.  
  1011.     // ensure root is executable
  1012.     if (access(root, X_OK) == -1)
  1013.     {
  1014.         stop();
  1015.     }
  1016.  
  1017.     // announce root
  1018.     printf("\033[33m");
  1019.     printf("Using %s for server's root", root);
  1020.     printf("\033[39m\n");
  1021.  
  1022.     // create a socket
  1023.     sfd = socket(AF_INET, SOCK_STREAM, 0);
  1024.     if (sfd == -1)
  1025.     {
  1026.         stop();
  1027.     }
  1028.  
  1029.     // allow reuse of address (to avoid "Address already in use")
  1030.     int optval = 1;
  1031.     setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
  1032.  
  1033.     // assign name to socket
  1034.     struct sockaddr_in serv_addr;
  1035.     memset(&serv_addr, 0, sizeof(serv_addr));
  1036.     serv_addr.sin_family = AF_INET;
  1037.     serv_addr.sin_port = htons(port);
  1038.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  1039.     if (bind(sfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
  1040.     {
  1041.         printf("\033[33m");
  1042.         printf("Port %i already in use", port);
  1043.         printf("\033[39m\n");
  1044.         stop();
  1045.     }
  1046.  
  1047.     // listen for connections
  1048.     if (listen(sfd, SOMAXCONN) == -1)
  1049.     {
  1050.         stop();
  1051.     }
  1052.  
  1053.     // announce port in use
  1054.     struct sockaddr_in addr;
  1055.     socklen_t addrlen = sizeof(addr);
  1056.     if (getsockname(sfd, (struct sockaddr*) &addr, &addrlen) == -1)
  1057.     {
  1058.         stop();
  1059.     }
  1060.     printf("\033[33m");
  1061.     printf("Listening on port %i", ntohs(addr.sin_port));
  1062.     printf("\033[39m\n");
  1063. }
  1064.  
  1065. /**
  1066.  * Stop server, deallocating any resources.
  1067.  */
  1068. void stop(void)
  1069. {
  1070.     // preserve errno across this function's library calls
  1071.     int errsv = errno;
  1072.  
  1073.     // announce stop
  1074.     printf("\033[33m");
  1075.     printf("Stopping server\n");
  1076.     printf("\033[39m");
  1077.  
  1078.     // free root, which was allocated by realpath
  1079.     if (root != NULL)
  1080.     {
  1081.         free(root);
  1082.     }
  1083.  
  1084.     // close server socket
  1085.     if (sfd != -1)
  1086.     {
  1087.         close(sfd);
  1088.     }
  1089.  
  1090.     // stop server
  1091.     exit(errsv);
  1092. }
  1093.  
  1094. /**
  1095.  * Transfers file at path with specified type to client.
  1096.  */
  1097. void transfer(const char* path, const char* type)
  1098. {
  1099.     // ensure path is readable
  1100.     if (access(path, R_OK) == -1)
  1101.     {
  1102.         error(403);
  1103.         return;
  1104.     }
  1105.  
  1106.     // open file
  1107.     FILE* file = fopen(path, "r");
  1108.     if (file == NULL)
  1109.     {
  1110.         error(500);
  1111.         return;
  1112.     }
  1113.  
  1114.     // load file's content
  1115.     BYTE* content;
  1116.     size_t length;
  1117.     if (load(file, &content, &length) == false)
  1118.     {
  1119.         error(500);
  1120.         return;
  1121.     }
  1122.  
  1123.     // close file
  1124.     fclose(file);
  1125.  
  1126.     // prepare response
  1127.     char* template = "Content-Type: %s\r\n";
  1128.     char headers[strlen(template) - 2 + strlen(type) + 1];
  1129.     if (sprintf(headers, template, type) < 0)
  1130.     {
  1131.         error(500);
  1132.         return;
  1133.     }
  1134.  
  1135.     // respond with file's content
  1136.     respond(200, headers, content, length);
  1137.  
  1138.     // free file's content
  1139.     free(content);
  1140. }
  1141.  
  1142. /**
  1143.  * URL-decodes string, returning dynamically allocated memory for decoded string
  1144.  * that must be deallocated by caller.
  1145.  */
  1146. char* urldecode(const char* s)
  1147. {
  1148.     // check whether s is NULL
  1149.     if (s == NULL)
  1150.     {
  1151.         return NULL;
  1152.     }
  1153.  
  1154.     // allocate enough (zeroed) memory for an undecoded copy of s
  1155.     char* t = calloc(strlen(s) + 1, 1);
  1156.     if (t == NULL)
  1157.     {
  1158.         return NULL;
  1159.     }
  1160.    
  1161.     // iterate over characters in s, decoding percent-encoded octets, per
  1162.     // https://www.ietf.org/rfc/rfc3986.txt
  1163.     for (int i = 0, j = 0, n = strlen(s); i < n; i++, j++)
  1164.     {
  1165.         if (s[i] == '%' && i < n - 2)
  1166.         {
  1167.             char octet[3];
  1168.             octet[0] = s[i + 1];
  1169.             octet[1] = s[i + 2];
  1170.             octet[2] = '\0';
  1171.             t[j] = (char) strtol(octet, NULL, 16);
  1172.             i += 2;
  1173.         }
  1174.         else if (s[i] == '+')
  1175.         {
  1176.             t[j] = ' ';
  1177.         }
  1178.         else
  1179.         {
  1180.             t[j] = s[i];
  1181.         }
  1182.     }
  1183.  
  1184.     // escaped string
  1185.     return t;
  1186. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement