Interfacing with Interactive Problems

Back to General discussions forum

DaskieLQC     2015-05-28 23:59:47

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++)

drewcocker     2015-05-29 06:20:10
User avatar

In answer to your questions:

  1. Yes, you're missing something obvious. The code doesn't always have to compile on the site. Most problems can be run locally and the answers posted into the answer field. You still need have code in the code field, but it doesn't have to have successfully run on the site. I couldn't get my solution (using c#) to run on the server - I couldn't work out what the error was - but was able to run it fine locally. That way you can use whatever library you want.
  2. No idea. I'm answering this question because I just solved this problem and wanted to share what I found out.
  3. It looks like Quandray was using C rather than C++ and uses #include <curl/curl.h> for the web stuff.
Quandray     2015-05-29 14:16:02
User avatar

I use Libcurl with a C++ compiler. C is a subset of C++ and the code I write uses a mixture of C & C++.

DaskieLQC     2015-05-30 01:02:37

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...

DaskieLQC     2015-05-30 01:02:57
#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");
}
Quandray     2015-05-30 07:52:03
User avatar

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);
DaskieLQC     2015-05-30 23:31:44

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:

  • UYOqyFFs2iunFsYX17YNyTM0
  • q82H/jNQKNfEJALd1FdvxDM1

Tokens that do not work and yeild "error: Bad token":

  • 5DC6reyZb+n8DdFwYKFeTU0
  • WaG9GXZex1wXXP83r/Q+ajIz

Not sure what's going on there.. intentional or possibly a bug?

Quandray     2015-06-02 19:56:14
User avatar

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.

tinzendA     2015-06-28 22:03:56

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
Rodion (admin)     2015-06-29 04:49:36
User avatar

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.

tinzendA     2015-06-29 08:28:53

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.

Rodion (admin)     2015-06-29 10:41:54
User avatar

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 ;-)

goto     2018-11-17 23:32:14

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?

Rodion (admin)     2018-11-18 05:29:04
User avatar

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)... :)

goto     2018-11-18 12:01:06

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.

Rodion_Gork     2018-11-18 18:59:36
User avatar

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.

Please login and solve 5 problems to be able to post at forum