I have the following raw HTTP request:
GET http://www.google.ie/ HTTP/1.1
Host: www.google.ie
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encod...
I'm trying to send this from my localhost. Could someone point me in the right direction as to how I might do this in C or C++?
I'm currently looking at sockets, but it's not really working.
int sockfdi, portnoi, ni;
struct sockaddr_in serv_addri;
struct hostent *serveri;
portnoi =80;
sockfdi = socket(AF_INET, SOCK_STREAM, 0);
if (sockfdi < 0){
error("***ERROR opening socket");
}
serveri = gethostbyname("172.16.1.218");
if (serveri == NULL){
fprintf(stderr,"***ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addri, sizeof(serv_addri));
serv_addri.sin_family = AF_INET;
bcopy((char *)serveri->h_addr, (char *)&serv_addri.sin_addr.s_addr, serveri->h_length);
serv_addri.sin_port = htons(portnoi);
if (connect(sockfdi,(struct sockaddr *) &serv_addri,sizeof(serv_addri)) < 0){
error("***ERROR connecting");
}
printf("Please enter the message: ");
bzero(buffer,256);
You could try using libcurl instead of sockets:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
curl = curl_easy_init();
if(curl) {
headers = curl_slist_append(headers, "Host: www.google.ie");
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20100101 Firefox/5.0");
headers = curl_slist_append(headers, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers = curl_slist_append(headers, "Accept-Language: en-us,en;q=0.5");
/* Add more headers here */
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.ie/");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return 0;
}
Related
I'm trying to build a Discord API with C (libdiscord it's constantly crashing).
I have found this promosing code (found here):
#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */
void error(const char *msg) { perror(msg); exit(0); }
int main(int argc,char *argv[])
{
/* first what are we going to send and where are we going to send it? */
int portno = 80;
char *host = "api.somesite.com";
char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";
struct hostent *server;
struct sockaddr_in serv_addr;
int sockfd, bytes, sent, received, total;
char message[1024],response[4096];
if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }
/* fill in the parameters */
sprintf(message,message_fmt,argv[1],argv[2]);
printf("Request:\n%s\n",message);
/* create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
/* lookup the ip address */
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
/* fill in the structure */
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
/* connect the socket */
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
/* send the request */
total = strlen(message);
sent = 0;
do {
bytes = write(sockfd,message+sent,total-sent);
if (bytes < 0)
error("ERROR writing message to socket");
if (bytes == 0)
break;
sent+=bytes;
} while (sent < total);
/* receive the response */
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");
/* close the socket */
close(sockfd);
/* process response */
printf("Response:\n%s\n",response);
return 0;
}
But I need to send a header and data, according to this post (in Python):
import requests
import json
channelID = "your_id_goes_here" # enable dev mode on discord, right-click on the channel, copy ID
botToken = "your_token_here" # get from the bot page. must be a bot, not a discord app
baseURL = "https://discordapp.com/api/channels/{}/messages".format(channelID)
headers = { "Authorization":"Bot {}".format(botToken),
"User-Agent":"myBotThing (http://some.url, v0.1)",
"Content-Type":"application/json", }
message = "hello world"
POSTedJSON = json.dumps ( {"content":message} )
r = requests.post(baseURL, headers = headers, data = POSTedJSON)
I'm sorry, I don't know the protocols in detail.
I'd like to read messages too, but for now I'm OK just writing they.
UPDATE:
My new code (error 400, bad request).
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl = NULL;
CURLcode res;
const char *data = "{\"content\": \"data to send\"}";
const char *ID = "...";
const char *token = "...";
char tmp[1024];
curl = curl_easy_init();
if(curl != NULL) {
struct curl_slist *headers = NULL;
/* Remove a header curl would otherwise add by itself */
headers = curl_slist_append(headers, "Accept:");
/* Add a custom header */
sprintf(tmp, "Host: https://discordapp.com/api/channels/%s/messages", ID);
headers = curl_slist_append(headers, tmp);
sprintf(tmp, "Authorization: Bot %s", token);
headers = curl_slist_append(headers, tmp);
headers = curl_slist_append(headers, "User-Agent: myBotThing (http://some.url, v0.1)");
headers = curl_slist_append(headers, "Content-Type: application/json");
/* set our custom set of headers */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
sprintf(tmp, "https://discordapp.com/api/channels/%s/messages", ID);
curl_easy_setopt(curl, CURLOPT_URL, tmp);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// POST
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK) printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}
return 0;
}
I wrote a simple TCP client and server program in C language.
It works fine among them but I have a doubt.
What if I wanted to access the TCP server from the web server?
I got the headers from web server and I can't write() back to the web browser. Should the response be in HTTP specifications compulsorily?
I get the following error:
Server Code:
// Server side C program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket; long valread;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("In socket");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("In bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("In listen");
exit(EXIT_FAILURE);
}
while(1)
{
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("In accept");
exit(EXIT_FAILURE);
}
valread = read( new_socket , buffer, 1024);
printf("%s\n",buffer );
write(new_socket , hello , strlen(hello));
printf("Hello message sent\n");
}
return 0;
}
Output:
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Hello message sent
What is the problem? Is browser also expecting HTTP type response from the server? As the server is sending plain text, web browser can't display the contents. Is this the reason for the error displayed in web browser?
What is the problem? Is browser also expecting HTTP type response from the server? As the server is sending plain text, web browser can't display the contents. Is this the reason for the error displayed in web browser?
Yes, the browser expects a HTTP response.
Here a simple HTTP response:
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Hello world!
C Code snippet:
const char *hello = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nHello world!";
Parts explained:
HTTP/1.1 specifies the HTTP protocol version.
200 OK is the so called response status. 200 means no error.
List of HTTP status codes (wikipedia)
Content-Type and Content-Length are http headers:
Content-Type refers to the content type (who would've guessed?). text/plain means plaintext. (There is also text/html, image/png etc..)
Content-Length total size of the response in bytes.
Now, after doing the changes in code I am able to send the POST resquest to SERVER and even server is sending the response. But now my program hangs at curl_easy_perform function. Do you have any idea?
curl -H "Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0" -X POST "http://x.x.x.x:8080/authservice/token?grant_type=client_credential"
My program:
struct url_data {
size_t size;
char* data;
};
static size_t write_data(char *buffer, size_t size, size_t nitems, void *userp)
{
struct url_data *data = (struct url_data *)userp;
size_t index = data->size;
size_t n = (size * nitems);
data->size += (size * nitems);
char* tmp = realloc(data->data, data->size + 1);
if(tmp) {
data->data = tmp;
} else {
if(data->data) free(data->data);
fprintf(stderr, "Failed to allocate memory.\n");
return EXIT_FAILURE;
}
memcpy(data->data + index, buffer, n);
data->data[data->size] = '\0';
return size * nitems;
}
int main(void)
{
int i = 0;
long http_code = 0;
CURL *curl;
CURLcode res;
struct curl_slist *slist=NULL;
struct url_data data;
data.size = 0;
data.data = (char*) malloc(4096); /* reasonable size initial buffer */
bzero(data.data, 4096);
//curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://x.x.x.x:8080/authservice/token?grant_type=client_credential");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
slist = curl_slist_append(slist, "Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Content-Type:application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Content-Length: 0");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
slist = curl_slist_append(slist, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
fprintf(stderr, "Data:[%s] Ret:[%s]\n", data.data, curl_easy_strerror(res));
}
res = curl_easy_getinfo (curl, CURLINFO_HTTP_CODE, &http_code);
printf("http_code:%ld\n", http_code);
/* always cleanup */
curl_easy_cleanup(curl);
if(data.data) free(data.data);
curl_slist_free_all(slist);
}
//curl_global_cleanup();
return 0;
}
Output:
* About to connect() to x.x.x.x port 8080 (#0)
* Trying x.x.x.x...
* connected
* Connected to x.x.x.x (x.x.x.x) port 8080 (#0)
> POST /authservice/token?grant_type=client_credential HTTP/1.1
User-Agent: libcurl-agent/1.0
Host: x.x.x.x:8080
Accept: */*
Authorization: Basic dGVzdENsaWVudDp0ZXN0U2VjcmV0
Content-Type:application/json
Content-Length: 0
I'm trying to make a connection localhost on port 80 and send a simple http get request and simultaneously I run wireshark and look at the headers. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
int yes = 1;
char buffer[1024];
int newsockfd, portno, recv_length, sockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
ssize_t number;
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = 0;
serv_addr.sin_port = htons(80);
connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
if(send(sockfd,
"GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n",
strlen("GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n"),
0) > 0)
{
printf("GET send from %d\n", sockfd);
}
else
{
printf("Problem in send %s\n", strerror(errno));
}
But when I compile it and run it gives me a lot of erros. here is the image of errros. After this error I changed the send function to this send(sockfd, "GET / HTTP/1.1\r\n Host: localhost\r\n\r\n", strlen("GET / HTTP/1.1\r\n Host: localhost\r\n\r\n") Compilation went ok but the wireshark shows me HTTP/1.0 400 BAD REQUEST (text/html) So I have few questions.
1)What is the difference between send functions that I've used? I mean does it really matter if I send GET / HTTP/1.1\r\n Host: localhost\r\n\r\n or GET / HTTP/1.1\r\n
Host: localhost\r\n
Connection: Keep-alive\r\n
Cache-Control: max-age=0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,;q=0.8\r\n
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: en-US,en;q=0.8\r\n\r\n
2)How to configure send function to make correct HTTP GET request?
Hope you can help. Thanks.
You have literal newlines inside your string! You need to close and re-open the quotes on each line. For example:
if(send(sockfd,
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: Keep-alive\r\n"
"Cache-Control: max-age=0\r\n"
...
I have set the cookie into HTTP header in this way.
.....
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "charsets: utf-8");
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
curl_easy_setopt(curl, CURLOPT_URL,"http://localhost:9763/addApp.jag");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,reqbody);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, body_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA,&cookiec);
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
res=curl_easy_perform(curl);
......
In server side when I retrieved post data they seem to be null. But when I check from Wireshark actually those post data are sent. But when I remove
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
I can access the post data in the server side. If I make any mistake in my post request please correct me.
Actually it little bit complicated to find answer for this. Because when I set the cookie it should be excluded \r\n characters in cookie value which is coming from server side. If somebody want to do this here is the sample code
struct response_data *makeCURLRequest(char* reqbody,char* cookie,int memorySize,char* url){
CURL *curl;
struct url_data data;
data.size = 0;
data.data = malloc(memorySize);
if(NULL == data.data) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct site_cookie cookiec;
cookiec.size=0;
cookiec.cookie=malloc(256);
if(NULL == cookiec.cookie) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct response_data* res_data;
res_data=malloc(sizeof(struct response_data));
res_data->res_body=malloc(1000);
res_data->res_cookie=malloc(256);
if(NULL == res_data->res_body || NULL==res_data->res_cookie) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Subscription/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Content-Type: Subscription/x-www-form-urlencoded");
headers = curl_slist_append(headers, "charsets: utf-8");
data.data[0] = '\0';
cookiec.cookie[0]= '\0';
res_data->res_body[0]='\0';
res_data->res_cookie[0]='\0';
buf_t *buf = buf_size(NULL, BUFFER_SIZE);
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL,url);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,reqbody);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA,&cookiec);
curl_easy_setopt(curl, CURLOPT_COOKIE,cookie);
res=curl_easy_perform(curl);
if(res != CURLE_OK){
fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
return NULL;
}
curl_easy_cleanup(curl);
char *jsonstr = buf_tostr(buf);
free(buf->data);
free(buf);
strcpy(res_data->res_body,jsonstr);
strcpy(res_data->res_cookie,cookiec.cookie);
return res_data;
}
full source code can be found here https://github.com/GPrathap/REST_API_in_C/blob/master/libs/curlreq.c