<commit_before>/* http.c  -  HTTP library  -  Public Domain  -  2013 <NAME> / Rampant Pixels
 * 
 * This library provides a HTTP communication library built on our foundation and
 * network libraries. The latest source code is always available at
 * 
 * https://github.com/rampantpixels/http_lib
 * 
 * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
 * 
 */

#include <http/http.h>

#include <network/network.h>
#include <foundation/foundation.h>


int http_initialize( void )
{
	return network_initialize( 0 );
}


void http_shutdown( void )
{
}


static object_t _http_open( const char* url, const char* headers, const char* cmd, unsigned int timeout )
{
	const char* cleanpath = url;	
	unsigned int port = 80;
	char* address_str = 0;
	char* host = 0;
	char* portstr = 0;
	char* name = 0;
	char* request = 0;
	network_address_t** addresses = 0;
	object_t sock = 0;
	bool connected = false;
	int iaddr, asize;
	stream_t* stream = 0;

	if( ( string_length( cleanpath ) > 7 ) && ( string_equal_substr( cleanpath, "http://", 7 ) ) )
		cleanpath = url + 7;
	
	string_split( cleanpath, "/", &address_str, &name, false );

	//TODO: Handle IPv6 numeric addresses with port, [xx:xx:..:xx]:80
	string_split( address_str ? address_str : "", ":", &host, &portstr, false );
	if( portstr && string_length( portstr ) )
		port = string_to_uint( portstr, false );
	if( !port )
		port = 80;

	addresses = network_address_resolve( address_str );
	if( !addresses )
	{
		log_warnf( HASH_NETWORK, WARNING_BAD_DATA, "HTTP %s request failed, unable to resolve host: %s", cmd, host );
		goto exit;
	}

	if( !host )
		request = string_format( "%s /%s HTTP/1.1\n", cmd, name );
	else
		request = string_format( "%s /%s HTTP/1.1\nHost: %s\n", cmd, name, host );
	if( headers && string_length( headers ) )
	{
		request = string_append( request, headers );
		if( headers[ string_length( headers ) - 1 ] != '\n' )
			request = string_append( request, "\n" );
	}
	request = string_append( request, "\n" );

	//Send HTTP request
	sock = tcp_socket_create();
	socket_set_blocking( sock, true );
	
	for( iaddr = 0, asize = array_size( addresses ); iaddr < asize; ++iaddr )
	{
		network_address_t* address = addresses[iaddr];
		
		if( !network_address_ip_port( address ) )
			network_address_ip_set_port( address, port );
		
		if( socket_connect( sock, address, timeout ) )	
		{
			connected = true;
			break;
		}
	}
	
	if( !connected )
	{
		log_warnf( HASH_NETWORK, WARNING_BAD_DATA, "HTTP %s request failed, unable to connect to host: %s", cmd, host );
		socket_free( sock );
		sock = 0;
		goto exit;
	}

	log_debugf( HASH_NETWORK, "Sending HTTP %s request to host %s: %s /%s HTTP/1.1", cmd, host, cmd, name );<commit_msg>set log context to http<commit_after>/* http.c  -  HTTP library  -  Public Domain  -  2013 <NAME> / Rampant Pixels
 * 
 * This library provides a HTTP communication library built on our foundation and
 * network libraries. The latest source code is always available at
 * 
 * https://github.com/rampantpixels/http_lib
 * 
 * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
 * 
 */

#include <http/http.h>

#include <network/network.h>
#include <foundation/foundation.h>


int http_initialize( void )
{
	return network_initialize( 0 );
}


void http_shutdown( void )
{
}


static object_t _http_open( const char* url, const char* headers, const char* cmd, unsigned int timeout )
{
	const char* cleanpath = url;	
	unsigned int port = 80;
	char* address_str = 0;
	char* host = 0;
	char* portstr = 0;
	char* name = 0;
	char* request = 0;
	network_address_t** addresses = 0;
	object_t sock = 0;
	bool connected = false;
	int iaddr, asize;
	stream_t* stream = 0;

	if( ( string_length( cleanpath ) > 7 ) && ( string_equal_substr( cleanpath, "http://", 7 ) ) )
		cleanpath = url + 7;
	
	string_split( cleanpath, "/", &address_str, &name, false );

	//TODO: Handle IPv6 numeric addresses with port, [xx:xx:..:xx]:80
	string_split( address_str ? address_str : "", ":", &host, &portstr, false );
	if( portstr && string_length( portstr ) )
		port = string_to_uint( portstr, false );
	if( !port )
		port = 80;

	addresses = network_address_resolve( address_str );
	if( !addresses )
	{
		log_warnf( HASH_HTTP, WARNING_BAD_DATA, "HTTP %s request failed, unable to resolve host: %s", cmd, host );
		goto exit;
	}

	if( !host )
		request = string_format( "%s /%s HTTP/1.1\n", cmd, name );
	else
		request = string_format( "%s /%s HTTP/1.1\nHost: %s\n", cmd, name, host );
	if( headers && string_length( headers ) )
	{
		request = string_append( request, headers );
		if( headers[ string_length( headers ) - 1 ] != '\n' )
			request = string_append( request, "\n" );
	}
	request = string_append( request, "\n" );

	//Send HTTP request
	sock = tcp_socket_create();
	socket_set_blocking( sock, true );
	
	for( iaddr = 0, asize = array_size( addresses ); iaddr < asize; ++iaddr )
	{
		network_address_t* address = addresses[iaddr];
		
		if( !network_address_ip_port( address ) )
			network_address_ip_set_port( address, port );
		
		if( socket_connect( sock, address, timeout ) )	
		{
			connected = true;
			break;
		}
	}
	
	if( !connected )
	{
		log_warnf( HASH_HTTP, WARNING_BAD_DATA, "HTTP %s request failed, unable to connect to host: %s", cmd, host );
		socket_free( sock );
		sock = 0;
		goto exit;
	}

	log_debugf( HASH_HTTP, "Sending HTTP %s request to host %s: %s /%s HTTP/1.1", cmd, host, cmd, name );
{'fraction_non_alphanumeric': 0.1340599455040872, 'fraction_numerical': 0.011625794732061762, 'mean_word_length': 3.685957446808511, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4347152', 'n_tokens_mistral': 2074, 'n_tokens_neox': 1917, 'n_words': 596}