The text below is selected, press Ctrl+C to copy to your clipboard. (⌘+C on Mac) No line numbers will be copied.
Guest
Common.h
By Guest on 5th October 2022 10:01:32 PM | Syntax: TEXT | Views: 1



New paste | Download | Show/Hide line no. | Copy text to clipboard
  1. /*
  2.   proxy_parse.c -- a HTTP Request Parsing Library.
  3.   COS 461  
  4. */
  5.  
  6. #include "proxy_parse.h"
  7.  
  8. #define DEFAULT_NHDRS 8
  9. #define MAX_REQ_LEN 65535
  10. #define MIN_REQ_LEN 4
  11.  
  12. static const char *root_abs_path = "/";
  13.  
  14. /* private function declartions */
  15. int ParsedRequest_printRequestLine(struct ParsedRequest *pr,
  16.                                    char * buf, size_t buflen,
  17.                                    size_t *tmp);
  18. size_t ParsedRequest_requestLineLen(struct ParsedRequest *pr);
  19.  
  20. /*
  21.  * debug() prints out debugging info if DEBUG is set to 1
  22.  *
  23.  * parameter format: same as printf
  24.  *
  25.  */
  26. void debug(const char * format, ...) {
  27.      va_list args;
  28.      if (DEBUG) {
  29.           va_start(args, format);
  30.           vfprintf(stderr, format, args);
  31.           va_end(args);
  32.      }
  33. }
  34.  
  35.  
  36. /*
  37.  *  ParsedHeader Public Methods
  38.  */
  39.  
  40. /* Set a header with key and value */
  41. int ParsedHeader_set(struct ParsedRequest *pr,
  42.                      const char * key, const char * value)
  43. {
  44.      struct ParsedHeader *ph;
  45.      ParsedHeader_remove (pr, key);
  46.  
  47.      if (pr->headerslen <= pr->headersused+1) {
  48.           pr->headerslen = pr->headerslen * 2;
  49.           pr->headers =
  50.                (struct ParsedHeader *)realloc(pr->headers,
  51.                 pr->headerslen * sizeof(struct ParsedHeader));
  52.           if (!pr->headers)
  53.                return -1;
  54.      }
  55.  
  56.      ph = pr->headers + pr->headersused;
  57.      pr->headersused += 1;
  58.      
  59.      ph->key = (char *)malloc(strlen(key)+1);
  60.      memcpy(ph->key, key, strlen(key));
  61.      ph->key[strlen(key)] = '\0';
  62.  
  63.      ph->value = (char *)malloc(strlen(value)+1);
  64.      memcpy(ph->value, value, strlen(value));
  65.      ph->value[strlen(value)] = '\0';
  66.  
  67.      ph->keylen = strlen(key)+1;
  68.      ph->valuelen = strlen(value)+1;
  69.      return 0;
  70. }
  71.  
  72.  
  73. /* get the parsedHeader with the specified key or NULL */
  74. struct ParsedHeader* ParsedHeader_get(struct ParsedRequest *pr,
  75.                                       const char * key)
  76. {
  77.      size_t i = 0;
  78.      struct ParsedHeader * tmp;
  79.      while(pr->headersused > i)
  80.      {
  81.           tmp = pr->headers + i;
  82.           if(tmp->key && key && strcmp(tmp->key, key) == 0)
  83.           {
  84.                return tmp;
  85.           }
  86.           i++;
  87.      }
  88.      return NULL;
  89. }
  90.  
  91. /* remove the specified key from parsedHeader */
  92. int ParsedHeader_remove(struct ParsedRequest *pr, const char *key)
  93. {
  94.      struct ParsedHeader *tmp;
  95.      tmp = ParsedHeader_get(pr, key);
  96.      if(tmp == NULL)
  97.           return -1;
  98.  
  99.      free(tmp->key);
  100.      free(tmp->value);
  101.      tmp->key = NULL;
  102.      return 0;
  103. }
  104.  
  105.  
  106. /* modify the header with given key, giving it a new value
  107.  * return 1 on success and 0 if no such header found
  108.  *
  109. int ParsedHeader_modify(struct ParsedRequest *pr, const char * key,
  110.                         const char *newValue)
  111. {
  112.      struct ParsedHeader *tmp;
  113.      tmp = ParsedHeader_get(pr, key);
  114.      if(tmp != NULL)
  115.      {
  116.           if(tmp->valuelen < strlen(newValue)+1)
  117.           {
  118.                tmp->valuelen = strlen(newValue)+1;
  119.                tmp->value = (char *) realloc(tmp->value,
  120.                                              tmp->valuelen * sizeof(char));
  121.           }
  122.           strcpy(tmp->value, newValue);
  123.           return 1;
  124.      }
  125.      return 0;
  126. }
  127. */
  128.  
  129. /*
  130.   ParsedHeader Private Methods
  131. */
  132.  
  133. void ParsedHeader_create(struct ParsedRequest *pr)
  134. {
  135.      pr->headers =
  136.      (struct ParsedHeader *)malloc(sizeof(struct ParsedHeader)*DEFAULT_NHDRS);
  137.      pr->headerslen = DEFAULT_NHDRS;
  138.      pr->headersused = 0;
  139. }
  140.  
  141.  
  142. size_t ParsedHeader_lineLen(struct ParsedHeader * ph)
  143. {
  144.      if(ph->key != NULL)
  145.      {
  146.           return strlen(ph->key)+strlen(ph->value)+4;
  147.      }
  148.      return 0;
  149. }
  150.  
  151. size_t ParsedHeader_headersLen(struct ParsedRequest *pr)
  152. {
  153.      if (!pr || !pr->buf)
  154.           return 0;
  155.  
  156.      size_t i = 0;
  157.      int len = 0;
  158.      while(pr->headersused > i)
  159.      {
  160.           len += ParsedHeader_lineLen(pr->headers + i);
  161.           i++;
  162.      }
  163.      len += 2;
  164.      return len;
  165. }
  166.  
  167. int ParsedHeader_printHeaders(struct ParsedRequest * pr, char * buf,
  168.                               size_t len)
  169. {
  170.      char * current = buf;
  171.      struct ParsedHeader * ph;
  172.      size_t i = 0;
  173.  
  174.      if(len < ParsedHeader_headersLen(pr))
  175.      {
  176.           debug("buffer for printing headers too small\n");
  177.           return -1;
  178.      }
  179.  
  180.      while(pr->headersused > i)
  181.      {
  182.           ph = pr->headers+i;
  183.           if (ph->key) {
  184.                memcpy(current, ph->key, strlen(ph->key));
  185.                memcpy(current+strlen(ph->key), ": ", 2);
  186.                memcpy(current+strlen(ph->key) +2 , ph->value,
  187.                       strlen(ph->value));
  188.                memcpy(current+strlen(ph->key) +2+strlen(ph->value) ,
  189.                       "\r\n", 2);
  190.                current += strlen(ph->key)+strlen(ph->value)+4;
  191.           }
  192.           i++;
  193.      }
  194.      memcpy(current, "\r\n",2);
  195.      return 0;
  196. }
  197.  
  198.  
  199. void ParsedHeader_destroyOne(struct ParsedHeader * ph)
  200. {
  201.      if(ph->key != NULL)
  202.      {
  203.           free(ph->key);
  204.           ph->key = NULL;
  205.           free(ph->value);
  206.           ph->value = NULL;
  207.           ph->keylen = 0;
  208.           ph->valuelen = 0;
  209.      }
  210. }
  211.  
  212. void ParsedHeader_destroy(struct ParsedRequest * pr)
  213. {
  214.      size_t i = 0;
  215.      while(pr->headersused > i)
  216.      {
  217.           ParsedHeader_destroyOne(pr->headers + i);
  218.           i++;
  219.      }
  220.      pr->headersused = 0;
  221.  
  222.      free(pr->headers);
  223.      pr->headerslen = 0;
  224. }
  225.  
  226.  
  227. int ParsedHeader_parse(struct ParsedRequest * pr, char * line)
  228. {
  229.      char * key;
  230.      char * value;
  231.      char * index1;
  232.      char * index2;
  233.  
  234.      index1 = index(line, ':');
  235.      if(index1 == NULL)
  236.      {
  237.           debug("No colon found\n");
  238.           return -1;
  239.      }
  240.      key = (char *)malloc((index1-line+1)*sizeof(char));
  241.      memcpy(key, line, index1-line);
  242.      key[index1-line]='\0';
  243.  
  244.      index1 += 2;
  245.      index2 = strstr(index1, "\r\n");
  246.      value = (char *) malloc((index2-index1+1)*sizeof(char));
  247.      memcpy(value, index1, (index2-index1));
  248.      value[index2-index1] = '\0';
  249.  
  250.      ParsedHeader_set(pr, key, value);
  251.      free(key);
  252.      free(value);
  253.      return 0;
  254. }
  255.  
  256. /*
  257.   ParsedRequest Public Methods
  258. */
  259.  
  260. void ParsedRequest_destroy(struct ParsedRequest *pr)
  261. {
  262.      if(pr->buf != NULL)
  263.      {
  264.           free(pr->buf);
  265.      }
  266.      if (pr->path != NULL) {
  267.           free(pr->path);
  268.      }
  269.      if(pr->headerslen > 0)
  270.      {
  271.           ParsedHeader_destroy(pr);
  272.      }
  273.      free(pr);
  274. }
  275.  
  276. struct ParsedRequest* ParsedRequest_create()
  277. {
  278.      struct ParsedRequest *pr;
  279.      pr = (struct ParsedRequest *)malloc(sizeof(struct ParsedRequest));
  280.      if (pr != NULL)
  281.      {
  282.           ParsedHeader_create(pr);
  283.           pr->buf = NULL;
  284.           pr->method = NULL;
  285.           pr->protocol = NULL;
  286.           pr->host = NULL;
  287.           pr->path = NULL;
  288.           pr->version = NULL;
  289.           pr->buf = NULL;
  290.           pr->buflen = 0;
  291.      }
  292.      return pr;
  293. }
  294.  
  295. /*
  296.    Recreate the entire buffer from a parsed request object.
  297.    buf must be allocated
  298. */
  299. int ParsedRequest_unparse(struct ParsedRequest *pr, char *buf,
  300.                           size_t buflen)
  301. {
  302.      if (!pr || !pr->buf)
  303.           return -1;
  304.  
  305.      size_t tmp;
  306.      if (ParsedRequest_printRequestLine(pr, buf, buflen, &tmp) < 0)
  307.           return -1;
  308.      if (ParsedHeader_printHeaders(pr, buf+tmp, buflen-tmp) < 0)
  309.           return -1;
  310.      return 0;
  311. }
  312.  
  313. /*
  314.    Recreate the headers from a parsed request object.
  315.    buf must be allocated
  316. */
  317. int ParsedRequest_unparse_headers(struct ParsedRequest *pr, char *buf,
  318.                                   size_t buflen)
  319. {
  320.      if (!pr || !pr->buf)
  321.           return -1;
  322.  
  323.      if (ParsedHeader_printHeaders(pr, buf, buflen) < 0)
  324.           return -1;
  325.      return 0;
  326. }
  327.  
  328.  
  329. /* Size of the headers if unparsed into a string */
  330. size_t ParsedRequest_totalLen(struct ParsedRequest *pr)
  331. {
  332.      if (!pr || !pr->buf)
  333.           return 0;
  334.      return ParsedRequest_requestLineLen(pr)+ParsedHeader_headersLen(pr);
  335. }
  336.  
  337.  
  338. /*
  339.    Parse request buffer
  340.  
  341.    Parameters:
  342.    parse: ptr to a newly created ParsedRequest object
  343.    buf: ptr to the buffer containing the request (need not be NUL terminated)
  344.    and the trailing \r\n\r\n
  345.    buflen: length of the buffer including the trailing \r\n\r\n
  346.    
  347.    Return values:
  348.    -1: failure
  349.    0: success
  350. */
  351. int
  352. ParsedRequest_parse(struct ParsedRequest * parse, const char *buf,
  353.                     int buflen)
  354. {
  355.      char *full_addr;
  356.      char *saveptr;
  357.      char *index;
  358.      char *currentHeader;
  359.  
  360.      if (parse->buf != NULL) {
  361.           debug("parse object already assigned to a request\n");
  362.           return -1;
  363.      }
  364.    
  365.      if (buflen < MIN_REQ_LEN || buflen > MAX_REQ_LEN) {
  366.           debug("invalid buflen %d", buflen);
  367.           return -1;
  368.      }
  369.    
  370.      /* Create NUL terminated tmp buffer */
  371.      char *tmp_buf = (char *)malloc(buflen + 1); /* including NUL */
  372.      memcpy(tmp_buf, buf, buflen);
  373.      tmp_buf[buflen] = '\0';
  374.    
  375.      index = strstr(tmp_buf, "\r\n\r\n");
  376.      if (index == NULL) {
  377.           debug("invalid request line, no end of header\n");
  378.           free(tmp_buf);
  379.           return -1;
  380.      }
  381.    
  382.      /* Copy request line into parse->buf */
  383.      index = strstr(tmp_buf, "\r\n");
  384.      if (parse->buf == NULL) {
  385.           parse->buf = (char *) malloc((index-tmp_buf)+1);
  386.           parse->buflen = (index-tmp_buf)+1;
  387.      }
  388.      memcpy(parse->buf, tmp_buf, index-tmp_buf);
  389.      parse->buf[index-tmp_buf] = '\0';
  390.  
  391.      /* Parse request line */
  392.      parse->method = strtok_r(parse->buf, " ", &saveptr);
  393.      if (parse->method == NULL) {
  394.           debug( "invalid request line, no whitespace\n");
  395.           free(tmp_buf);
  396.           free(parse->buf);
  397.           parse->buf = NULL;
  398.           return -1;
  399.      }
  400.      if (strcmp (parse->method, "GET")) {
  401.           debug( "invalid request line, method not 'GET': %s\n",
  402.                  parse->method);
  403.           free(tmp_buf);
  404.           free(parse->buf);
  405.           parse->buf = NULL;
  406.           return -1;
  407.      }
  408.  
  409.      full_addr = strtok_r(NULL, " ", &saveptr);
  410.  
  411.      if (full_addr == NULL) {
  412.           debug( "invalid request line, no full address\n");
  413.           free(tmp_buf);
  414.           free(parse->buf);
  415.           parse->buf = NULL;
  416.           return -1;
  417.      }
  418.  
  419.      parse->version = full_addr + strlen(full_addr) + 1;
  420.  
  421.      if (parse->version == NULL) {
  422.           debug( "invalid request line, missing version\n");
  423.           free(tmp_buf);
  424.           free(parse->buf);
  425.           parse->buf = NULL;
  426.           return -1;
  427.      }
  428.      if (strncmp (parse->version, "HTTP/", 5)) {
  429.           debug( "invalid request line, unsupported version %s\n",
  430.                  parse->version);
  431.           free(tmp_buf);
  432.           free(parse->buf);
  433.           parse->buf = NULL;
  434.           return -1;
  435.      }
  436.  
  437.  
  438.      parse->protocol = strtok_r(full_addr, "://", &saveptr);
  439.      if (parse->protocol == NULL) {
  440.           debug( "invalid request line, missing host\n");
  441.           free(tmp_buf);
  442.           free(parse->buf);
  443.           parse->buf = NULL;
  444.           return -1;
  445.      }
  446.      
  447.      const char *rem = full_addr + strlen(parse->protocol) + strlen("://");
  448.      size_t abs_uri_len = strlen(rem);
  449.  
  450.      parse->host = strtok_r(NULL, "/", &saveptr);
  451.      if (parse->host == NULL) {
  452.           debug( "invalid request line, missing host\n");
  453.           free(tmp_buf);
  454.           free(parse->buf);
  455.           parse->buf = NULL;
  456.           return -1;
  457.      }
  458.      
  459.      if (strlen(parse->host) == abs_uri_len) {
  460.           debug("invalid request line, missing absolute path\n");
  461.           free(tmp_buf);
  462.           free(parse->buf);
  463.           parse->buf = NULL;
  464.           return -1;
  465.      }
  466.  
  467.      parse->path = strtok_r(NULL, " ", &saveptr);
  468.      if (parse->path == NULL) {          // replace empty abs_path with "/"
  469.           int rlen = strlen(root_abs_path);
  470.           parse->path = (char *)malloc(rlen + 1);
  471.           strncpy(parse->path, root_abs_path, rlen + 1);
  472.      } else if (strncmp(parse->path, root_abs_path, strlen(root_abs_path)) == 0) {
  473.           debug("invalid request line, path cannot begin "
  474.                 "with two slash characters\n");
  475.           free(tmp_buf);
  476.           free(parse->buf);
  477.           parse->buf = NULL;
  478.           parse->path = NULL;
  479.           return -1;
  480.      } else {
  481.           // copy parse->path, prefix with a slash
  482.           char *tmp_path = parse->path;
  483.           int rlen = strlen(root_abs_path);
  484.           int plen = strlen(parse->path);
  485.           parse->path = (char *)malloc(rlen + plen + 1);
  486.           strncpy(parse->path, root_abs_path, rlen);
  487.           strncpy(parse->path + rlen, tmp_path, plen + 1);
  488.      }
  489.  
  490.      parse->host = strtok_r(parse->host, ":", &saveptr);
  491.      parse->port = strtok_r(NULL, "/", &saveptr);
  492.  
  493.      if (parse->host == NULL) {
  494.           debug( "invalid request line, missing host\n");
  495.           free(tmp_buf);
  496.           free(parse->buf);
  497.           free(parse->path);
  498.           parse->buf = NULL;
  499.           parse->path = NULL;
  500.           return -1;
  501.      }
  502.  
  503.      if (parse->port != NULL) {
  504.           int port = strtol (parse->port, (char **)NULL, 10);
  505.           if (port == 0 && errno == EINVAL) {
  506.                debug("invalid request line, bad port: %s\n", parse->port);
  507.                free(tmp_buf);
  508.                free(parse->buf);
  509.                free(parse->path);
  510.                parse->buf = NULL;
  511.                parse->path = NULL;
  512.                return -1;
  513.           }
  514.      }
  515.  
  516.    
  517.      /* Parse headers */
  518.      int ret = 0;
  519.      currentHeader = strstr(tmp_buf, "\r\n")+2;
  520.      while (currentHeader[0] != '\0' &&
  521.             !(currentHeader[0] == '\r' && currentHeader[1] == '\n')) {
  522.          
  523.           //debug("line %s %s", parse->version, currentHeader);
  524.  
  525.           if (ParsedHeader_parse(parse, currentHeader)) {
  526.                ret = -1;
  527.                break;
  528.           }
  529.  
  530.           currentHeader = strstr(currentHeader, "\r\n");
  531.           if (currentHeader == NULL || strlen (currentHeader) < 2)
  532.                break;
  533.  
  534.           currentHeader += 2;
  535.      }
  536.      free(tmp_buf);
  537.      return ret;
  538. }
  539.  
  540. /*
  541.    ParsedRequest Private Methods
  542. */
  543.  
  544. size_t ParsedRequest_requestLineLen(struct ParsedRequest *pr)
  545. {
  546.      if (!pr || !pr->buf)
  547.           return 0;
  548.  
  549.      size_t len =  
  550.           strlen(pr->method) + 1 + strlen(pr->protocol) + 3 +
  551.           strlen(pr->host) + 1 + strlen(pr->version) + 2;
  552.      if(pr->port != NULL)
  553.      {
  554.           len += strlen(pr->port)+1;
  555.      }
  556.      /* path is at least a slash */
  557.      len += strlen(pr->path);
  558.      return len;
  559. }
  560.  
  561. int ParsedRequest_printRequestLine(struct ParsedRequest *pr,
  562.                                    char * buf, size_t buflen,
  563.                                    size_t *tmp)
  564. {
  565.      char * current = buf;
  566.  
  567.      if(buflen <  ParsedRequest_requestLineLen(pr))
  568.      {
  569.           debug("not enough memory for first line\n");
  570.           return -1;
  571.      }
  572.      memcpy(current, pr->method, strlen(pr->method));
  573.      current += strlen(pr->method);
  574.      current[0]  = ' ';
  575.      current += 1;
  576.  
  577.      memcpy(current, pr->protocol, strlen(pr->protocol));
  578.      current += strlen(pr->protocol);
  579.      memcpy(current, "://", 3);
  580.      current += 3;
  581.      memcpy(current, pr->host, strlen(pr->host));
  582.      current += strlen(pr->host);
  583.      if(pr->port != NULL)
  584.      {
  585.           current[0] = ':';
  586.           current += 1;
  587.           memcpy(current, pr->port, strlen(pr->port));
  588.           current += strlen(pr->port);
  589.      }
  590.      /* path is at least a slash */
  591.      memcpy(current, pr->path, strlen(pr->path));
  592.      current += strlen(pr->path);
  593.  
  594.      current[0] = ' ';
  595.      current += 1;
  596.  
  597.      memcpy(current, pr->version, strlen(pr->version));
  598.      current += strlen(pr->version);
  599.      memcpy(current, "\r\n", 2);
  600.      current +=2;
  601.      *tmp = current-buf;
  602.      return 0;
  603. }



  • Recent Pastes