abhiarora abhiarora - 2 months ago 27
C Question

Bad Request for www.httpbin.org?

I am using

openSSL
library to create a SSL session with
www.httpbin.org
. I am able to create it successfully at port number 443 of the server. I have used
ping www.httpbin.org
command in
ubuntu
to get
ip address
of
httpbin
so that i can use it with my program. I have pasted my program below. I am getting
400 Bad Request
from the server.

Can someone explain me why i am getting this error?.
char msg[]
holds HTTP initial line and headers. May be problem lies with my
http headers
but i am not able to solve the issue.

#include <iostream>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>



#define DEFAULT_PORT_NUMBER 443

int create_socket(char *, uint16_t port_num);

int openSSL_client_init()
{
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();

if (SSL_library_init() < 0)
return -1;
return 0;
}

int openSSL_create_client_ctx(SSL_CTX **ctx)
{
const SSL_METHOD *method = SSLv23_client_method();

if ((*ctx = SSL_CTX_new(method)) == NULL)
return -1;


//SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2);

return 0;
}


int main(int argc, char *argv[])
{
BIO *outbio = NULL;

X509 *cert;
X509_NAME *certname = NULL;

SSL_CTX *ctx;
SSL *ssl;
int server = 0;
int ret, i;

if (openSSL_client_init()) {
std :: cerr << "Could not initialize the OpenSSL library !" << std :: endl;
return -1;
}

outbio = BIO_new_fp(stdout, BIO_NOCLOSE);

if (openSSL_create_client_ctx(&ctx)) {
std :: cerr << "Unable to create a new SSL context structure." << std :: endl;
return -1;
}

ssl = SSL_new(ctx);
server = create_socket(argv[1], atoi(argv[2]));

if (server < 0) {
std :: cerr << "Error: Can't create TCP session" << std :: endl;
return -1;
}
std :: cout << "Successfully made the TCP connection to: " << argv[1] << " port: " << atoi(argv[2]) << std :: endl;

SSL_set_fd(ssl, server);

if (SSL_connect(ssl) != 1) {
std :: cerr << "Error: Could not build a SSL session to: " << argv[1] << std :: endl;
return -1;
}

std :: cout << "Successfully enabled SSL/TLS session to: " << argv[1] << std :: endl;
//SSL_SESSION *ss = SSL_get_session(ssl);

cert = SSL_get_peer_certificate(ssl);
if (cert == NULL) {
std :: cerr << "Error: Could not get a certificate from: " << argv[1] << std :: endl;
return -1;
}

certname = X509_NAME_new();
certname = X509_get_subject_name(cert);

std :: cout << "Displaying the certificate subject data:" << std :: endl;
X509_NAME_print_ex(outbio, certname, 0, 0);
std :: cout << std :: endl;


char msg[1024] = "GET https://www.httpbin.org/ HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip\r\nUser-Agent: runscope/0.1\r\n\r\n";
SSL_write(ssl, msg, strlen(msg));
SSL_read(ssl, msg, 1024);
std :: cout << "Message is " << msg << std :: endl;


SSL_free(ssl);
close(server);
X509_free(cert);
SSL_CTX_free(ctx);
std :: cout << "Finished SSL/TLS connection with server" << std :: endl;
return 0;
}


int create_socket(char *ip_cstr, uint16_t port_num)
{
int fd;
struct sockaddr_in dest_addr;

fd = socket(AF_INET, SOCK_STREAM, 0);

dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port_num);
dest_addr.sin_addr.s_addr = inet_addr(ip_cstr);

memset(&(dest_addr.sin_zero), '\0', 8);

if (connect(fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1)
return -1;

return fd;
}


To compile above program, you can use
gcc -lssl -lcrypto FILE_NAME.C
. I am using
gcc
on
Ubuntu
. To install openSSL development package, you can use
sudo apt-get install libssl-dev
on
Ubuntu
. To execute the compiled program, use
./a.out IP_ADDERSS PORT_NUMBER
.

The output i am getting from my program is:


Successfully made the TCP connection to: 23.22.14.18 port: 443
Successfully enabled SSL/TLS session to: 23.22.14.18
Displaying the certificate subject data:
=Domain Control Validated, OU=EssentialSSL Wildcard, CN=*.httpbin.org
Message is


HTTP/1.1 400 Bad Request
Server: nginx
Date: Thu, 29 Sep 2016 11:10:59 GMT
Content-Type: text/html
Content-Length: 166
Connection: close

<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx</center>
</body>
</html>



Finished SSL/TLS connection with server

Answer
GET https://www.httpbin.org/ HTTP/1.1
Accept: */*
Accept-Encoding: gzip
User-Agent: runscope/0.1

I am not aware that providing protocol and domain in the GET line is valid (though don't quote me on that). Certainly, the Host line is mandatory with HTTP 1.1, but you didn't provide one.

Did you mean:

GET / HTTP/1.1
Host: www.httpbin.org
Accept: */*
Accept-Encoding: gzip
User-Agent: runscope/0.1

I recommend reading about HTTP requests before attempting to implement one.

Comments