Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- helloworld.c
- Dylan Weber
- */
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <time.h>
- typedef struct URLdata {
- char *protocol;
- char *username;
- char *password;
- char *host;
- char *port;
- char *path;
- } URLdata;
- typedef struct HTTPresponse {
- int status;
- char **headers;
- char *content;
- } HTTPresponse;
- URLdata *createURLdata(char *weburl);
- void freeURLdata(URLdata *freeURL);
- HTTPresponse *requestHTTPresponse(URLdata *requestDestination);
- void *get_in_addr(struct sockaddr *sa);
- char **generateHeaderList(char *headers);
- void freeHTTPresponse(HTTPresponse *freeResponse);
- void copyAndTerminateString(char *dest, char *src, int len);
- char *base64encode(char *input);
- int main(int argc, char **argv) {
- if (argc != 2) {
- printf("Usage: helloworld ... destination\r\n");
- return 1;
- }
- URLdata *inputURL = createURLdata(argv[1]);
- HTTPresponse *outputResponse = requestHTTPresponse(inputURL);
- /*printf("Response Code:%d\r\nHeaders:\r\n", outputResponse->status);
- int n;
- for (n = 0; outputResponse->headers[n] != NULL; n++) {
- printf("%d: \"%s\"\r\n", n+1, outputResponse->headers[n]);
- }
- int conlen = strlen(outputResponse->content);
- printf("Content length:%d\r\n", conlen);
- printf("Content:\"%.100s\"%s\r\n", outputResponse->content, (conlen > 100)?"...":"");*/
- freeURLdata(inputURL);
- freeHTTPresponse(outputResponse);
- return 0;
- }
- URLdata *createURLdata(char *weburl) {
- char *postprotocol, *postuserinfo, *postusername, *posthost, *posthostname, *hostloc;
- int isPath = 1, userlen;
- URLdata *returnURL = malloc(sizeof(URLdata));
- returnURL->protocol = NULL;
- returnURL->username = NULL;
- returnURL->password = NULL;
- returnURL->host = NULL;
- returnURL->port = NULL;
- returnURL->path = NULL;
- if ((postprotocol = strstr(weburl, "://")) == NULL) {
- return returnURL;
- }
- returnURL->protocol = malloc(sizeof(char) * (postprotocol - weburl) + 1);
- copyAndTerminateString(returnURL->protocol, weburl, postprotocol - weburl);
- postprotocol = (postprotocol + (*(postprotocol+3)=='/'?4:3));
- if ((postuserinfo = strstr(postprotocol, "@")) != NULL) {
- if ((postusername = strchr(postprotocol, ':')) != NULL) {
- returnURL->password = malloc(sizeof(char) * (postuserinfo - postusername) + 1);
- copyAndTerminateString(returnURL->password, postusername + 1, postuserinfo - postusername - 1);
- }
- userlen = (postusername?postusername:postuserinfo) - postprotocol;
- returnURL->username = malloc(sizeof(char) * userlen + 1);
- copyAndTerminateString(returnURL->username, postprotocol, userlen);
- }
- hostloc = (postuserinfo?postuserinfo + 1:postprotocol);
- if ((posthost = strchr(hostloc, '/')) == NULL) {
- posthost = hostloc + strlen(hostloc);
- isPath = 0;
- }
- if ((posthostname = strchr(hostloc, ':')) == NULL) {
- posthostname = posthost;
- }
- returnURL->host = malloc(sizeof(char) * (posthostname - hostloc + 1));
- copyAndTerminateString(returnURL->host, hostloc, (posthostname - hostloc));
- if (posthostname != posthost) {
- posthostname++;
- returnURL->port = malloc(sizeof(char) * (posthost - posthostname + 1));
- copyAndTerminateString(returnURL->port, posthostname, (posthost - posthostname));
- } else {
- returnURL->port = malloc(sizeof(char) * 2 + 1);
- copyAndTerminateString(returnURL->port, "80", 2);
- }
- if (isPath) {
- returnURL->path = malloc(sizeof(char) * strlen(posthost) + 1);
- copyAndTerminateString(returnURL->path, posthost, strlen(posthost));
- } else {
- returnURL->path = calloc(1, 1);
- }
- return returnURL;
- }
- void freeURLdata(URLdata *freeURL) {
- free(freeURL->protocol);
- free(freeURL->username);
- free(freeURL->password);
- free(freeURL->host);
- free(freeURL->port);
- free(freeURL->path);
- free(freeURL);
- }
- HTTPresponse *requestHTTPresponse(URLdata *requestDestination) {
- char ip[INET6_ADDRSTRLEN], *request, *response = NULL, *headerTerminator = NULL, *responseTerminator = NULL, *headerString, *contentString, *authstring = NULL, buffer[100];
- int sockfd, bufferLength, requesttime, responseLength = 0;
- struct addrinfo hints, *servinfo, *p;
- /* Initialize HTTP response structure */
- HTTPresponse *returnresponse = malloc(sizeof(HTTPresponse));
- returnresponse->status = 0;
- returnresponse->headers = NULL;
- returnresponse->content = NULL;
- /* Retrieve IP address of host */
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- if (getaddrinfo(requestDestination->host, requestDestination->port, &hints, &servinfo) != 0) {
- return returnresponse;
- }
- /* Loop through all possible connections */
- for (p = servinfo; p != NULL; p = p->ai_next) {
- if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
- continue;
- }
- if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
- close(sockfd);
- continue;
- }
- break;
- }
- if (p == NULL) {
- return returnresponse;
- }
- /* Print IP address & free server information */
- inet_ntop(p->ai_family, get_in_addr((struct sockaddr*)p->ai_addr), ip, sizeof(ip));
- printf("The IP address is: %s\n", ip);
- freeaddrinfo(servinfo);
- /* Format HTTP request */
- if (requestDestination->username && requestDestination->password) {
- char *preencode, *encode;
- preencode = malloc(2 + (int)strlen(requestDestination->username) + (int)strlen(requestDestination->password) * sizeof(char));
- sprintf(preencode, "%s:%s", requestDestination->username, requestDestination->password);
- encode = base64encode(preencode);
- authstring = malloc(24 + (int)strlen(encode) * sizeof(char));
- sprintf(authstring, "\r\nAuthorization: Basic %s", encode);
- free(preencode);
- free(encode);
- printf("AUTH: %s\r\n", authstring + 2);
- }
- request = malloc((26 + (int)strlen((*(requestDestination->path) == 0)?"/":requestDestination->path) + (int)strlen(requestDestination->host) + ((authstring != NULL)?(int)strlen(authstring):0)) * sizeof(char));
- if (request == NULL) {
- printf("Failure to allocate memory at line %d.\n", __LINE__ - 2);
- exit(1);
- }
- sprintf(request, "GET %s HTTP/1.1\r\nHost: %s%s\r\n\r\n", (*(requestDestination->path) == 0)?"/":requestDestination->path, requestDestination->host, ((authstring != NULL)?authstring:""));
- if (authstring != NULL) free(authstring);
- /* Send HTTP request */
- send(sockfd, request, (int)strlen(request), 0);
- free(request);
- requesttime = time(NULL);
- /* Receive HTTP response */
- do {
- bufferLength = recv(sockfd, buffer, 99, 0);
- if (bufferLength == -1) {
- break;
- }
- responseLength += bufferLength;
- response = realloc(response, (responseLength + 1) * sizeof(char));
- if (response == NULL) {
- printf("Failure to allocate memory at line %d.\r\n", __LINE__ - 2);
- exit(2);
- }
- copyAndTerminateString(response + responseLength - bufferLength, buffer, bufferLength);
- if (headerTerminator) {
- responseTerminator = strstr(headerTerminator+4, "\r\n\r\n");
- } else {
- headerTerminator = strstr(response, "\r\n\r\n");
- }
- if ((time(NULL) - requesttime) > 20) {
- printf("Server timeout error.\r\n");
- exit(1);
- }
- } while (responseTerminator == NULL);
- /* Store data in structs */
- headerString = malloc((headerTerminator - response + 1) * sizeof(char));
- if (headerString == NULL) {
- printf("Failure to allocate memory at line %d.\r\n", __LINE__ - 2);
- exit(1);
- }
- copyAndTerminateString(headerString, response, headerTerminator - response);
- contentString = malloc((responseTerminator - headerTerminator + 1) * sizeof(char));
- if (contentString == NULL) {
- printf("Failure to allocate memory at line %d.\r\n", __LINE__ - 2);
- exit(1);
- }
- copyAndTerminateString(contentString, headerTerminator+4, responseTerminator - headerTerminator - 4);
- returnresponse->headers = generateHeaderList(headerString);
- returnresponse->content = contentString;
- free(headerString);
- free(response);
- /* Extract status code */
- if (strncmp(returnresponse->headers[0], "HTTP", 4) == 0) {
- response = malloc(4 * sizeof(char));
- copyAndTerminateString(response, returnresponse->headers[0] + 9, 3);
- returnresponse->status = atoi(response);
- free(response);
- } else {
- returnresponse->status = -1;
- }
- /* Close connection & return HTTP response */
- close(sockfd);
- return returnresponse;
- }
- void *get_in_addr(struct sockaddr *sa) {
- if (sa->sa_family == AF_INET) {
- return &(((struct sockaddr_in*)sa)->sin_addr);
- } else if (sa->sa_family == AF_INET6) {
- return &(((struct sockaddr_in6*)sa)->sin6_addr);
- }
- return 0;
- }
- char **generateHeaderList(char *headers) {
- char **returnHeaders = NULL, *nextLine;
- int len, n;
- for (n = 0; (nextLine = strstr(headers, "\r\n")) != NULL; n++) {
- len = nextLine - headers;
- if (len == 0) break;
- returnHeaders = realloc(returnHeaders, (n + 1) * sizeof(char *));
- if (returnHeaders == NULL) {
- printf("Failure to allocate memory at line %d.\r\n", __LINE__ - 2);
- exit(1);
- }
- returnHeaders[n] = malloc((len + 1) * sizeof(char));
- copyAndTerminateString(returnHeaders[n], headers, len);
- headers = nextLine + 2;
- printf("finished %d at %p\r\n", n, (void *)*(returnHeaders + n));
- }
- printf("with %d, remaining %s\r\n", n, headers);
- len = strlen(headers);
- if (len == 0) return returnHeaders;
- returnHeaders = realloc(returnHeaders, (n + 1) * sizeof(char *));
- if (returnHeaders == NULL) {
- printf("Failure to allocate memory at line %d.\r\n", __LINE__ - 2);
- exit(1);
- }
- returnHeaders[n] = malloc((len + 1) * sizeof(char));
- copyAndTerminateString(returnHeaders[n], headers, len);
- returnHeaders[n+1] = NULL;
- return returnHeaders;
- }
- void freeHTTPresponse(HTTPresponse *freeResponse) {
- int n;
- for (n = 0; freeResponse->headers[n] != NULL; n++) {
- printf("freeing %d at %p: %s\r\n", n, (void *)*(freeResponse->headers + n), freeResponse->headers[n]);
- free(freeResponse->headers[n]);
- }
- free(freeResponse->headers);
- free(freeResponse->content);
- free(freeResponse);
- }
- void copyAndTerminateString(char *dest, char *src, int len) {
- strncpy(dest, src, len);
- dest[len] = '\0';
- }
- char *base64encode(char *input) {
- int len = strlen(input), leftover = len % 3, n = 0, outlen = 0;
- char *ret = malloc(((len / 3) * 4) + ((leftover)?4:0) + 1);
- uint8_t *inp = (uint8_t *)input, i = 0;
- const char *index = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- if (ret == NULL) {
- return NULL;
- }
- len -= leftover;
- for (n = 0; n < len; n+=3) {
- i = inp[n] >> 2;
- ret[outlen++] = index[i];
- i = (inp[n] & 0x03) << 4;
- i |= (inp[n+1] & 0xf0) >> 4;
- ret[outlen++] = index[i];
- i = ((inp[n+1] & 0x0f) << 2);
- i |= ((inp[n+2] & 0xc0) >> 6);
- ret[outlen++] = index[i];
- i = (inp[n+2] & 0x3f);
- ret[outlen++] = index[i];
- }
- if (leftover) {
- i = (inp[n] >> 2);
- ret[outlen++] = index[i];
- i = (inp[n] & 0x03) << 4;
- if (leftover == 2) {
- i |= (inp[n+1] & 0xf0) >> 4;
- ret[outlen++] = index[i];
- i = ((inp[n+1] & 0x0f) << 2);
- }
- ret[outlen++] = index[i];
- ret[outlen++] = '=';
- if (leftover == 1) {
- ret[outlen++] = '=';
- }
- }
- ret[outlen] = '\0';
- return ret;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement