Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
HTTP Request in C using low level write to socket functionality
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
int socket_connect(char *host, in_port_t port){
struct hostent *hp;
struct sockaddr_in addr;
int on = 1, sock;
if((hp = gethostbyname(host)) == NULL){
herror("gethostbyname");
exit(1);
}
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));
if(sock == -1){
perror("setsockopt");
exit(1);
}
if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(1);
}
return sock;
}
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]){
int fd;
char buffer[BUFFER_SIZE];
if(argc < 3){
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
exit(1);
}
fd = socket_connect(argv[1], atoi(argv[2]));
write(fd, "GET /\r\n", strlen("GET /\r\n")); // write(fd, char[]*, len);
bzero(buffer, BUFFER_SIZE);
while(read(fd, buffer, BUFFER_SIZE - 1) != 0){
fprintf(stderr, "%s", buffer);
bzero(buffer, BUFFER_SIZE);
}
shutdown(fd, SHUT_RDWR);
close(fd);
return 0;
}
@sebitoelcheater

This comment has been minimized.

Copy link

sebitoelcheater commented Sep 21, 2014

nice work! how can I go to for example, localhost:3000/something ?

@TylerTemp

This comment has been minimized.

Copy link

TylerTemp commented Jun 24, 2016

@sebitoelcheater

gcc socket.c -o soc
./soc https://www.google.com 80
@dimuthnc

This comment has been minimized.

Copy link

dimuthnc commented Dec 1, 2016

I tried to call localhost:8080/services from this. It fails in every way. Can you please help me?

@fxfactorial

This comment has been minimized.

Copy link

fxfactorial commented Dec 26, 2016

@dimuthnc change the code to give 127.0.0.1 for whenever host is localhost

@Matrixbirds

This comment has been minimized.

Copy link

Matrixbirds commented Jan 27, 2017

why use PF_INET for create sock.. addr structure be set by AF_INET..

@alr-lab

This comment has been minimized.

Copy link

alr-lab commented Feb 28, 2017

@sebitoelcheater and @dimuthnc you need to modify the request header https://gist.github.com/nolim1t/126991#file-socket-c-L53 to something such as GET /something HTTP/1.1\r\n, maybe create a #define if you want to use it everytime OR change the code so it accept a third argument (or parse it from the complete URI): the suffix URI - the requested page.

The GET /\r\n in this Gist will ask for the index page (/) if any.

Reminder: a minimal header may look like:

GET /something HTTP/1.1\r\n
Host: www.42.fr\r\n
\r\n

which, if successfully sent, will trigger a request to a web server located at www.42.fr to get the /something page using the GET HTTP method. Note the double \r\n line ending, ending the header.

I hope this will help you!
Happy coding everyone

@minhnv-viosoft

This comment has been minimized.

Copy link

minhnv-viosoft commented May 15, 2017

I've used your code to get a text file ( about 70KB)
It run through the while loop about 25 times,
but the last loop it seem very slow , I think it's been blocking somewhere ( maybe in read function). please help me to explain .

example the file :
http://super-pomoyka.us.to//trash/ttv-list/ttv.m3u

@RossignolVincent

This comment has been minimized.

Copy link

RossignolVincent commented Jun 12, 2017

