I have a C program that sends a HTTP request to an url, then retrieves the response, but I got a problem, its hanging forever on function read
, modifying the REQUEST macro to an invalid HTTP request I can read the bad request response, but when I set a valid request it got stuck on read
function, here's the code:
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#define URL "www.google.com"
#define REQUEST "GET / HTTP/1.1\r\nHost: www.google.com\r\n"
int main()
{
struct addrinfo *info;
if ( getaddrinfo(URL, "http", NULL, &info) != 0)
{
fprintf(stderr, "couldn't retrieve info from url\n");
exit(EXIT_FAILURE);
}
int sfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in client;
memset(&client, 0, sizeof(struct sockaddr_in));
client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
if ( bind(sfd, (struct sockaddr*) &client, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "couldn't bind the client\n");
exit(EXIT_FAILURE);
}
else
puts("client bound successfully");
if ( connect(sfd, info->ai_addr, info->ai_addrlen) == -1 )
{
fprintf(stderr, "couldn't connect to the server\n");
exit(EXIT_FAILURE);
}
else
puts("client connect successfully");
if ( write(sfd, REQUEST, strlen(REQUEST)) < 0)
{
fprintf(stderr, "couldn't send request to server\n");
exit(EXIT_FAILURE);
}
else
puts("request sent");
puts("waiting response...\n");
int chksize = 100;
char buff[chksize];
memset(buff, 0, chksize);
// PROGRAM HANGS FOREVER HERE
while ( read(sfd, buff, chksize - 1) > 0 )
{
printf("%s", buff);
memset(buff, 0, chksize);
}
freeaddrinfo(info);
close(sfd);
return 0;
}
CodePudding user response:
In HTTP 1 you have to end the request with an empty line.
https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#HTTP/1.1_request_messages
Request syntax
A client sends request messages to the server, which consist of:[48]
a request line, consisting of the case-sensitive request method, a space, the requested URL, another space, the protocol version, a carriage return, and a line feed, e.g.:
GET /images/logo.png HTTP/1.1
zero or more request header fields (at least 1 or more headers in case of HTTP/1.1), each consisting of the case-insensitive field name, a colon, optional leading whitespace, the field value, an optional trailing whitespace and ending with a carriage return and a line feed, e.g.:
Host: www.example.com
Accept-Language: en
an empty line, consisting of a carriage return and a line feed; an optional message body.
In the HTTP/1.1 protocol, all header fields except Host: hostname are optional.