C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

UE4/C++: FHttpModule で SetContentAsString して POST で投げたら落ちた時のメモ

次のようなごく簡単な FHttpModule の実装例を実行するとゲームまたは UE4Editor ごとプロセスが落ちてしまう。

TSharedRef< IHttpRequest > r = FHttpModule::Get().CreateRequest();
r->OnProcessRequestComplete().BindUObject( this, &UMyHttpTask::HandleRequest );
r->SetURL( TEXT( "https://example.com/" ) );
r->SetVerb( TEXT( "POST" ) );
r->SetContentAsString( TEXT( "nyanko" ) );
r->ProcessRequest();

何が間違えているだろうか?あるいは足りないだろうか?余計だろうか?この実装例で落ちる場合の答えは Crash Reporter で知れる。

f:id:USAGI-WRP:20181023003802p:plain

Assertion failed: !GetHeader("Content-Type").IsEmpty() || IsURLEncoded(RequestPayload) [File:D:\Build\++UE4+Release-4.19+Compile\Sync\Engine\Source\Runtime\Online\HTTP\Private\Curl\CurlHttp.cpp] [Line: 569]

UE4の実装のアサーションで"殺されて"いる。アサーションの冒頭の !GetHeader("Content-Type").IsEmpty() で分かるように、 Content-Type ヘッダーが「足りない」と分かる。こんな事で UE4Editor ごとアサーションで殺されるとは思わなかったので、遭遇したときには「なんぞめんどくさい何かを踏んだかのぅ…」と覚悟したものの、原因は "こんな事" だった。

次のように Content-Type を設定する実装を追加すると期待動作するようになる。

r->SetHeader( TEXT( "Content-Type" ), TEXT( "text/plain" ) );

今回の例では SetContentAsString を使っているので Content-Length は自動的に加えられる。また、蛇足としてPOSTフォームのクエリーを体裁の場合、Content-Typeapplication/x-www-form-urlencoded とする。