I made a simple client program with C that sends HTTP request to a host. The last part of the code, where the client receives HTTP response from server looks like this:
int main(int argc, char *argv[])
{
// ...
char buf[BUFSIZ];
int content_length;
content_length = recv(clientfd, buf, sizeof(buf) - 1, 0);
buf[content_length] = 0;
printf("%s", buf);
fflush(stdout);
exit(EXIT_SUCCESS);
}
With this code, I often get the expected result like the following:
GET /foo HTTP/1.0
Host: 127.0.0.1:8080
HTTP/1.0 200 OK
Content-Length: 12
Connection: close
abadakedavra
But sometimes, the content of the request doesn't show up.
GET /foo HTTP/1.0
Host: 127.0.0.1:8080
HTTP/1.0 200 OK
Content-Length: 12
Connection: close
What could be the reason for this behavior?
cf. My whole client code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAX_REQUEST 10000
#define MAX_URL 2048
void error(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void parse_url(char *src, char *hostname, char *port, char *url)
{
size_t i, j = 0;
for (i = 7; src[i] != ':'; i++)
hostname[j++] = src[i];
hostname[j] = 0;
j = 0;
for (i = i + 1; src[i] != '/'; i++)
port[j++] = src[i];
port[j] = 0;
j = 0;
for (i = i + 1; src[i]; i++)
url[j++] = src[i];
url[j] = 0;
}
int main(int argc, char *argv[])
{
/*
Expect
argv[0] : ./client (Executable name)
argv[1] : -G (GET) or -P (POST)
argv[2] : http://hostname:port/url
*/
int clientfd;
char hostname[MAX_URL], port[6], url[MAX_URL];
char msg[MAX_REQUEST];
struct addrinfo hints, *listp, *p;
if (argc < 3 || (strcmp(argv[1], "-G") != 0 && strcmp(argv[1], "-P") != 0))
{
printf("Usage:\n %s -P <URL> HTTP 1.0 POST from stdin\n"
" %s -G <URL> HTTP 1.0 GET to stdin\n",
argv[0], argv[0]);
exit(EXIT_FAILURE);
}
parse_url(argv[2], hostname, port, url);
if(strcmp(argv[1], "-P") == 0) fgets(msg, MAX_REQUEST, stdin);
/* Client socket creation */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; // Use TCP
hints.ai_flags = AI_NUMERICSERV; // Use numeric port arg
// Generate a list of addrinfo in listp
getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next)
{
// Create a socket based on addrinfo struct
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1)
break;
close(clientfd); // Bind fail, loop to try again
}
freeaddrinfo(listp); // Not needed anymore
if (!p) // Entire loop failed
{
error("Failed in socket binding");
}
/* Send HTTP Request */
char httpRequest[MAX_REQUEST];
if(strcmp(argv[1], "-G") == 0) sprintf(httpRequest, "GET /%s HTTP/1.0\r\nHost: %s:%s\r\n\r\n", url, hostname, port);
else if(strcmp(argv[1]), "-P" == 0) sprintf(httpRequest, "POST /%s HTTP/1.0\r\nHost: %s:%s\r\nContent-Type: plain/text\r\nContent-Length: %lu\r\n\r\n%s\n", url, hostname, port, strlen(msg), msg);
else error("Invalid request");
printf("%s", httpRequest);
send(clientfd, httpRequest, strlen(httpRequest), 0);
/* Recieve HTTP response */
char buf[BUFSIZ];
int content_length;
content_length = recv(clientfd, buf, sizeof(buf) - 1, 0);
buf[content_length] = 0;
printf("%s", buf);
fflush(stdout);
exit(EXIT_SUCCESS);
}