Back to General discussions forum
Technically for the Say 100 problem, but applies to any/all interactive problems.
How exactly do we interface with the server? I've done almost no "web" stuff in the past, so this is unfamiliar territory. I'm using c++, and looking into the problem it seems like it's one of the few languages that doesn't have some sort of built-in web library. Instead, there are a ton of 3rd party libraries and frameworks, which is great, but the code has to compile on this site.
So...
Am I missing something obvious and c++ does have the built-in capability?
Do the online compilers include any of the more popular libraries such as Libcurl?
(tried to look into this but was unsuccessful)
Is c++ simply not an option and I should use another language for the interactive problems?
(Although apparently user Quandray solved Say 100 using C/C++)
In answer to your questions:
#include <curl/curl.h>
for the web stuff. I use Libcurl with a C++ compiler. C is a subset of C++ and the code I write uses a mixture of C & C++.
Alright thank you, that makes a lot more sense. Unfortunately now I cannot seem to, I assume, send the POST request correctly. I've managed to make connection with the server, but I only ever get the reply
error: No token found
I'm using Libcurl in C++ using Visual Studio.
As I understand It, I am to send the following string to http://codeabbey.sourceforge.net/say-100.php
token: <token here not including angle brackets>
ending with a newline, and expect to recieve
secret: <some number>
I've tried using c++ strings, c-style strings, basic char arrays, with null terminating character, without null terminating character, with and without newline character, with and without the space, without and without the brackets, etc. etc. It simply isn't working.
I'm assuming I'm not using Libcurl correctly. Maybe I'm sending too much, or not enough data, I just don't know.
Anyway, the code is below...
#pragma once
#include <iostream>
#include <string>
#include <curl/curl.h>
using namespace std;
void cleanup(CURL * curl) {
curl_easy_cleanup(curl);
curl_global_cleanup();
}
size_t handleResponse(void * buffer, size_t size, size_t nmemb, void * userp) {
int nbytes = size * nmemb;
for (int i = 0; i < nbytes; i++) {
cout << ((char *)buffer)[i];
}
cout << endl;
return size * nmemb;
}
int main() {
CURL * curl;
CURLcode resCode;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (!curl) {
cerr << "could not initialize curl" << endl;
cleanup(curl);
cout << endl;
system("pause");
return 1;
}
string token;
cin >> token;
token = "token: " + token + "\n";
//I'm guessing here's where it's going wrong...
curl_easy_setopt(curl, CURLOPT_URL, "http://codeabbey.sourceforge.net/say-100.php");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, token.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handleResponse);
resCode = curl_easy_perform(curl);
if (resCode != CURLE_OK) {
cerr << "curl_easy_perform() failed: " << curl_easy_strerror(resCode) << endl;
cleanup(curl);
cout << endl;
system("pause");
return 1;
}
/*
Future location of further exchanges and the rest of the program
*/
cleanup(curl);
cout << endl;
system("pause");
}
I think it's the way you are passing the token. My code has the token hardcoded as
char data[256]="token=9qdU7JeINVALIDTKEyRZiTYz";
then
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,data);
Thank you Quandray! The problem was the equals sign, as in..
Correct:
"token=myfancytoken"
Incorrect:
"token: myfancytoken"
Updated Code:
string token;
cin >> token;
token = "token=" + token + "\n";
curl_easy_setopt(curl, CURLOPT_URL, "http://codeabbey.sourceforge.net/say-100.php");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, token.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handleResponse);
resCode = curl_easy_perform(curl);
Interestingly enough, it appears that the token generated will contain alphanumeric characters, forward slashes, and plus signs. However, any token that contains a plus sign will not work, and instead yeild "error: Bad token", e.g.,
Tokens that work and yeild the secret value back:
Tokens that do not work and yeild "error: Bad token":
Not sure what's going on there.. intentional or possibly a bug?
I was lucky that I didn't get a token containing a plus sign.
The documentation for CURLOPT_POST says that it will make curl use a "Content-Type: application/x-www-form-urlencoded" header.
Amongst other things, this tells the server that spaces have been converted to plus signs.
I'm guessing that the server is converting the plus signs back to spaces.
The documentation also says that you can override the default POST Content-Type: header by setting your own with CURLOPT_HTTPHEADER. I haven't tried it.
However, it may be easier to convert any plus signa into %2B, so that the server will then convert them back to plus signs.
I was having the same prob using ':' as opposed to'='. Now I can't get the end token.
The server keeps giving me another secret number.
I'm using sfml (and am very frustrated).
string data = "token=FFq5NlXJm1DjQGN8VYPFEjk1";
sendRequest(data);
data = data + "\n" + "answer=" + response;
cout<<sendRequest(data);
Here is the request-response interaction I keep getting.
token=FFq5NlXJm1DjQGN8VYPFEjk1
secret: 13
token=FFq5NlXJm1DjQGN8VYPFEjk1
answer=87
secret: 66
Hi! Your code fragment has two sendRequest
calls. Is this intentionally (i.e. response
is calculated
somewhere between 2-nd
and 3-rd
line - and you just skipped few more lines from between)?
> I was having the same prob using ':' as opposed to'='.
Please, make sure you are sending the proper Content-Type
. I'm not sure what it is from your code fragment.
Feel free to post the whole code (if it is large - to pastebin.com - and drop a link here)
Important Update: note that if you use url-encoded-form-data
, i.e. with =
instead of :
, then you
must glue lines not with \n
but with &
instead. However I advise to switch Content-Type
to text-plain
instead since this is less tricky approach and has not as many pitfalls.
Hi Admin,
Yes response was calculated elsewhere and I skipped the lines.
I didn't realise I was sending url-encoded and the issue was using \n to glue instead of &.
I submited my code and it worked so you can see it(it's not to pretty, but it works).
I'm green but hopefully I'll improve and learn doing the other interactive probs.
Thanks for the reply.
Hi! I'm very glad you overcame this trouble! You are far not that green, allow me to assure you :)
I believe you will be very successful and probably very soon ;-)
Probably a stupid question, but now, when server changed, does that gluing with & instead of \n still apply? I'm trying to solve this task with Winsock and url-encoded-form-data. I get through the secret, but after sending the final answer i get nothing in response. Any help?
Hi there!
I think this couldn't be "stupid question"! Thanks for checking and testing!
Both methods should work (though I think correct header value is application/x-www-form-urlencoded
(as in the code
you've uploaded).
If you get nothing in response - this looks strange, since the server code usually returns various error messages if encounters errors...
However! Do you send this header Content-Length: 32
the same on both requests? I think you want to have it
calculated according to real length of the data...
You can alternatively try this from command line using curl
utility (probably needs to be installed in windows),
like:
curl -XPOST -d token=... http://open-abbey.appspot.com/interactive/say-100
curl -XPOST -d 'token=...&answer=...' http://...
Another thought - looking at your code I was impressed how large this can become when implemented in C++
and
without using some library for HTTP. Of course it is not extremely hard, but this problem was meant to be easy :)
So I suggest checking one of libraries mentioned here on stackoverflow
or trying to switch temporarily to other language with http support out-of-the-box... Or installing curl
mentioned
above and calling this command from the program (dirty hack but should work -
and may be easier than compiling with libraries)... :)
Thank you for reply! Your notice about Content-length got me on the right direction. The problem was that i didn't send the header in the second time, only the answer...
As for the difficulty of implementation without using 3rd party libraries - it's a good opportunity for me to learn about socket programming and i also like to use low-level approach for tasks here.
Me again. Sorry for I missed this, about missing header, sorry :) Very glad you've got it fixed now.
You are right about opportunity to learn low-level of TCP-related programming (though I believe in C++ it is bit more
complicated than necessary due to historical reasons). I dare only to propose that socket-related code should be
then isolated in a separate function, like sendPostRequest(char* data, int length)
- then it can be reused it in
other program - and have less chance to forget about header etc :)
Well done, I see another one of these "interactive" have surrendered to your efforts!
BTW, I've just noticed you are far over the level necessary even for new certificate. So if you write the name for it here or in your profile - I will add it.