My first C project is a simple cURL-like HTTP client that retrieves the headers, content, and status of a request sent to a server. It's been working out so far, but it is not finished and I need some help. Memory allocation has been a bit of a hurdle for me and this current issue is one I cannot solve by myself.
In a function called HTTPresponse *requestHTTPresponse(URLdata *requestDestination)
, the reallocation of a string that holds the raw HTTP response headers and contents fails for some unknown reason. The pointer for the raw HTTP response string is set to NULL, and I'm forced to exit my program. Why is this behavior happening and how do I solve it? Additionally, when I compile my program, it sometimes just freezes and refuses to print out text as intended or to exit, which could be the result of DNS hanging up or some other odd network issue. Any other advice is also welcome.
The full C source code can be found here.
HTTPresponse *requestHTTPresponse(URLdata *requestDestination) {
char ip[INET6_ADDRSTRLEN], *request, *response = malloc(1), *headerTerminator = NULL, *responseTerminator = NULL, *headerString, *contentString, buffer[100];
int sockfd, bufferLength, responseLength;
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 */
request = malloc(27 + (int)strlen(requestDestination->path) + (int)strlen(requestDestination->host) * sizeof(char));
if (request == NULL) {
printf("Failure to allocate memory.\n");
exit(1);
}
sprintf(request, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", (*(requestDestination->path) == 0)?"/":requestDestination->path, requestDestination->host);
/* Send HTTP request */
send(sockfd, request, 26 + strlen(requestDestination->path) + strlen(requestDestination->host), 0);
free(request);
/* Receive HTTP response */
do {
bufferLength = recv(sockfd, buffer, 99, 0);
if (bufferLength == -1) {
break;
}
responseLength += bufferLength;
response = realloc(response, (responseLength + 1) * sizeof(char)); //Source of issues
if (response == NULL) {
printf("Failure to allocate memory.\n");
exit(2);
}
strncpy(response + responseLength - bufferLength, buffer, bufferLength);
if (headerTerminator) {
responseTerminator = strstr(response, "\r\n\r\n");
} else {
headerTerminator = strstr(response, "\r\n\r\n");
}
} while (responseTerminator == NULL);
/* Store data in structs */
headerString = malloc((headerTerminator - response + 1) * sizeof(char));
if (headerString == NULL) {
printf("Failure to allocate memory.\n");
exit(1);
}
strncpy(headerString, response, headerTerminator - response);
contentString = malloc((responseTerminator - headerTerminator) * sizeof(char));
if (contentString == NULL) {
printf("Failure to allocate memory.\n");
exit(1);
}
strncpy(contentString, headerTerminator, responseTerminator - headerTerminator);
returnresponse->headers = generateHeaderList(headerString);
returnresponse->content = contentString;
free(response);
/* Close connection & return HTTP response */
close(sockfd);
return returnresponse;
}
Make sure your variables are initialized. In the original question, you were trying to realloc a null pointer, and you need to be sure your responselength variable is initialized to 0.
----- EDIT -----
Also, when grabbing data from a network connection, be sure your strings are zero-terminated if you use functions like strcpy.