2016-06-23 6 views
1

У меня эта неприятная проблема с моей программой сервера minecraft. Я пытаюсь получить ответ от пользователя minecraft.com, когда вы пытаетесь войти на мой сервер minecraft. Все в порядке и настройки, такие как проверка ключа токена и общий секрет.Использование CURL для запроса GET

Я просто не могу получить запрос приступить к работе с завитком :(

Это то, что у меня есть:

requestString.append("GET /session/minecraft/hasJoined?username="); 
    requestString.append(player.Username); 
    requestString.append("&"); 
    requestString.append("serverId="); 
    requestString.append(player.loginHash); 
    requestString.append(" HTTP/1.0\r\n"); 
    std::cout << requestString << std::endl; 


    curl_easy_setopt(curl, CURLOPT_URL, "https://sessionserver.mojang.com"); 
    list = curl_slist_append(list, requestString.c_str()); 
    list = curl_slist_append(list, "User-Agent: MinecraftServerPP\r\n"); 
    list = curl_slist_append(list, "Connection: close\r\n"); 
    list = curl_slist_append(list, "\r\n"); 
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); 
    curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem"); 

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_write_data); 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); 
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 

я получаю нормально с сервера, но не объект JSON, содержащий данные мне нужно

+0

Когда * все * это хорошо? Использование командной строки cURL? Если да, отправьте его. Я действительно не понимаю, почему вы отправляете 'GET/....' в свой запрос заголовка. –

+0

Используйте 'strace' для захвата необработанного запроса, отправляемого на сервер. Сравните с запросом, который необходимо отправить. Затем выясните, как сделать ваш запрос совпадающим с тем, что нужно отправить. Постскриптум со всей работой, выполняемой этим кодом, я не понимаю, почему требуется скручивание. Вы сделали всю работу. Просто создайте сокет, подключитесь к серверу, напишите запрос, прочитайте ответ. Готово. –

+0

Это не завиток командной строки. Я использую C++. И это другая версия, которую я пробовал. Первая была с «CURLOPT_POSTFIELDS». Проблема в том, что я получаю ошибку «запрос не может быть удовлетворен» –

ответ

2

Почему вы поставить GET строку запроса в заголовке HTTP Он не принадлежит там вообще, и в самом деле документация Libcurl даже указывает, что из:.?

CURLOPT_HTTPHEADER explained

Первая строка в запросе (содержащего метод, обычно GET или POST) не заголовок и не могут быть заменены с помощью этой опции. Только строки, следующие за строкой запроса, являются заголовками. Добавление этой строки метода в этот список заголовков приведет только к тому, что ваш запрос отправит недопустимый заголовок. Используйте метод CURLOPT_CUSTOMREQUEST, чтобы изменить метод.

Ваш текущий код посылает запрос GET похожее на это:

 
GET/HTTP/1.1 
Host: sessionserver.mojang.com 
GET /session/minecraft/hasJoined?username=<username>&serverId=<loginHash> HTTP/1.0 
User-Agent: MinecraftServerPP 
Connection: close 

Вот почему вы не получаете ответ вы ожидаете. Вы на самом деле не запрашиваете ресурс /session/minecraft/hasJoined, вы на самом деле запрашиваете ресурс root /.

Вы должны быть отправив запрос GET как это вместо:

 
GET /session/minecraft/hasJoined?username=<username>&serverId=<loginHash> HTTP/1.0 
Host: sessionserver.mojang.com 
User-Agent: MinecraftServerPP 
Connection: close 

Для достижения этой цели, вы должны передать URL полный к CURLOPT_URL и пусть Libcurl обрабатывать GET линию для вас. Вы можете использовать CURLOPT_HTTPGET, чтобы фактически использовать GET.

Кроме того, вы должны указать CURLOPT_HTTP_VERSION, если хотите указать конкретную версию HTTP.

Кроме того, хотя вы можете использовать CURLOPT_HTTPHEADER для заголовков User-Agent и Connection, вы должны использовать CURLOPT_USERAGENT и CURLOPT_FORBID_REUSE вместо этого.

Попробуйте вместо этого:

url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username="); 
url.append(player.Username); // <-- NOTE: see further below! 
url.append("&serverId="); 
url.append(player.loginHash); // <-- NOTE: see further below! 
std::cout << url << std::endl; 

curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); 
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L); 
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem"); 

curl_easy_setopt(curl, CURLOPT_USERAGENT, "MinecraftServerPP"); 

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_write_data); 
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); 
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 

Теперь, с учетом сказанного, есть дополнительная логика вам нужно принять во внимание, чтобы обрабатывать CURLOPT_URLправильно:

