I have coded this C function to make a simple GET
request to my Apache HTTP server at localhost. The function uses a socket file descriptor, sockfd
.
char *send_http_get (int sockfd) {
// Allocate a buffer to write/read bytes
const int buffer_size = 512;
char *buffer = malloc(buffer_size);
// write "GET /" to the server
bzero(buffer, buffer_size);
strncpy(
buffer,
"GET / HTTP/1.1\r\n"
"\r\n",
buffer_size
);
write(sockfd, buffer, strlen(buffer));
// Read the response from the server
bzero(buffer, buffer_size);
read(sockfd, buffer, buffer_size);
// Make buffer a c-string
buffer[buffer_size - 1] = 0;
return buffer;
}
The function sends the request and receives the response, but something very silly may be wrong with the sending process as I always get a 400 Bad Request
status code from my Apache HTTP server.
HTTP/1.1 400 Bad Request
Date: Fri, 28 Oct 2022 11:31:21 GMT
Server: Apache/2.4.51 (Unix)
Content-Length: 226
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>
This is a complete test program to test the idea.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h> // for hostent
#define SA struct sockaddr
#define DEFAULT_TIMEOUT 5
#define HOSTNAME_MAX_LEN 128
///////////////////
// TCP FUNCTIONS //
///////////////////
char *send_http_get (int sockfd) {
// Allocate a buffer to write/read bytes
const int buffer_size = 512;
char *buffer = malloc(buffer_size);
// Write "GET /" to the server
bzero(buffer, buffer_size);
strncpy(
buffer,
"GET / HTTP/1.1\r\n"
"\r\n",
buffer_size
);
write(sockfd, buffer, strlen(buffer));
// read the response from the server
bzero(buffer, buffer_size);
read(sockfd, buffer, buffer_size);
// Make buffer a c-string
buffer[buffer_size - 1] = 0;
return buffer;
}
/**
* Creates a client socket to connect to the target server at hostname:port.
* Returns the client socket file descriptor or -1 if anything goes wrong.
*/
int connect_to_server (char *hostname, int port) {
// Ask for a new client socket to the OS
int sockfd;
struct sockaddr_in ipa;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Check the socket is OK
if (sockfd == -1) {
fprintf(stderr, "Error: Cannot create a socket\n");
return -1;
}
// Zero the ipa struct
bzero(&ipa, sizeof(ipa));
// Populate the server IP address struct
ipa.sin_family = AF_INET;
ipa.sin_addr.s_addr = inet_addr(hostname);
ipa.sin_port = htons(port);
// Connect the client socket to the server socket
if (connect(sockfd, (SA*)&ipa, sizeof(ipa)) != 0) {
// todo: find everything that can be learned from the remote socket
close(sockfd);
return -1;
}
// Set a timeout for read operations on the server
// See https://stackoverflow.com/a/2939145/8520235
struct timeval tv;
tv.tv_sec = 2; // 2s
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
return sockfd;
}
//////////////////
// MAIN PROGRAM //
//////////////////
int main () {
int sockfd;
char *buffer;
// Connect to the server port
if ((sockfd = connect_to_server("127.0.0.1", 80)) > 0) {
buffer = send_http_get(sockfd);
printf("%s\n", buffer);
close(sockfd);
free(buffer);
}
return 0;
}
Any idea of what is going wrong here?
EDIT
A Host
header was missing, as Example person mentioned.
strncpy(
buffer,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"\r\n",
buffer_size
);
A good explanation on the need of Host
header can be found here
https://stackoverflow.com/a/8824910/8520235