Почему вы поставить 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;
Когда * все * это хорошо? Использование командной строки cURL? Если да, отправьте его. Я действительно не понимаю, почему вы отправляете 'GET/....' в свой запрос заголовка. –
Используйте 'strace' для захвата необработанного запроса, отправляемого на сервер. Сравните с запросом, который необходимо отправить. Затем выясните, как сделать ваш запрос совпадающим с тем, что нужно отправить. Постскриптум со всей работой, выполняемой этим кодом, я не понимаю, почему требуется скручивание. Вы сделали всю работу. Просто создайте сокет, подключитесь к серверу, напишите запрос, прочитайте ответ. Готово. –
Это не завиток командной строки. Я использую C++. И это другая версия, которую я пробовал. Первая была с «CURLOPT_POSTFIELDS». Проблема в том, что я получаю ошибку «запрос не может быть удовлетворен» –