<commit_before>#include "winpch.h"
#include "winhttp.h"
#include "..\exceptions\fileExceptions.h"
#include "..\text\textParser.tcc"
#include "..\text\textFormat.tcc"
#include "../containers/autoArray.tcc"
#include "../interface.tcc"
#include "../exceptions/httpStatusException.h"

namespace LightSpeed {

template IHTTPStream &IInterface::getIfc<IHTTPStream>(void);
template const IHTTPStream &IInterface::getIfc<IHTTPStream>(void) const;
template Pointer<IHTTPStream>IInterface::getIfcPtr<IHTTPStream>(void);
template Pointer<const IHTTPStream>IInterface::getIfcPtr<IHTTPStream>(void) const;

#pragma comment (lib, "Wininet.lib")




WinHttpStream::WinHttpStream( String url, const HTTPSettings &settings )
:WinHTTPSettings(this->settings),hInternet(0),hConnect(0),hHTTPConn(0),exceptionDisabled(false),redirDisabled(false)
,url(url),settings(settings),method("GET")
,curState(stIdle),tmaction(0)
{
}

WinHttpStream::~WinHttpStream()
{
	if (!postBuffer.empty() && !std::uncaught_exception()) setState(stReadResponse);
	timeoutThr.stop();
	if (hHTTPConn) InternetCloseHandle(hHTTPConn);
	if (hConnect) InternetCloseHandle(hConnect);
	if (hInternet) InternetCloseHandle(hInternet);
}


IHTTPStream & WinHttpStream::setMethod( ConstStrA method )
{
	this->method = method;
	return *this;
}

IHTTPStream & WinHttpStream::setHeader( ConstStrA headerName, ConstStrA headerValue )
{
	hdrmap.replace(headerName,headerValue);
	return *this;
}



IHTTPStream & WinHttpStream::cancel()
{
	if (hHTTPConn) {
		InternetCloseHandle(hHTTPConn);
		hHTTPConn = 0;
	}
	return *this;
}

StringA WinHttpStream::getReplyHeaders()
{
	setState(stReadResponse);
	AutoArray<char> buffer;
	buffer.resize(1000);
	DWORD size = (DWORD)buffer.length();
	while (!HttpQueryInfoA(hHTTPConn,HTTP_QUERY_RAW_HEADERS_CRLF,
		buffer.data(),&size,0)) {
			DWORD res = GetLastError();
			if (res == ERROR_INSUFFICIENT_BUFFER) {
				buffer.resize(size);
			} else {
				throw ErrNoWithDescException(THISLOCATION,GetLastError(),
					"Cannot retrieve headers from the request");
			}
	}
	buffer.resize(size);
	return buffer;
}


IHTTPStream & WinHttpStream::disableRedirect()
{
	redirDisabled = true;
	return *this;
}

IHTTPStream & WinHttpStream::disableException()
{
	exceptionDisabled= true;
	return *this;

}

IHTTPStream & WinHttpStream::connect()
{
	if (method == ConstStrA("GET") || method == ConstStrA("HEAD"))
		setState(stReadResponse);
	else
		setState(stWriteRequest);
	return *this;
}

LightSpeed::natural WinHttpStream::getStatusCode()
{
	setState(stReadResponse);
	DWORD statusCode = 0;
	DWORD buffSz = sizeof(statusCode);
	DWORD index = 0;
	if (HttpQueryInfo(hHTTPConn,HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
		&statusCode,&buffSz,&index) == FALSE)
		throw FileMsgException(THISLOCATION,GetLastError(),
		url,
		"Unable to retrieve status code. HttpQueryInfo has failed");
	else 
		return statusCode;
}

void WinHttpStream::setState( State newState )
{
	while (newState > curState) {
		if (curState == stIdle) {
			initRequest();
			curState = stWriteRequest;
		} else if (curState == stWriteRequest) {
			sendRequest();
			curState = stReadResponse;
		} else {
			break;
		}
	}
}

natural WinHttpStream::read( void *buffer, natural size )
{
	setState(stReadResponse);
	if (!peekBuffer.empty()) {
		natural r = peekBuffer.length();
		if (r <= size) {
			memcpy(buffer,peekBuffer.data(),r);
			peekBuffer.clear();
			return r;
		} else {
			memcpy(buffer,peekBuffer.data(),size);
			peekBuffer.erase(0,size);
			return size;

		}
	} else {
		return readInternal(buffer, size);
	}
}

LightSpeed::natural WinHttpStream::peek( void *buffer, natural size ) const
{
	const_cast<WinHttpStream *>(this)->setState(stReadResponse);
	if (size <= peekBuffer.length()) {
		memcpy(buffer,peekBuffer.data(),size);
		return size;
	}
	natural rm = size - peekBuffer.length();
	AutoArray<byte, StaticAlloc<256> > peekBuffer2;
	peekBuffer2.resize(rm);
	natural r = const_cast<WinHttpStream *>(this)->readInternal(peekBuffer2.data(),peekBuffer2.length());
	peekBuffer2.resize(r);
	peekBuffer.append(peekBuffer2);
	return peek(buffer,r);
}

LightSpeed::natural WinHttpStream::readInternal( void * buffer, natural size ) 
{
	DWORD rd;
	BOOL res = InternetReadFile(hHTTPConn,buffer,(DWORD)size,&rd);
	DWORD err = GetLastError();
	if (res == FALSE) {
		throw FileMsgException(THISLOCATION,err,url,"Read failed");
	}
	return rd;
}

LightSpeed::natural WinHttpStream::write( const void *buffer, natural size )
{
	postBuffer.append(ArrayRef<const byte>(reinterpret_cast<const byte *>(buffer),size));
	if (method == ConstStrA("GET")) method == ConstStrA("POST");
/*



	if (curState == stIdle) {
		setState(stWriteRequest);
	}<commit_msg>POST method was not properly set<commit_after>#include "winpch.h"
#include "winhttp.h"
#include "..\exceptions\fileExceptions.h"
#include "..\text\textParser.tcc"
#include "..\text\textFormat.tcc"
#include "../containers/autoArray.tcc"
#include "../interface.tcc"
#include "../exceptions/httpStatusException.h"

namespace LightSpeed {

template IHTTPStream &IInterface::getIfc<IHTTPStream>(void);
template const IHTTPStream &IInterface::getIfc<IHTTPStream>(void) const;
template Pointer<IHTTPStream>IInterface::getIfcPtr<IHTTPStream>(void);
template Pointer<const IHTTPStream>IInterface::getIfcPtr<IHTTPStream>(void) const;

#pragma comment (lib, "Wininet.lib")




WinHttpStream::WinHttpStream( String url, const HTTPSettings &settings )
:WinHTTPSettings(this->settings),hInternet(0),hConnect(0),hHTTPConn(0),exceptionDisabled(false),redirDisabled(false)
,url(url),settings(settings),method("GET")
,curState(stIdle),tmaction(0)
{
}

WinHttpStream::~WinHttpStream()
{
	if (!postBuffer.empty() && !std::uncaught_exception()) setState(stReadResponse);
	timeoutThr.stop();
	if (hHTTPConn) InternetCloseHandle(hHTTPConn);
	if (hConnect) InternetCloseHandle(hConnect);
	if (hInternet) InternetCloseHandle(hInternet);
}


IHTTPStream & WinHttpStream::setMethod( ConstStrA method )
{
	this->method = method;
	return *this;
}

IHTTPStream & WinHttpStream::setHeader( ConstStrA headerName, ConstStrA headerValue )
{
	hdrmap.replace(headerName,headerValue);
	return *this;
}



IHTTPStream & WinHttpStream::cancel()
{
	if (hHTTPConn) {
		InternetCloseHandle(hHTTPConn);
		hHTTPConn = 0;
	}
	return *this;
}

StringA WinHttpStream::getReplyHeaders()
{
	setState(stReadResponse);
	AutoArray<char> buffer;
	buffer.resize(1000);
	DWORD size = (DWORD)buffer.length();
	while (!HttpQueryInfoA(hHTTPConn,HTTP_QUERY_RAW_HEADERS_CRLF,
		buffer.data(),&size,0)) {
			DWORD res = GetLastError();
			if (res == ERROR_INSUFFICIENT_BUFFER) {
				buffer.resize(size);
			} else {
				throw ErrNoWithDescException(THISLOCATION,GetLastError(),
					"Cannot retrieve headers from the request");
			}
	}
	buffer.resize(size);
	return buffer;
}


IHTTPStream & WinHttpStream::disableRedirect()
{
	redirDisabled = true;
	return *this;
}

IHTTPStream & WinHttpStream::disableException()
{
	exceptionDisabled= true;
	return *this;

}

IHTTPStream & WinHttpStream::connect()
{
	if (method == ConstStrA("GET") || method == ConstStrA("HEAD"))
		setState(stReadResponse);
	else
		setState(stWriteRequest);
	return *this;
}

LightSpeed::natural WinHttpStream::getStatusCode()
{
	setState(stReadResponse);
	DWORD statusCode = 0;
	DWORD buffSz = sizeof(statusCode);
	DWORD index = 0;
	if (HttpQueryInfo(hHTTPConn,HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
		&statusCode,&buffSz,&index) == FALSE)
		throw FileMsgException(THISLOCATION,GetLastError(),
		url,
		"Unable to retrieve status code. HttpQueryInfo has failed");
	else 
		return statusCode;
}

void WinHttpStream::setState( State newState )
{
	while (newState > curState) {
		if (curState == stIdle) {
			initRequest();
			curState = stWriteRequest;
		} else if (curState == stWriteRequest) {
			sendRequest();
			curState = stReadResponse;
		} else {
			break;
		}
	}
}

natural WinHttpStream::read( void *buffer, natural size )
{
	setState(stReadResponse);
	if (!peekBuffer.empty()) {
		natural r = peekBuffer.length();
		if (r <= size) {
			memcpy(buffer,peekBuffer.data(),r);
			peekBuffer.clear();
			return r;
		} else {
			memcpy(buffer,peekBuffer.data(),size);
			peekBuffer.erase(0,size);
			return size;

		}
	} else {
		return readInternal(buffer, size);
	}
}

LightSpeed::natural WinHttpStream::peek( void *buffer, natural size ) const
{
	const_cast<WinHttpStream *>(this)->setState(stReadResponse);
	if (size <= peekBuffer.length()) {
		memcpy(buffer,peekBuffer.data(),size);
		return size;
	}
	natural rm = size - peekBuffer.length();
	AutoArray<byte, StaticAlloc<256> > peekBuffer2;
	peekBuffer2.resize(rm);
	natural r = const_cast<WinHttpStream *>(this)->readInternal(peekBuffer2.data(),peekBuffer2.length());
	peekBuffer2.resize(r);
	peekBuffer.append(peekBuffer2);
	return peek(buffer,r);
}

LightSpeed::natural WinHttpStream::readInternal( void * buffer, natural size ) 
{
	DWORD rd;
	BOOL res = InternetReadFile(hHTTPConn,buffer,(DWORD)size,&rd);
	DWORD err = GetLastError();
	if (res == FALSE) {
		throw FileMsgException(THISLOCATION,err,url,"Read failed");
	}
	return rd;
}

LightSpeed::natural WinHttpStream::write( const void *buffer, natural size )
{
	postBuffer.append(ArrayRef<const byte>(reinterpret_cast<const byte *>(buffer),size));
	if (method == ConstStrA("GET")) method = ConstStrA("POST");
/*



	if (curState == stIdle) {
		setState(stWriteRequest);
	}
{'fraction_non_alphanumeric': 0.14311555650138327, 'fraction_numerical': 0.004681847201532241, 'mean_word_length': 6.109682299546142, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 39, 'https://': 0, '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': '3002806', 'n_tokens_mistral': 3386, 'n_tokens_neox': 3200, 'n_words': 595}