Skip to main content
GameDev.net gamedev.net
🔒 Locked

[web] C++ HTTP Requests

Started by Rob Loach Mar 10, 2005 at 7:08 AM 20 replies 38.2k views
Original Post
Rob Loach
Rob Loach
I saw a thread on it about a week or two ago but sadly the search and my attempt at a manual search resulted in a miserable failure. Does anyone know how to make HTTP requests from C++ (not .NET)? I'm looking to setup a PHP script that will take a highscore along with some type of key to validate it. The application will then call the script and upload the highscores. Or if there is any other solution available, that would be great. Maybe even running remote MySQL queries directly from the application....
Rob Loach [Website] [Projects] [
DrEvil
DrEvil
I use libcurl http://curl.haxx.se/ to perform http queries. It's easy to set up a multiplayer game to request a php script that returns a list of servers for example, and easy to run the php script with variables in the url to interact more with the database.
markr
markr
Quote:
Original post by Rob Loach
Or if there is any other solution available, that would be great. Maybe even running remote MySQL queries directly from the application....


No that would be less than ideal.

This is because the user would be able to detect the MySQL login / password and put in their own data, which would be bad.

Using a PHP (or even a CGI program written in C++, maybe, so it can reuse code from the app itself) script to update high scores, list servers etc, is definitely the way to go.

It's much easier to code this sort of high-score updater or server-list manager in PHP than it would be in C++ (well, if you know PHP anyway).

A server-list manager would need to be able to query servers though to check that they were online

Mark
Rob Loach
Rob Loach
No other alternatives? I have yet to try either out completely, but will get to it sometime.... Anyone have any other suggestions?
Rob Loach [Website] [Projects] [
Drew_Benton
Drew_Benton
Is this it? If not (ehh it's more than a few weeks old lol), I htink you will need to use WinSock to do this in C++. Here is another thing to look at.
RichardS
RichardS
I suggest going the libcurl route. I've attached a really simple HTTP GET class. It should be easily modifiable to support HTTP POST or SSL, if that's what you need:

I decided to go the stateful route (only allowing the object to handle one download at a time) for 2 reasons: It allowed easy re-use of the CURL handle (which allows for pipelined transactions), and it allowed me to re-use buffers (so the user doesn't have to allocate their own entire buffer ahead of time, they just have to get a pointer). This has the downside of keeping a buffer around that's as large as the largest file you ever downloaded, but for my application, that doesn't matter. In my usage, almost all downloads will be about the same size, pipelineing is important, and the downloads will only be about ~1meg.

If all you're doing is reporting scores, then the buffer size should stay small, and it won't matter.

Obviously, the content/contentLength/contentType will be overwritten on each call to downloadFile().

HTTPDownloader.h:
#include <string>#include <curl/curl.h>#ifndef HTTP_DOWNLOADER_GUARD#define HTTP_DOWNLOADER_GUARDclass HTTPDownloader {public:	HTTPDownloader();	~HTTPDownloader();	bool downloadFile(const std::string url);	std::string contentType() const;	unsigned int contentLength() const;	char* content() const;private:	static size_t httpFetch(void* ptr, size_t size, size_t nmemb, void* stream);	CURL* curlHandle;	char* data;	unsigned int length;	unsigned int allocatedLength;	std::string type;};#endif /* HTTP_DOWNLOADER_GUARD */


HTTPDownloader.cpp
#include "HTTPDownloader.h"#include <iostream>#include <cassert>using namespace std;const int kInitialBufferSize = 1024*1024;HTTPDownloader::HTTPDownloader():curlHandle(curl_easy_init()), data(NULL), length(0), allocatedLength(0){}HTTPDownloader::~HTTPDownloader() {	curl_easy_cleanup(curlHandle);	if (data) {		free(data);		data = NULL;		allocatedLength = 0;		length = 0;	}}bool HTTPDownloader::downloadFile(const std::string url) {	length = 0;	//  set up transfer	CURLcode curlErr = curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str());	if (curlErr != CURLE_OK) {		cerr << "got curl error on setopt url " << curlErr << endl;		return false;	}	curlErr = curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, httpFetch);	if (curlErr != CURLE_OK) {		cerr << "got curl error on setopt func " << curlErr << endl;		return false;	}	curlErr = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, this);	if (curlErr != CURLE_OK) {		cerr << "got curl error on setopt url " << curlErr << endl;		return false;	}	//  perform transfer	curlErr = curl_easy_perform(curlHandle);	if (curlErr != CURLE_OK) {		cerr << "got curl error on perform " << curlErr << endl;		return false;	}	char* contentType = NULL;	curlErr = curl_easy_getinfo(curlHandle, CURLINFO_CONTENT_TYPE, &contentType);	if (curlErr != CURLE_OK) {		cerr << "got curl error on getopt for CONTENT_TYPE " << curlErr << endl;		return false;	}	type = string(contentType);	return true;}std::string HTTPDownloader::contentType() const {	return type;}unsigned int HTTPDownloader::contentLength() const {	return length;}char* HTTPDownloader::content() const {	return data;}size_t HTTPDownloader::httpFetch(void* ptr, size_t size, size_t nmemb, void* stream) {	HTTPDownloader* handle = (HTTPDownloader*)stream;	size_t newDataSize = size*nmemb;	if (handle->data == NULL) {		assert(handle->allocatedLength == 0);		handle->data = (char*)malloc(kInitialBufferSize);		handle->allocatedLength = kInitialBufferSize;		handle->length = 0;	}	while (handle->length+newDataSize+1 > handle->allocatedLength) {		assert(handle->allocatedLength > 0);		handle->data = (char*)realloc(handle->data, handle->allocatedLength*2);		handle->allocatedLength *= 2;	}	memcpy(handle->data + handle->length, ptr, newDataSize);	handle->length += newDataSize;	return newDataSize;}
Hedos
Hedos
Why not simply use sockets and send out the HTTP requests directly by yourself? As long as you don't anything too fancy, it won't be really hard. And there is a lot of resource available on the HTTP protocol on internet.
Rob Loach
Rob Loach
Just found a libcURL Wrapper courtasy of Mayukh. I haven't tried it out yet, but it looks pretty good.

Sorry for the necro, I just thought this needed mentioning.
Rob Loach [Website] [Projects] [
MatttK
MatttK
Hi,

I thought this might be a good thread to ask for help in...

I've been trying to get libcurl to work with the curlpp wrapper. I have managed to compile libcurl into a .lib/.dll but cannot do the same with curlpp. Well... I have compiled a dll but my project does not accept it.

I have instead #included the required files in my project but am still getting errors.

E.g.

Linking...
Creating library Debug/test_project.lib and object Debug/test_project.exp
urlReader.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall cURLpp::Easy::setOpt(class cURLpp::OptionBase const &)" (?setOpt@Easy@cURLpp@@UAEXABVOptionBase@2@@Z) referenced in function "private: int __thiscall urlReader::saveData(void)" (?saveData@urlReader@@AAEHXZ)
urlReader.obj : error LNK2019: unresolved external symbol "void __cdecl cURLpp::initialize(long)" (?initialize@cURLpp@@YAXJ@Z) referenced in function "private: int __thiscall urlReader::saveData(void)" (?saveData@urlReader@@AAEHXZ)
urlReader.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall cURLpp::OptionList::getOpt(class cURLpp::OptionBase *)" (?getOpt@OptionList@cURLpp@@UAEXPAVOptionBase@2@@Z)
urlReader.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall cURLpp::Easy::setOpt(class cURLpp::OptionBase *)" (?setOpt@Easy@cURLpp@@UAEXPAVOptionBase@2@@Z)
urlReader.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall cURLpp::Easy::setOpt(class cURLpp::OptionList const &)" (?setOpt@Easy@cURLpp@@UAEXABVOptionList@2@@Z)
urlReader.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall cURLpp::OptionList::~OptionList(void)" (??1OptionList@cURLpp@@UAE@XZ) referenced in function __unwindfunclet$??0Easy@cURLpp@@QAE@XZ$0
urlReader.obj : error LNK2019: unresolved external symbol "public: __thiscall cURLpp::CurlHandle::CurlHandle(void)" (??0CurlHandle@cURLpp@@QAE@XZ) referenced in function "public: __thiscall cURLpp::Easy::Easy(void)" (??0Easy@cURLpp@@QAE@XZ)
urlReader.obj : error LNK2019: unresolved external symbol "public: __thiscall cURLpp::OptionList::OptionList(void)" (??0OptionList@cURLpp@@QAE@XZ) referenced in function "public: __thiscall cURLpp::Easy::Easy(void)" (??0Easy@cURLpp@@QAE@XZ)
urlReader.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall cURLpp::CurlHandle::~CurlHandle(void)" (??1CurlHandle@cURLpp@@UAE@XZ) referenced in function "public: virtual __thiscall cURLpp::Easy::~Easy(void)" (??1Easy@cURLpp@@UAE@XZ)
urlReader.obj : error LNK2001: unresolved external symbol "public: virtual bool __thiscall cURLpp::OptionBase::operator<(class cURLpp::OptionBase const &)const " (??MOptionBase@cURLpp@@UBE_NABV01@@Z)
urlReader.obj : error LNK2019: unresolved external symbol "public: enum cURL::CURLoption __thiscall cURLpp::OptionBase::getOption(void)const " (?getOption@OptionBase@cURLpp@@QBE?AW4CURLoption@cURL@@XZ) referenced in function "public: virtual void __thiscall cURLpp::Option,class std::allocator > >::print(void)const " (?print@?$Option@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@cURLpp@@UBEXXZ)
urlReader.obj : error LNK2019: unresolved external symbol "public: __thiscall cURLpp::UnsetOption::UnsetOption(char const *)" (??0UnsetOption@cURLpp@@QAE@PBD@Z) referenced in function "public: virtual void __thiscall cURLpp::Option,class std::allocator > >::updateMeToOption(class cURLpp::OptionBase const &)" (?updateMeToOption@?$Option@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@cURLpp@@UAEXABVOptionBase@2@@Z)
urlReader.obj : error LNK2019: unresolved external symbol "public: __thiscall cURLpp::UnsetOption::UnsetOption(class std::basic_string,class std::allocator > const &)" (??0UnsetOption@cURLpp@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "private: virtual void __thiscall cURLpp::OptionTrait,class std::allocator >,10002>::updateHandleToMe(class cURLpp::CurlHandle *)const " (?updateHandleToMe@?$OptionTrait@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@$0CHBC@@cURLpp@@EBEXPAVCurlHandle@2@@Z)
urlReader.obj : error LNK2019: unresolved external symbol "public: __thiscall cURLpp::OptionBase::OptionBase(enum cURL::CURLoption)" (??0OptionBase@cURLpp@@QAE@W4CURLoption@cURL@@@Z) referenced in function "protected: __thiscall cURLpp::Option,class std::allocator > >::Option,class std::allocator > >(enum cURL::CURLoption,class std::basic_string,class std::allocator > const &)" (??0?$Option@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@cURLpp@@IAE@W4CURLoption@cURL@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
urlReader.obj : error LNK2019: unresolved external symbol "void __cdecl cURLpp::libcurlRuntimeAssert(char const *,enum cURL::CURLcode)" (?libcurlRuntimeAssert@cURLpp@@YAXPBDW4CURLcode@cURL@@@Z) referenced in function "public: void __thiscall cURLpp::CurlHandle::option(enum cURL::CURLoption,char const *)" (??$option@PBD@CurlHandle@cURLpp@@QAEXW4CURLoption@cURL@@PBD@Z)
Debug/test_project.dll : fatal error LNK1120: 15 unresolved externals

---

That's QUITE a mess.

All I'm doing is

cURLpp::initialize();
cURLpp::Easy curl_handle;
curl_handle.setOpt(cURLpp::Options::Url("http://www.example.com/"));

I haven't gone beyond there yet. I've clearly screwed something up with the linking because even with the first line, I get

Linking...
Creating library Debug/test_project.lib and object Debug/test_project.exp
urlReader.obj : error LNK2019: unresolved external symbol "void __cdecl cURLpp::initialize(long)" (?initialize@cURLpp@@YAXJ@Z) referenced in function "private: int __thiscall urlReader::saveData(void)" (?saveData@urlReader@@AAEHXZ)
Debug/test_project.dll : fatal error LNK1120: 1 unresolved externals

--

Can anybody shed some light? I'm a little new to C++.
dnaxx
dnaxx
Quote:
Original post by RichardS
I suggest going the libcurl route. I've attached a really simple HTTP GET class. It should be easily modifiable to support HTTP POST or SSL, if that's what you need:

I decided to go the stateful route (only allowing the object to handle one download at a time) for 2 reasons: It allowed easy re-use of the CURL handle (which allows for pipelined transactions), and it allowed me to re-use buffers (so the user doesn't have to allocate their own entire buffer ahead of time, they just have to get a pointer). This has the downside of keeping a buffer around that's as large as the largest file you ever downloaded, but for my application, that doesn't matter. In my usage, almost all downloads will be about the same size, pipelineing is important, and the downloads will only be about ~1meg.

If all you're doing is reporting scores, then the buffer size should stay small, and it won't matter.

Obviously, the content/contentLength/contentType will be overwritten on each call to downloadFile().

HTTPDownloader.h:
*** Source Snippet Removed ***

HTTPDownloader.cpp
*** Source Snippet Removed ***


hello,

thank you for sharing your code. I tried it but as a result I don't get the code of a website but only a very long list of stupid signs...
BeanDog
BeanDog
Rob Loach, regarding the actual question:

Some useful utility code from BYU's CS240 class. At the top is a link to the documentation for it and a TAR file with the C++ source code. You can pretty easily just make a request to a URL and get the response as a stream.



~BenDilts( void );
hplus0603
hplus0603
If you want a minimalist option, that you can compile straight into your code, try HTTP-GET. It's a simple C++ class that you just insert into your program, and tell it to go get a specific URL. It will return the response data to you when you ask for it.
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.