Hello, i try to run this code on the Star Wars API (https://swapi.co/) but it doesn't work. I've tried multiple configurations :

./api swapi.co/ 80
gethostbyname: Unknown host
./api http://swapi.co/api/people/1/ 80
gethostbyname: Unknown host

Even with you example with google.com, i've got the same error message. Do you know why ?

@Cannedfood

This comment has been minimized.

Copy link

Cannedfood commented Jun 28, 2017

@RossignolVincent Have you tried www.swapi.co?

@mudiadamz

This comment has been minimized.

Copy link

mudiadamz commented Jul 21, 2017

what if the response is 302 redirection,
how to make a request to new location?

@ajvuik

This comment has been minimized.

Copy link

ajvuik commented Sep 19, 2017

Thank for this. I used this in conjuction with Arduino Json to get the local weather from http://openweathermap.org. Works like a treat 👍

@wb-towa

This comment has been minimized.

Copy link

wb-towa commented Sep 30, 2017

gethostbyname() isn't very futureproof. gethostbyname2() will at least let you opt for ipv4 or ipv6

As alr-lab pointed out the headers are incomplete.

I think most of the problems people are experiencing is down to not understanding the code (i.e. including the http and ending slash rather than just www.google.com) so it may have been nicer to include some examples or comments. Of course this is 8 years old too so understandably it may not hold up as well now.

It is a good pointer in the right direction but learners will need to work on it bit.

@hebrerillo

This comment has been minimized.

Copy link

hebrerillo commented Nov 26, 2017

When I try to get this url "http://www.cplusplus.com/" the webserver performs a 301 redirection to the same url.

Why? What am I doing wrong?

This is the command line I am executing:

./a.out www.cplusplus.com 80

Thanks a lot!

@hebrerillo

This comment has been minimized.

Copy link

hebrerillo commented Nov 26, 2017

Hi everyone!

I found the solution, the get request should be like this :

"GET / HTTP/1.0\r\nHost: www.cplusplus.com\r\n\r\n\r\n"

All the best!

@itsKindred

This comment has been minimized.

Copy link

itsKindred commented Jan 31, 2019

It looks like the GET request is missing a second \r\n. HTTP Requests require a blank line at the end. If you do a raw nc to a web server, and send "GET /" and press enter, you wont get a response. Once hitting enter again, however, you will get a response. This is due to that second \r\n being needed. write(fd, "GET /\r\n", strlen("GET /\r\n")); // write(fd, char[], len); should actually be write(fd, "GET /\r\n\r\n", strlen("GET /\r\n\r\n")); // write(fd, char[], len);

@kinnounko

This comment has been minimized.

Copy link

kinnounko commented Feb 9, 2019

This doesn't work on Mac. I keep getting an error:

Undefined symbols for architecture x86_64:
  "_copy", referenced from:
      _socket_connect in msgario-a206e2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
@kinnounko

This comment has been minimized.

Copy link

kinnounko commented Feb 10, 2019

This code snippet should use bcopy() instead of copy(). copy() doesn't work.

@SirDrope

This comment has been minimized.

Copy link

SirDrope commented Jul 16, 2019

try with -> ./soc www.google.com 80

@Andermutu

This comment has been minimized.

Copy link

Andermutu commented Oct 21, 2019

Hi;

I am trying to send a Telegram message using HTTP GET. However, I don't know how to pass the required parameters. I have try this:

"GET / HTTP/1.1\r\nHost: https://api.telegram.org/botmybottokenhere/sendMessage?chat_id=mychatidhere&text=mymessagehere\r\nConnection: close\r\n\r\n"

but does not work. I get a 400 bad request error. But if I copy that url and paste it in Chrome the message is sent, so the url is correct. It also works in Python3.7.

Thanks.

@Penniman

This comment has been minimized.

Copy link

Penniman commented Nov 12, 2019

I am trying to send a Telegram message using HTTP GET. However, I don't know how to pass the required parameters. I have try this:

"GET / HTTP/1.1\r\nHost: https://api.telegram.org/botmybottokenhere/sendMessage?chat_id=mychatidhere&text=mymessagehere\r\nConnection: close\r\n\r\n"

but does not work. I get a 400 bad request error. But if I copy that url and paste it in Chrome the message is sent, so the url is correct. It also works in Python3.7.

You're getting the 400 error because you are sending an HTTP request to an HTTPS-encrypted endpoint. For what it's worth, I stumbled upon your comment because I am running into this exact same issue and I am trying to figure out how to send an HTTPS-based request using the low-level socket_*() functions. If I figure this out then I'll try to pop back in here and see if I can share my knowledge.

The response I receive in my own attempts are as follows:

400 The plain HTTP request was sent to HTTPS port
400 Bad Request
The plain HTTP request was sent to HTTPS port

@nolim1t

This comment has been minimized.

Copy link
Owner Author

nolim1t commented Nov 13, 2019

This bit of code only relates to non-SSL secured endpoints. For SSL you would have to add in SSL/TLS related negotiation code too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.