Pass в указатель на URL для работы.Параметр должен быть символ * к нулевой строке, оканчивающейся , который должен быть URL-кодированного в следующем формате:

схема: // хост: порт/пути

Для большего объяснения формата, пожалуйста, см. RFC 3986.

libcurl не подтверждает синтаксис или использует эту переменную до тех пор, пока не будет выдана передача. Даже если вы установили сумасшедшее значение здесь, curl_easy_setopt все равно вернет CURLE_OK.

В частности, эти разделы RFC имеют отношение к вашей коде:

2,1. Процент-Кодирование

Механизм процента-кодирование используется для представления октета данных в компоненте, когда соответствующий символ, который октет находится за пределами разрешенного установить или используются в качестве разделителя, или внутри компонента. Процент закодированный октет кодируется как триплет символа, состоящий из процентного символа «%», за которым следуют две шестнадцатеричные цифры, представляющие это числовое число октетов. Например, «% 20» представляет собой процентное кодирование для двоичного октета «00100000» (ABNF:% x20), который в US-ASCII соответствует символу пробела (SP). Section 2.4 описывает, когда применяется процентное кодирование и декодирование.

РСТ-закодированы = "%" HEXDIG HEXDIG

'A' в верхнем регистре шестнадцатеричных цифр через 'F' эквивалентны строчных цифр 'A' через 'F', соответственно. Если два URI отличаются только в случае шестнадцатеричных цифр, используемых в октетах с процентным кодированием, они эквивалентны. Для обеспечения согласованности производители URI и нормализаторы должны использовать верхние шестнадцатеричные цифры для всех процентных кодировок.

2,4. Когда кодировать или декодировать

При нормальных обстоятельствах единственный раз, когда октеты внутри URI имеют процентное кодирование, в процессе создания URI из его составных частей. Это когда реализация определяет, какие зарезервированные символы должны использоваться как разделители подкомпонентов и которые можно безопасно использовать в качестве данных. После создания URI всегда находится в своей процентной форме.

Когда URI разыменовывается, компоненты и подкомпоненты, значимые для процесса разыменования схемы (если есть), должны быть проанализированы и разделены до того, как процентные кодированные октеты внутри этих компонентов могут быть безопасно декодированы, так как в противном случае данные могут быть ошибочно приняты за разделители компонентов. Единственное исключение - для октетов с процентным кодированием, соответствующих символам в незарезервированном наборе, которые могут быть декодированы в любое время. Например, октет, соответствующий тильде («~»), часто кодируется как «% 7E» более старыми реализациями обработки URI; «% 7E» можно заменить на «~» без изменения его интерпретации.

Поскольку символ процента («%») служит индикатором для октетов с процентным кодированием, он должен быть пронумерован как «% 25» для этого октета, который будет использоваться в качестве данных в URI.Реализации не должны перекодировать или декодировать одну и ту же строку более чем один раз, поскольку декодирование уже декодированной строки может привести к неверному истолкованию октета процента данных в качестве начала процентного кодирования или наоборот в случае процентного кодирования уже процентная кодировка.

query компонент URL определяется в section 3.4:

запроса = * ("?" PChar/"/" /)

pchar определяется в section 3.3:

pchar = unreserved/pct-encoded/sub-delims/":"/"@"

unreserved определяется в section 2.3:

безоговорочное = АЛЬФА/ЦИФРА/"-"/""/"_"/"~"

sub-delims определяется в section 2.2:

суб-delims = "!"/"$"/"&"/"'"/"("/")"/"*"/"+"/","/";"/«=»

Таким образом, если какие-либо символы в ваших player.Username и player.loginHash строк являются вне этих разрешенных символов, вы MUST процента, закодировать их при вводе их в строке запроса вашего URL. Например:

std::string encodeForUrlQuery(std::string s) 
{ 
    static const char* allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~!$&'()*+,;=:@/?"; 

    // this is just an example, in practice you should first convert the 
    // input string to Unicode and charset-encode it, usually to UTF-8, 
    // and then percent-encode the resulting octets... 

    std::string::size_type idx = s.find_first_not_of(allowed); 
    while (idx != std::string::npos) 
    { 
     std::ostringstream oss; 
     oss << '%' << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)s[idx]; 
     std::string encoded = oss.str(); 
     s.replace(idx, 1, encoded); 
     idx = s.find_first_not_of(allowed, idx+encoded.length()); 
    } 
    return s; 
} 

url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username="); 
url.append(encodeForUrlQuery(player.Username)); 
url.append("&serverId="); 
url.append(encodeForUrlQuery(player.loginHash)); 
std::cout << url << std::endl; 
+0

Спасибо за подробный ответ. Я попробую ваши предложения –

+0

Работает! Спасибо –

Смежные вопросы