Skip to content

Instantly share code, notes, and snippets.

@nolim1t
Created June 10, 2009 03:14
Show Gist options
  • Save nolim1t/126991 to your computer and use it in GitHub Desktop.
Save nolim1t/126991 to your computer and use it in GitHub Desktop.
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;
}
@Andermutu
Copy link

Andermutu commented Sep 26, 2020

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

I think you need to add something like this to add TLS :

int client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
enum {
NONE = 0,
OPTIONAL = 1,
REQUIRED = 2,
};

int verify = OPTIONAL;

err = setsockopt(client_fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify));

@naushadckk
Copy link

Error - IPPROTO_TLS_1_2 is not defined..........

@renatoathaydes
Copy link

@Andermutu it has been a while , but in case you're still interested :)

This is not valid HTTP:

"GET / HTTP/1.1\r\nHost: [https://api.telegram.org/botmybottokenhere/sendMessage?chat_id=mychatidhere&text=mymessagehere\r\nConnection](https://api.telegram.org/botmybottokenhere/sendMessage?chat_id=mychatidhere&text=mymessagehere%5Cr%5CnConnection): close\r\n\r\n"

The host header should contain only the host. You've given it a full URL!

And your request path is just / so it would never work.

Also, you're trying to send a https request which means the socket needs to be encrypted. And notice that the protocol doesn't go in the HTTP request itself as that refers to the transport being used.

So, your request should look like this (\r\n replaced with simple new-lines for readability, you still need them in a real request):

GET /botmybottokenhere/sendMessage?chat_id=mychatidhere&text=mymessagehere HTTP/1.1
Host: api.telegram.org
Connection: close

@0x2a94b5
Copy link

0x2a94b5 commented Aug 17, 2022

@dimuthnc

localhost:8080/services

write(fd, "GET /services HTTP/1.1\r\n\r\n", strlen("GET /services HTTP/1.1\r\n\r\n"));

Run command:

gcc socket.c -o socket
./socket localhost 8080

@rilysh
Copy link

rilysh commented Sep 1, 2022

You may want to use bcopy instead of copy at line 22

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment