Home > Net >  http request using sockets on c
http request using sockets on c

Time:01-02

I'm trying to do an HTTP request using sockets on Linux, and my function works now, but only with simple domains as www.google.com or webpage.000webhostapp.com. When I try to add a path and query like webpage.000webhostapp.com/folder/file.php?parameter=value, it starts failing.

This is my code:

#include <iostream>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

int main(){
 int socket_desc;
 struct sockaddr_in serv_addr;
 struct hostent *server;
 char buffer[4096];

 std::string url = "www.exampleweb.com/folder/file.php";

 socket_desc = socket(AF_INET, SOCK_STREAM, 0);
 if(socket_desc < 0){
  std::cout<<"failed to create socket"<<std::endl;
 }

 server = gethostbyname(url.c_str());
 if(server==NULL){std::cout<<"could Not resolve hostname :("<<std::endl;}
 bzero((char *) &serv_addr, sizeof(serv_addr));
 serv_addr.sin_family = AF_INET;
 serv_addr.sin_port = htons(80);
 bcopy((char *)server->h_addr,
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);

 if(connect(socket_desc, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
   std::cout<<"connection failed :("<<std::endl;
 }
 std::string request = "GET / HTTP/1.1\r\nHost: "   url   "\r\nConnection: close\r\n\r\n";

 if(send(socket_desc, request.c_str(), strlen(request.c_str()) 1, 0) < 0){
  std::cout<<"failed to send request..."<<std::endl;
 }
 int n;
 std::string raw_site;
 while((n = recv(socket_desc, buffer, sizeof(buffer) 1, 0)) > 0){
  int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){

            raw_site =buffer[i];
            i  = 1;
        }
 }

 std::cout<<raw_site<<std::endl;
 return 0;
}

Using www.google.com, it works perfectly for the request.

Using www.example.com/folder/file.php?parameter=value&parameter2=value2, it fails and returns "could not resolve hostname".

Any idea on how to fix it?

I'm not using curl and can't use it for this project.

CodePudding user response:

gethostbyname() (which BTW is deprecated, you should be using getaddrinfo() instead) does not work with URLs, only with host names.

Given a URL like http://www.exampleweb.com/folder/file.php?parameter=value&parameter2=value2, you need to first break it up into its constituent pieces (read RFC 3986), eg:

  • the scheme http
  • the host name www.exampleweb.com
  • the resource path /folder/file.php
  • the query ?parameter=value&parameter2=value2

You can then resolve the IP address for the host, connect to that IP address on port 80 (the default port for HTTP) since the URL doesn't specify a different port, and finally send a GET request for the resource and query.

Also, note that the Host header in the GET request must specify only the host name (and port, if different than the default), not the whole URL. And also that HTTP requests are not null-terminated strings, so do not send the null terminator. Read RFC 2616.

Try this instead:

#include <iostream>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

int main(){
    int socket_desc;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[4096];

    std::string host = "www.exampleweb.com";
    std::string port = "80";
    std::string resource = "/folder/file.php";
    std::string query = "?parameter=value&parameter2=value2";

    socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_desc < 0){
        std::cout << "failed to create socket" << std::endl;
        return 0;
    }

    server = gethostbyname(host.c_str());
    if (server == NULL){
        std::cout << "could Not resolve hostname :(" << std::endl;
        close(socket_desc);
        return 0;
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(std::stoi(port));
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);

    if (connect(socket_desc, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
        std::cout << "connection failed :(" << std::endl;
        close(socket_desc);
        return 0;
    }

    std::string request = "GET "   resource   query   " HTTP/1.1\r\nHost: "   host   "\r\nConnection: close\r\n\r\n";

    if (send(socket_desc, request.c_str(), request.size(), 0) < 0){
        std::cout << "failed to send request..." << std::endl;
        close(socket_desc);
        return 0;
    }

    int n;
    std::string raw_site;
    while ((n = recv(socket_desc, buffer, sizeof(buffer), 0)) > 0){
        raw_site.append(buffer, n);
    }

    close(socket_desc);

    std::cout << raw_site << std::endl;
    return 0;
}
  • Related