Advertisement
dylanweber

c http client (in progress)

Mar 18th, 2015
341
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.49 KB | None | 0 0
  1. /*
  2.     helloworld.c
  3.     Dylan Weber
  4. */
  5. #include <stdio.h>
  6. #include <stdint.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/socket.h>
  10. #include <sys/types.h>
  11. #include <netdb.h>
  12.  
  13. typedef struct URLdata {
  14.     char *protocol;
  15.     char *username;
  16.     char *password;
  17.     char *host;
  18.     char *port;
  19.     char *path;
  20. } URLdata;
  21.  
  22. typedef struct HTTPresponse {
  23.     int status;
  24.     char **headers;
  25.     char *content;
  26. } HTTPresponse;
  27.  
  28. URLdata *createURLdata(char *weburl);
  29. void freeURLdata(URLdata *freeURL);
  30. HTTPresponse *requestHTTPresponse(URLdata *requestDestination);
  31. void *get_in_addr(struct sockaddr *sa);
  32. char **generateHeaderList(char *headers);
  33. void freeHTTPresponse(HTTPresponse *freeResponse);
  34.  
  35. int main(int argc, char *argv[]) {
  36.     if (argc != 2) {
  37.         printf("Usage: helloworld ... destination\n");
  38.         return 1;
  39.     }
  40.     URLdata *inputURL = createURLdata(argv[1]);
  41.     HTTPresponse *outputResponse = requestHTTPresponse(inputURL);
  42.     freeURLdata(inputURL);
  43.     freeHTTPresponse(outputResponse);
  44.     return 0;
  45. }
  46.  
  47. URLdata *createURLdata(char *weburl) {
  48.     char *postprotocol, *postuserinfo, *postusername, *login, *posthost, *posthostname, *hostloc, *postport;
  49.     int isPath, userlen;
  50.    
  51.     URLdata *returnURL = malloc(sizeof(URLdata));
  52.     returnURL->protocol = NULL;
  53.     returnURL->username = NULL;
  54.     returnURL->password = NULL;
  55.     returnURL->host = NULL;
  56.     returnURL->port = NULL;
  57.     returnURL->path = NULL;
  58.    
  59.     if ((postprotocol = strstr(weburl, "://")) == NULL) {
  60.         return returnURL;
  61.     }
  62.     returnURL->protocol = malloc(sizeof(char) * (postprotocol - weburl + 1));
  63.     strncpy(returnURL->protocol, weburl, postprotocol - weburl);
  64.     postprotocol = (postprotocol + (*(postprotocol+3)=='/'?4:3));
  65.     if ((postuserinfo = strstr(postprotocol, "@")) != NULL) {
  66.         if ((postusername = strchr(postprotocol, ':')) != NULL) {
  67.             returnURL->password = malloc(sizeof(char) * (postuserinfo - postusername + 1));
  68.             strncpy(returnURL->password, postusername + 1, (postuserinfo - postusername - 1));
  69.         }
  70.         userlen = (postusername?postusername:postuserinfo) - postprotocol;
  71.         returnURL->username = malloc(sizeof(char) *  userlen + 1);
  72.         strncpy(returnURL->username, postprotocol, userlen);
  73.     }
  74.     hostloc = (postuserinfo?postuserinfo + 1:postprotocol);
  75.     if ((posthost = strchr(hostloc, '/')) == NULL) {
  76.         posthost = hostloc + strlen(hostloc);
  77.         isPath = 1;
  78.     }
  79.     if ((posthostname = strchr(hostloc, ':')) == NULL) {
  80.         posthostname = posthost;
  81.     }
  82.     returnURL->host = malloc(sizeof(char) * (posthostname - hostloc + 1));
  83.     strncpy(returnURL->host, hostloc, (posthostname - hostloc));
  84.     if (posthostname != posthost) {
  85.         posthostname++;
  86.         returnURL->port = malloc(sizeof(char) * (posthost - posthostname + 1));
  87.         strncpy(returnURL->port, posthostname, (posthost - posthostname));
  88.     } else {
  89.         returnURL->port = malloc(sizeof(char) * 2 + 1);
  90.         strncpy(returnURL->port, "80", 2);
  91.     }
  92.     if (isPath) {
  93.         returnURL->path = malloc(sizeof(char) * strlen(posthost) + 1);
  94.         strncpy(returnURL->path, posthost, strlen(posthost));
  95.     } else {
  96.         returnURL->path = calloc(1, 1);
  97.     }
  98.     return returnURL;
  99. }
  100.  
  101. void freeURLdata(URLdata *freeURL) {
  102.     free(freeURL->protocol);
  103.     free(freeURL->username);
  104.     free(freeURL->password);
  105.     free(freeURL->host);
  106.     free(freeURL->port);
  107.     free(freeURL->path);
  108.     free(freeURL);
  109. }
  110.  
  111. HTTPresponse *requestHTTPresponse(URLdata *requestDestination) {
  112.     char ip[INET6_ADDRSTRLEN], *request, *response = malloc(1), *headerTerminator = NULL, *responseTerminator = NULL, *headerString, *contentString, buffer[100];
  113.     int sockfd, bufferLength, responseLength;
  114.     struct addrinfo hints, *servinfo, *p;
  115.    
  116.     /* Initialize HTTP response structure */
  117.     HTTPresponse *returnresponse = malloc(sizeof(HTTPresponse));
  118.     returnresponse->status = 0;
  119.     returnresponse->headers = NULL;
  120.     returnresponse->content = NULL;
  121.    
  122.     /* Retrieve IP address of host */
  123.     memset(&hints, 0, sizeof hints);
  124.     hints.ai_family = AF_UNSPEC;
  125.     hints.ai_socktype = SOCK_STREAM;
  126.     if (getaddrinfo(requestDestination->host, requestDestination->port, &hints, &servinfo) != 0) {
  127.         return returnresponse;
  128.     }
  129.    
  130.     /* Loop through all possible connections */
  131.     for (p = servinfo; p != NULL; p = p->ai_next) {
  132.         if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
  133.             continue;
  134.         }
  135.         if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
  136.             close(sockfd);
  137.             continue;
  138.         }
  139.         break;
  140.     }
  141.    
  142.     if (p == NULL) {
  143.         return returnresponse;
  144.     }
  145.    
  146.     /* Print IP address & free server information */
  147.     inet_ntop(p->ai_family, get_in_addr((struct sockaddr*)p->ai_addr), ip, sizeof(ip));
  148.     printf("The IP address is: %s\n", ip);
  149.     freeaddrinfo(servinfo);
  150.    
  151.     /* Format HTTP request */
  152.     request = malloc(27 + (int)strlen(requestDestination->path) + (int)strlen(requestDestination->host) * sizeof(char));
  153.     if (request == NULL) {
  154.         printf("Failure to allocate memory.\n");
  155.         exit(1);
  156.     }
  157.     sprintf(request, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", (*(requestDestination->path) == 0)?"/":requestDestination->path, requestDestination->host);
  158.    
  159.     /* Send HTTP request */
  160.     send(sockfd, request, 26 + strlen(requestDestination->path) + strlen(requestDestination->host), 0);
  161.     free(request);
  162.    
  163.     /* Receive HTTP response */
  164.     do {
  165.         bufferLength = recv(sockfd, buffer, 99, 0);
  166.         if (bufferLength == -1) {
  167.             break;
  168.         }
  169.         responseLength += bufferLength;
  170.         response = realloc(response, (responseLength + 1) * sizeof(char));
  171.         if (response == NULL) {
  172.             printf("Failure to allocate memory.\n");
  173.             exit(2);
  174.         }
  175.         strncpy(response + responseLength - bufferLength, buffer, bufferLength);
  176.         if (headerTerminator) {
  177.             responseTerminator = strstr(response, "\r\n\r\n");
  178.         } else {
  179.             headerTerminator = strstr(response, "\r\n\r\n");
  180.         }
  181.     } while (responseTerminator == NULL);
  182.    
  183.     /* Store data in structs */
  184.     headerString = malloc((headerTerminator - response + 1) * sizeof(char));
  185.     if (headerString == NULL) {
  186.         printf("Failure to allocate memory.\n");
  187.         exit(1);
  188.     }
  189.     strncpy(headerString, response, headerTerminator - response);
  190.     contentString = malloc((responseTerminator - headerTerminator) * sizeof(char));
  191.     if (contentString == NULL) {
  192.         printf("Failure to allocate memory.\n");
  193.         exit(1);
  194.     }
  195.     strncpy(contentString, headerTerminator, responseTerminator - headerTerminator);
  196.     returnresponse->headers = generateHeaderList(headerString);
  197.     returnresponse->content = contentString;
  198.     free(response);
  199.    
  200.     /* Close connection & return HTTP response */
  201.     close(sockfd);
  202.     return returnresponse;
  203. }
  204.  
  205. void *get_in_addr(struct sockaddr *sa) {
  206.     if (sa->sa_family == AF_INET) {
  207.         return &(((struct sockaddr_in*)sa)->sin_addr);
  208.     } else if (sa->sa_family == AF_INET6) {
  209.         return &(((struct sockaddr_in6*)sa)->sin6_addr);
  210.     }
  211. }
  212.  
  213. char **generateHeaderList(char *headers) {
  214.     char **returnHeaders = NULL, *nextLine;
  215.     int len, n = 0;
  216.     do {
  217.         returnHeaders = realloc(returnHeaders, (n + 1) * sizeof(char *));
  218.         if (returnHeaders == NULL) {
  219.             printf("Failure to allocate memory.\n");
  220.             exit(1);
  221.         }
  222.         nextLine = strstr(headers, "\r\n");
  223.         if (nextLine == NULL) break;
  224.         len = nextLine - headers;
  225.         *(returnHeaders + n) = malloc(((len==0)?1:len) * sizeof(char));
  226.         strncpy(*(returnHeaders + n), headers, len);
  227.         headers = nextLine + (2 * (int)(n!=0));
  228.         if (len != 0) {
  229.             n++;
  230.         } else {
  231.             free(*(returnHeaders + n));
  232.         }
  233.     } while (nextLine != NULL);
  234.     return returnHeaders;
  235. }
  236.  
  237. void freeHTTPresponse(HTTPresponse *freeResponse) {
  238.     int n;
  239.     for (n = 0; *((freeResponse->headers) + n) != NULL; n++) {
  240.         free(*((freeResponse->headers) + n));
  241.     }
  242.     free(freeResponse->headers);
  243.     free(freeResponse->content);
  244.     free(freeResponse);
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement