How should this be done?
I want to receive a (rather long) HTTP request and cannot get this to work.
The problem: Without flags, recv does not read the whole message. I guess this is normal behavior. From what I understand using the MSG_WAITALL flag causes it to block until everything is received. However, in that case the call blocks forever (until I ctrl+c the client (curl) process.
Below there is a (still lengthy, but rather minimal) example snippet.
Sorry it mixes C and C++ style but I wanted to avoid own errors and sticked largely to example code with as few modifications as possible.
// Example largely based on: beej.us/guide/bgnet/output/html/singlepage/bgnet.html
// Mixes c-style and c++ due to my modifications.
// Only intended to reproduce a problem.
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sstream>
#include <iostream>
#include <cstring>
#define PORT "7004" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
const uint EASILY_ENOUGH = 1000000;
char* buffer = new char[EASILY_ENOUGH + 1];
auto bytesRead = recv(new_fd, buffer, EASILY_ENOUGH, MSG_WAITALL); // FREEZES UNTIL I KILL THE CLIENT
// auto bytesRead = recv(new_fd, buffer, EASILY_ENOUGH, 0); // DOES NOT READ FULL REQUEST
if (bytesRead == -1) {
perror("recv");
close(new_fd);
continue;
}
buffer[bytesRead] = 0;
printf("bytes read: %ld\n", bytesRead);
printf("request: %s\n", buffer);
delete[] buffer;
std::string content = "some content.";
std::ostringstream os;
os << "HTTP/1.1 200 OK\r\n" << "Content-Length: " << content.size() << "\r\n"
<< "Connection: close\r\n" << "Content-Type: " << "plain/text"
<< "; charset=" << "utf-8" << "\r\n"
<< "Access-Control-Allow-Origin: *" << "\r\n" << "\r\n" << content;
std::string response = os.str();
printf("Response has size: %ld\n", response.size());
auto bytesSent = send(new_fd, response.c_str(), response.size(), 0);
printf("Method send claims it has sent %ld bytes\n", bytesSent);
close(new_fd);
}
return 0;
}
The curl resquest i used:
curl 'http://<myhost>:7004/___THE START___jsondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwa___THE END'
With MSG_WAITALL my server produces the output:
server: waiting for connections...
server: got connection from <my ip>
and hangs, once I CTRL+C curl it progresses with:
bytes read: 6379
request: GET /___THE START___jsondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwasondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwa___THE END HTTP/1.1
Host: <myhost>:7004
User-Agent: curl/7.49.0
Accept: */*
Response has size: 144
Method send claims it has sent 144 bytes
Without MSG_WAITALL and the same request, the server produces the output:
server: waiting for connections...
server: got connection from <my ip>
bytes read: 1448
request: GET /___THE START___jsondsadasdasdzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwaghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewjfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiwehfoewhfiuewhfiewhfhfiuewhfiwehfiuewwehgurwadzughjdssftzghuijerdftzghujiesdhufdewojfoewfhoiw
Response has size: 144
Method send claims it has sent 144 bytes
And curl does not receive the HTTP response.
However, a shorter request properly receives the response:
curl 'http://myhost:7004/___THE START___THE END__'
> some content.
And the server properly received the full request:
server: got connection from <my ip>
bytes read: 128
request: GET /___THE START___THE END__ HTTP/1.1
Host: <myhost>:7004
User-Agent: curl/7.49.0
Accept: */*
Response has size: 144
Method send claims it has sent 144 bytes
I do understand that it is normal that not all TCP packets arrive right away. However, what is the correct way for me to assemble the full request? I also tried non-blocking variants but usually ran into situations where no more data was ready for reading. If necessary I can produce sample code for this, similarly.
PS: The problem manifests when request length and connection badness exceed a threshold. I cannot reproduce it on my own machine with queries to localhost, and depending on my connection, the request length where problems start to manifest varies.
HTTP is a protocol, it has structure and rules to it. Read RFC 2616, particularly Section 4 "HTTP Message".
Your recv code is not doing anything to follow the protocol at all. You can't just blindly read an arbitrary buffer of data and expect it to be the complete HTTP request correctly. You have to read the request according to the rules of the protocol. Specifically, you need to:
read a CRLF delimited line of text. This will contain the requested method, resource, and HTTP version.
then read a variable length list of CRLF delimited request headers. The list is terminated by a CRLF CRLF sequence.
then analyze the request method and headers to determine whether the request has an entity body. If so, the headers will tell you how it is encoded over the connection (see Section 4.4 "Message Length"), so you know how it needs to be read and when you need to stop reading.
then process the completed request, and send your response.
then close the connection, unless either:
the request asked for HTTP 1.0 and Connection: keep-alive is present in the request headers.
the request asked for HTTP 1.1+ and Connection: close is not present in the request headers.
Related
I normally write a bunch of Typescript/Javascript code, and I took the HTTP protocol for granted. I decided to write a C++ program that can make GET requests to a given URL with sockets to learn more about how HTTP works. I've coded up what I think is the basic structure of what I should be doing:
Create a socket
Connect the socket to host
Send request byte by byte
Received response byte by byte
The issue is that the request always returns status code 400:
>>>> Request sent:
GET /links HTTP/1.1
>>>> Response received:
HTTP/1.1 400 Bad Request
Server: cloudflare
Date: Sun, 11 Oct 2020 05:57:11 GMT
Content-Type: text/html
Content-Length: 155
Connection: close
CF-RAY: -
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
Here's the code I'm using to create the socket and connect it to the host:
// ---- Create the socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("!!!! ERROR opening socket");
// ---- Look up (and parse) the server host, route
std::string host = parseHost(url);
std::string route = parseRoute(url);
struct hostent *server = gethostbyname(host.c_str()); // host.c_str())
if (server == NULL)
error("!!!! ERROR, no such host");
// ---- Fill in the server address structure
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT); // PORT
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
// ---- Connect the socket to the given url's host
const int didConnect = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (didConnect < 0) error("!!!! ERROR connecting to host");
If that logic seems correct, then here's the code that sends the request and receives the response:
// ---- Send the GET request byte by byte
int bytes, sent, received;
char response[MAX_CONTENT_LENGTH];
int total = sizeof(response) - 1;
sent = 0;
std::string message = "GET " + route + "HTTP/1.1" + "\r\n\r\n";
do
{
bytes = write(sockfd, message.c_str() + sent, total - sent);
if (bytes < 0) error("!!!! ERROR writing message to socket");
if (bytes == 0) break;
sent += bytes;
} while (sent < total);
std::cout << ">>>> Request sent: \n" << message << std::endl;
// ---- Receive the response byte by byte
memset(response, 0, sizeof(response));
total = sizeof(response) - 1;
received = 0;
do {
bytes = read(sockfd, response + received, total - received);
if (bytes < 0)
error("!!!! ERROR reading response from socket");
if (bytes == 0)
break;
received += bytes;
} while (received < total);
if (received == total)
error("!!!! ERROR storing complete response from socket (not enough space allocated)");
TLDR: Am I sending the right char array to the server? As of right now it has this format: "GET /route HTTP/1.1\r\n\r\n". Am I forgetting any headers/other information that lets the server know that it's a GET request?
>>>> Request sent:
GET /links HTTP/1.1
This is not a valid HTTP request. It is missing the Host header with the target domain name, i.e. it should be at least something like this
GET /links HTTP/1.1
Host: www.example.com
Apart from that your code simply tries to read data until the server closes the connection or the size of your internal buffer is reached. But HTTP/1.1 by default uses persistent connection. So the server might simply keep the connection open after the response is sent because it expects your next request, which means that your program will simply block doing nothing.
Note that HTTP is far more complex than it looks. Please study the actual standard if you want to implement it instead of using existing libraries. That's what standards are for.
int proxyRequest(string &request, char buffer[], struct hostent* host){
int sockfd, sockopt;
struct sockaddr_in their_addr;
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
perror("Socket generating failed");
return -1;
}
if(host==NULL){
strcpy(buffer, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n<h2>INET_E_RESOURCE_NOT_FOUND</h2>");
}
else{
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(SERVERPORT);
their_addr.sin_addr.s_addr = ((struct in_addr*)host->h_addr_list[0])->s_addr;
if(connect(sockfd, (struct sockaddr*)&their_addr, sizeof(their_addr)) == -1){
perror("Connection failed");
return -1;
}
write(sockfd, request.c_str(), request.length());
read(sockfd, buffer, BUFSIZE);
cout << buffer << endl;
}
close(sockfd);
return 0;
}
I am making a simple proxy server and everything's fine, except I can't receive a correct resposne body.
This is the request that I send to server(www.example.com). This is represented as "request" in the code.
It seems that http headers are received correctly. However, the html file(body) is not sent at all. And there is a weird character instead of it. Why does this happen? Is it related to null character?
However, the html file(body) is not sent at all. And there is a weird character instead of it. Why does this happen?
The body is sent, but compressed. The following tells you that the content is compressed using the gzip algorithm:
Content-Encoding: gzip
You'll need to either decompress it (taking care around NUL characters) or tell the server that you're not prepared to deal with gzip encoded content (i.e. remove the Accept-Encoding header in your request).
I want to write a simple application, which grabs the content of the HTTPS page: https://httpbin.org/html.
I know how to access its insecure (HTTP) version (http://httpbin.org/html), I just need to send a request using sockets:
std::stringstream ss;
ss << "GET /html HTTP/1.1" << "\r\n"
<< "Host: httpbin.org\r\n"
<< "Connection: close"
<< "\r\n\r\n";
std::string request = ss.str();
// socket creation, connect
send(sock, request.c_str(), request.size(), 0);
And it works. However, when using secure sockets (#include <openssl/ssl.h>) I got the following error: error:14094438:SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error when trying result = SSL_connect(ssl);
Here's the code:
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <iostream>
#include <sstream>
int main(int argc, char **argv)
{
int sock;
char buff[1024];
struct sockaddr_in address;
struct hostent *host = NULL;
std::string servername = "httpbin.org";
if (!inet_aton(servername.c_str(), &address.sin_addr))
if (host = gethostbyname(servername.c_str()))
address.sin_addr = *(struct in_addr*)host->h_addr;
else
return -1;
address.sin_port = htons(443);
address.sin_family = AF_INET;
std::stringstream ss;
ss << "GET /html HTTP/1.1" << "\r\n"
<< "Host: httpbin.org\r\n"
<< "Connection: close"
<< "\r\n\r\n";
std::string request = ss.str();
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1)
{
if (connect(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) != -1)
{
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_method());
if (!ctx)
return -1;
int result = -1;
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
result = SSL_connect(ssl);
if (result == 0)
{
long error = ERR_get_error();
const char* error_str = ERR_error_string(error, NULL);
printf("%s\n", error_str);
return 0;
}
SSL_write(ssl, request.c_str(), request.size());
SSL_read(ssl, buff, 1024);
printf("%s\n", buff);
memset(buff, 0, 1024);
SSL_free(ssl);
SSL_CTX_free(ctx);
close(sock);
}
}
return 0;
}
... SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error when trying result = SSL_connect(ssl);
This means that the server sends a TLSv1 alert back probably because it does not like the information send by the client in the handshake (ClientHello). This might be because the client only offers ciphers which the server does not supports, that the client uses a protocol version not supported or very often also because the server requires the TLS SNI extension to determine which certificate to provide to the client. Testing with other tools indicates that this is actually the case. The problem thus can be solved in your code by using the SNI extension:
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
// ADD THIS
SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (void*)servername.c_str());
result = SSL_connect(ssl);
In case it is ever useful to anyone, I had the same error (irregularly ) in my C++ program and it was driving me mad:
error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
I tried all combinations of OpenSSL, different TLS versions etc, etc.
In the end, I found the Ping I had implemented ( to check the socket was still up ) was being called while another thread's SSL_read / SSL_write() was active on the same SSL object.
This error is generated for a handshake failure, which is caused by a miss-match between what the client offers and what the server accepts.
For some situations, openssl will do a pretty good job of negotiating a working set between the client and server. For other situations, it's a hard failure and you will need to ammend your code. I have seen this error generated due to:
Protocol and cipher missmatch
SSL_set_min_proto_version()
SSL_set_max_proto_version()
SSL_set_cipher_list()
SNI required by the server but not offered by the client
SSL_set_tlsext_host_name()
Reused session offered by client but sessions not implemented on server
SSL_set_session()
I'm trying to send a POST Request and receive a GET response in return.
Here is my code :
#define IP "87.98.245.77"
#define Port 80
void getGETMessage(SOCKET s)
{
char *data = new char[2000];
recv(s, data, strlen(data), NULL);
int x = 3;
}
void SendPOSTMessage(SOCKET s)
{
string data = "POST /index.php?p=convert HTTP/1.1"
"Host: convert2mp3.netConnection: keep-alive"
"Content-Length: 80";
"Cache-Control: max-age=0"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
"Origin: http://convert2mp3.net"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36"
"Content-Type: application/x-www-form-urlencoded"
"Referer: http://convert2mp3.net/index.php?p=home"
"Accept-Encoding: gzip,deflate,sdch"
"Accept-Language: he-IL,he;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2,fr;q=0.2";
if (send(s, data.c_str(), data.length(), NULL) < data.length())
{
cout << "Error : " << WSAGetLastError() << endl;
return ;
}
getGETMessage(s);
}
int main()
{
char *data = new char[200];
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(IP); // IP
clientService.sin_port = htons(Port); // Port
iResult = connect(ConnectSocket, (SOCKADDR *)& clientService, sizeof(clientService));
if (iResult == SOCKET_ERROR)
{
cout << "Error" << endl;
return 0;
}
SendPOSTMessage(ConnectSocket);
cin.get();
cin.get();
}
For some reason, I'm not getting anything back...
I tried getting the IP of this website :
http://convert2mp3.net/index.php?p=home and using cmd, it told me it's http://87.98.245.77/ but it doesn't load in my browser... Maybe this is my error?
Thanks!
Your data is invalid. Each HTTP header needs to be terminated by \r\n, and you need another one after the last line of headers. And you're sending a Content-length of 80 but no content.
Further notes:
If send() returns a positive integer, calling WSAGetLastError() is meaningless. There has been no error, so what you will get is undefined. You should check for -1. In practice send() won't return a short count unless you're in non-blocking mode.
NULL is not a correct fourth parameter for send() or recv(), but 0 is.
There is no such thing as a 'GET response'. There are just HTTP responses.
Problem (at least one) is in this part of code:
void getGETMessage(SOCKET s)
{
char *data = new char[2000];
recv(s, data, strlen(data), NULL);
int x = 3;
}
You didn't initialized data, so, there may be any symbols, so strlen(data) may return 0, if first symbol will be '\0', or something else, depends on when '\0' will appears.
Try to change strlen to sizeof.
Something like that:
void getGETMessage(SOCKET s)
{
char data[2000] = {0};
recv(s, data, sizeof(data)-1, NULL);
cout << data << endl;
int x = 3;
}
Based on your code, you're only sending the header information. You specify a Content-Length of 80, but you're not sending any data. Therefore, the server is still waiting on the data and is not sending a response back to you yet.
My suggestion would be to utilize some HTTP library rather than attempt to perform all the low-level functionality yourself. Some suggestions are in this Stack Overflow question.
I am trying to make a program that uses HTTP in winsock, but I have run into a problem where the recv function just hangs there.
int connect()
{
WSADATA t_wsa; //WSADATA structure
WORD wVers = 0x0202; //version number
int iError; //error number
wVers = MAKEWORD(2, 2); // Set the version number to 2.2
iError = WSAStartup(wVers, &t_wsa); // Start the WSADATA
if(iError != NO_ERROR || iError == 1)
{
printf("Error at WSAStartup()\n");
WSACleanup();
system("PAUSE");
return 1;
}
/* Correct version? */
if(LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2)
{
printf("Incorrect version\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKET sClient;
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET || iError == 1)
{
printf("Invalid Socket!\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKADDR_IN sinClient;
memset(&sinClient, 0, sizeof(sinClient));
char cIP[50];
strcpy_s(cIP, "98.139.183.24");
sinClient.sin_family = AF_INET;
sinClient.sin_addr.s_addr = inet_addr(cIP); // Where to start server
sinClient.sin_port = htons(80); //Port
if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR)
{
/* failed at starting server */
printf("Could not connect ot the server!\n");
WSACleanup();
system("PAUSE");
return 1;
}
// Now we can send/recv data!
printf("YOU ARE CONNECTED!\r\n");
string buffer;
buffer += "GET / HTTP/1.1\r\n";
buffer += "Host: http://www.yahoo.com/\r\n";
buffer += "Connection: close\r\n\r\n";
const char *cha = buffer.c_str();
int sent;
int response;
sent = send(sClient, cha, sizeof(cha) - 1, 0);
char recvbuf[50000];
response = recv(sClient, recvbuf, 50000, 0);
recvbuf[response] = '\0';
printf("\nReceived data = %s", recvbuf);
WSACleanup();
return(0);
}
"sent" will get printed after the send function, but nothing after recv gets printed.
What am I missing here?
A possible cause is that the send() is not sending the data intended:
sent = send(sClient, cha, sizeof(cha) - 1, 0);
the sizeof(cha) - 1 is actually sizeof(char*) - 1, not the actual length of the data: use buffer.length() instead.
Note that you can construct the std::string with the string literal in a single statement instead of constructing it via several concatentations. However, as the std::string is being used to obtain a const char* only there is no reason for using std::string at all:
const char* buffer = "GET / HTTP/1.1\r\n"
"Host: http://www.yahoo.com/\r\n"
"Connection: close\r\n\r\n";
sent = send(sClient, buffer, strlen(buffer), 0);
Check the return value of send() and recv() to determine success or failure, particularly recv() as the result is being used to index an array. On failure, recv() returns SOCKET_ERROR which (I think) is -1.
Handling HTTP responses correctly requires significant effort. The receiving code needs to examine the returned HTTP headers to determine how to handle the response content. For example, a HTTP response may be chunked or not. Libraries exist for managing HTTP requests, one is cpp-netlib (which was announced on isocpp.org circa February 2013).