Guest User

Untitled

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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×