SophiaFramework UNIVERSE 5.3 |
SFXHTTPConnection は、HTTP 通信を行うためのクラスです。 HTTP 接続を行うクライアント(HTTP クライアント)を実装するための機能を提供します。
mif ファイルの設定 | |
---|---|
HTTP 接続を行うには、 mif ファイルの特権レベル設定で「Webアクセス」または「ネットワーク」の項目をオンにする必要があります。 |
BREW 2.0 / 2.1 における HTTP 通信の制約事項 | |
---|---|
BREW 2.0 / 2.1 の HTTP 通信では、それぞれ 1536 / 65536 バイト以上のデータを送信できません。 この場合、データを分割して送信するか、 SFXTCPSocket / SFXSSLSocket クラス ( BREW API ISocket インターフェース)を使用してデータを送信する必要があります。 |
HTTP クライアントは、 SFXHTTPConnection クラスを使用して以下の手順で実装します。
下記は、 GET メソッドを使用して取得した HTTP レスポンスボディからテキストデータを読み込み、デバッグウィンドウに表示するコードです。
例 16.5. GET メソッドによるテキストデータ読み込み
// コールバック関数で使用するので _http はクラスのメンバ変数として定義する class MyClass { private: SFXHTTPConnection _http; SFXAnsiStringStreamReader _reader; SFXAnsiString _string; public: Void Start(Void); Void SaveToFile(SFXPathConstRef path, SFXAnsiStringConstRef string); XALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; Void MyClass::Start(Void) { SFCError error(SFERR_NO_ERROR); // GET メソッドでアクセスする // ※ SFXHTTPConnection::SetMethod 関数呼び出しを省略した場合は、GET メソッドになる // 接続を開く if ((error = _http.Open()) == SFERR_NO_ERROR) { // 接続を開始する #if 1 // HTTP 通信の場合 // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("http://www.example.com/", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #else // HTTPS 通信の場合 // 必要に応じて SSL 認証モードを設定する _http.SetTrustMode(SSL_TRUST_MODE_FAIL); // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("https://www.example.com/", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #endif TRACE("> connecting..."); } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // 接続を閉じる _http.Close(); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); if (error == SFERR_NO_ERROR) { // HTTP ステータスコードを検査する TRACE("> result code : %d", _http.GetResultCode()); if (_http.GetResultCode() == 200) { // 接続に成功した場合: ストリームを使用して HTTP レスポンスボディを読み込む // HTTP レスポンスボディ読み込み用ストリームを取得する if ((error = _http.GetStreamReader(1024, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } } } else { error = SFERR_INVALID_STATE; } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; } // 読み込み(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; TRACE("> fetched... : %d", error); if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) { // _string 変数に string 変数を追加する if ((error = _string.Add(string)) == SFERR_NO_ERROR) { // 残りのデータをチェックする if (_reader.Ends()) { // すべてのデータを読み込んだとき: // HTTP レスポンスボディをデバッグウィンドウに表示する TRACE("--------"); TRACE("%s", _string.GetCString()); // (*) TRACE("--------"); // HTTP レスポンスボディ読み込みストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } else { // 読み込むデータがまだ存在するとき: // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; }
読み込んだデータをファイルに保存するには、(*) で以下の関数を呼びます。
例 16.6. 読み込んだデータをファイルに保存する
// 文字列 string をファイル path に保存する Void MyClass::SaveToFile(SFXPathConstRef path, SFXAnsiStringConstRef string) { SFCError error; SFXFile file; // 保存するファイル SFXAnsiStringStreamWriter writer; // ファイル出力用ストリーム // 読み書きモードでファイルを開く if ((error = file.OpenReadWrite(path)) == SFERR_NO_ERROR) { // ファイル書き込み用ストリームを取得する if ((error = file.GetStreamWriter(string.GetLength(), &writer)) == SFERR_NO_ERROR) { // string 変数からストリームバッファにデータを書き込む writer.WriteSFXAnsiString(string); // フラッシュを行う: ストリームバッファからファイルにデータを書き込む // ※ Flush 関数を呼び出さないかぎり、ファイルに書き込まれない error = writer.Flush(); // ファイル書き込み用ストリームを解放する writer.Release(); } // ファイルを閉じる file.Close(); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... } }
SFXHTTPConnection インスタンス | |
---|---|
コールバック関数が呼び出される前に、 SFXHTTPConnection インスタンスが解放されると正しく動作しません。 |
コールバック関数の第 1 引数 | |
---|---|
SFXHTTPConnection::Connect 関数は、 内部で BREW API の IWEB_GetResponseV 関数を呼び出します。 IWEB_GetResponseV 関数の呼び出しが失敗したときのエラー値(SFERR_FAILED)は、 コールバック関数の第 1 引数に渡されます。 |
下記は、 POST メソッドを使用して取得した HTTP レスポンスボディからテキストデータを読み込み、デバッグウィンドウに表示するコードです。
例 16.7. POST メソッドによるテキストデータ読み込み
// コールバック関数で使用するので _http はクラスのメンバ変数として定義する class MyClass { private: SFXHTTPConnection _http; SFXAnsiStringStreamReader _reader; SFXAnsiString _string; public: Void Start(Void); XALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; Void MyClass::Start(Void) { SFXAnsiStringStreamWriter writer; SFXAnsiString message; SFCError error(SFERR_NO_ERROR); unused(environment); // POST メソッドでアクセスする // ※ SFXHTTPConnection::SetMethod 関数呼び出しで "POST" を指定する必要がある // HTTP 接続を開く if ((error = _http.Open()) == SFERR_NO_ERROR) { // HTTP リクエストボディに書き込むデータを用意する message = "abcdefghijklmnopqrstuvwxyz"; // ストリームを使用して HTTP リクエストボディを書き込む // ストリームを取得する // ※ size 引数を指定していないのでストリームのバッファは可変長 if ((error = _http.GetStreamWriter(&writer)) == SFERR_NO_ERROR) { // message 変数からストリームバッファにデータを書き込む // ※ 書き込んだデータのサイズに合わせてストリームのバッファは自動的に拡張される // 1 回の WriteSFXAnsiString 関数呼び出しで書き込み操作は完了する if ((error = writer.WriteSFXAnsiString(message)) == SFERR_NO_ERROR) { // フラッシュを行う: ストリームバッファから HTTP リクエストボディにデータを書き込む // ※ Flush 関数を呼び出さないかぎり、データは書き込まれない if ((error = writer.Flush()) == SFERR_NO_ERROR) { // リクエストメソッドを POST に設定する if ((error = _http.SetMethod("POST")) == SFERR_NO_ERROR) { #if 1 // HTTP 通信の場合 // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("http://www.example.com", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #else // HTTPS 通信の場合 // 必要に応じて SSL 認証モードを設定する _http.SetTrustMode(SSL_TRUST_MODE_FAIL); // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("https://www.example.com", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #endif TRACE("> connecting..."); } } } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // 接続を閉じる _http.Close(); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); if (error == SFERR_NO_ERROR) { // HTTP ステータスコードを検査する TRACE("> result code : %d", _http.GetResultCode()); if (_http.GetResultCode() == 200) { // ストリームを使用して HTTP レスポンスボディを読み込む // HTTP レスポンスボディ読み込み用ストリームを取得する if ((error = _http.GetStreamReader(1024, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } } } else { error = SFERR_INVALID_STATE; } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; } // 読み込み(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; TRACE("> fetched... : %d", error); if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) { // _string 変数に string 変数を追加する if ((error = _string.Add(string)) == SFERR_NO_ERROR) { // 残りのデータをチェックする if (_reader.Ends()) { // すべてのデータを読み込んだとき: // HTTP レスポンスボディをデバッグウィンドウに表示する TRACE("--------"); TRACE("%s", _string.GetCString()); TRACE("--------"); // HTTP レスポンスボディ読み込みストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } else { // 読み込むデータがまだ存在するとき: // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; }
下記は、HTTP レスポンスボディからバイナリデータを読み込み、 そのままファイルに書き込むコードです。
例 16.8. HTTP レスポンスボディからのバイナリデータ読み込み
// コールバック関数で使用するので _http はクラスのメンバ変数として定義する class MyClass { private: SFXHTTPConnection _http; SFXFile _file; SFXBinaryStreamReader _reader; // HTTP レスポンスボディ読み込み用ストリーム SFXBinaryStreamWriter _writer; // ファイル書き込み用ストリーム SFXBuffer _buffer; // 読み込んだデータを格納するバッファ SFXBuffer _tempbuffer; // 読み込んだデータを一時的に格納するバッファ UInt32 _bufferSize; // ファイル書き込み用ストリームバッファサイズ public: Void Start(Void); XALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; Void MyClass::Start(Void) { SFCError error(SFERR_NO_ERROR); // GET メソッドでアクセスする // ※ SFXHTTPConnection::SetMethod 関数呼び出しを省略した場合は、GET メソッドになる // HTTP 接続を開く if ((error = _http.Open()) == SFERR_NO_ERROR) { #if 1 // HTTP 通信の場合: // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("http://www.example.com", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #else // HTTPS 通信の場合: // 必要に応じて SSL 認証モードを設定する _http.SetTrustMode(SSL_TRUST_MODE_FAIL); // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("https://www.example.com", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #endif TRACE("> connecting..."); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // 接続を閉じる _http.Close(); } } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); if (error == SFERR_NO_ERROR) { // HTTP ステータスコードを検査する TRACE("> result code : %d", _http.GetResultCode()); if (_http.GetResultCode() == 200) { // ストリームを使用して HTTP レスポンスボディを読み込む // HTTP レスポンスボディ読み込み用ストリームを取得する if ((error = _http.GetStreamReader(_bufferSize, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } } } else { error = SFERR_INVALID_STATE; } } // HTTP レスポンスボディをファイルに書き込む準備を行う if (error == SFERR_NO_ERROR) { // バッファサイズを設定する _bufferSize = 1024; // バッファを確保する if ((error = _tempbuffer.SetSize(_bufferSize)) == SFERR_NO_ERROR) { // ファイルを開く if ((error = _file.OpenReadWrite(SFXPath("/example.dat"))) == SFERR_NO_ERROR) { // ファイル書き込み用ストリームを取得する error = _file.GetStreamWriter(_bufferSize, &_writer); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); // ファイル書き込み用ストリームを解放する _writer.Release(); // ファイルを閉じる _file.Close(); } return; } // 読み込み(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { TRACE("> fetched... : %d", error); if (error == SFERR_NO_ERROR) { // 一時バッファサイズを再度設定する _tempbuffer.SetSize(_reader.GetReadableSize()); // ストリームバッファから_tempbuffer 変数にデータを読み込む if ((error = _reader.Read(&_tempbuffer)) == SFERR_NO_ERROR) { // _tempbuffer 変数からストリームバッファにデータを書き込む if ((error = _writer.Write(_tempbuffer)) == SFERR_NO_ERROR) { // フラッシュを行う: ストリームバッファからファイルにデータを書き込む // ※ Flush 関数を呼び出さないかぎり、ファイルに書き込まれない if ((error = _writer.Flush()) == SFERR_NO_ERROR) { // 残りのデータをチェックする if (_reader.Ends()) { // すべてのデータを読み終わったので、リソースを解放する // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); // ファイル書き込み用ストリームを解放する _writer.Release(); // ファイルを閉じる _file.Close(); } else { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); // ファイル書き込み用ストリームを解放する _writer.Release(); // ファイルを閉じる _file.Close(); } return; }
以下は、 ファイルを Web サーバーへアップロードするコードです。
SetRequestContentToFileData 関数を利用する方法では、 ファイルから全データを HTTP リクエストボディの内容としてヒープ上に読み込んでから、 HTTP 通信でファイルをアップロードしています。 そのため、アップロードできるファイルのサイズは、 携帯電話に搭載されているメモリ容量に制約されます。
SetRequestContentToFileStorage 関数を利用する方法では、 SFXHTTPConnection::SetRequestContent 関数を使用して、 ファイルストレージを HTTP リクエストボディの内容として設定しています。 この方法では、ファイルのデータがストリーミングによりサーバーに送信されるので、 アップロード可能なファイルのサイズは携帯電話に搭載されているメモリ容量に左右されません。
注意 | |
---|---|
SFXHTTPConnection::SetRequestContent 関数は、 SophiaFramework UNIVERSE 5.1.11 以降有効です。 |
注意 | |
---|---|
BREW 2.0 / 2.1 の HTTP 通信では、BREW の不具合により、 それぞれ 1536 / 65536 バイト以上のファイルをアップロードできません。 この場合、ファイルを分割してアップロードするか、 SFXTCPSocket / SFXSSLSocket クラス ( BREW API ISocket インターフェース)を使用してアップロードする必要があります。 |
例 16.9. ファイルのアップロード
#define SOURCE_FILE_PATH "/data.txt" // アップロードするファイル // コールバック関数で使用するので _http はクラスのメンバ変数として定義する class MyClass { private: SFXHTTPConnection _http; // HTTP 接続 SFXAnsiStringStreamReader _reader; // HTTP レスポンスボディ読み込み用ストリーム SFXAnsiString _string; // 読み込んだ HTTP レスポンスボディの内容 public: SFCError Start(Void); SFCError SetRequestContentToFileData(SFXFileRef file); SFCError SetRequestContentToFileStorage(SFXFileRef file); XALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; SFCError MyClass::Start(Void) { SFXFile file; // アップロードするファイル SFCError error; // エラー値 // HTTP 接続を開く if ((error = _http.Open()) == SFERR_NO_ERROR) { // ファイルを開く if ((error = file.OpenReadOnly(SFXPath(SOURCE_FILE_PATH))) == SFERR_NO_ERROR) { #if 1 if ((error = SetRequestContentToFileData(file)) == SFERR_NO_ERROR) { #else if ((error = SetRequestContentToFileStorage(file)) == SFERR_NO_ERROR) { #endif // ファイルを閉じる file.Close(); if (error == SFERR_NO_ERROR) { // HTTP リクエストボディの設定に成功したとき: // リクエストメソッドを POST に設定する // ※ POST メソッドの場合、テキストだけでなく、バイナリも送信できる if ((error = _http.SetMethod("POST")) == SFERR_NO_ERROR) { // 接続を開始する #if 1 // HTTP 通信の場合 // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("http://www.example.com/cgi-bin/fileupload.cgi", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #else // HTTPS 通信の場合 // 必要に応じて SSL 認証モードを設定する // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される _http.SetTrustMode(SSL_TRUST_MODE_FAIL); if ((error = _http.Connect("https://www.example.com/cgi-bin/fileupload.cgi", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { #endif TRACE("> connecting..."); } } } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ファイルを閉じる file.Close(); // 接続を閉じる _http.Close(); } return error; } // ヒープ上に HTTP リクエストボディの内容を作成してから HTTP リクエストボディを設定する方法 SFCError MyClass::SetRequestContentToFileData(SFXFileRef file) { SFXBinaryStreamReader reader; // ファイル読み込み用ストリーム SFXBinaryStreamWriter writer; // HTTP リクエストボディ書き込み用ストリーム SFXBuffer buffer; // ファイルから読み込んだデータ用バッファ SFCError error; // エラー値 // HTTP リクエストボディ書き込み用ストリームを取得する if ((error = _http.GetStreamWriter(1024, &writer)) == SFERR_NO_ERROR) { // ファイル読み込み用ストリームを取得する if ((error = file.GetStreamReader(1024, &reader)) == SFERR_NO_ERROR) { // ファイルから HTTP リクエストボディへデータをコピーする while ((error == SFERR_NO_ERROR) & !reader.Ends()) { // ※ ファイルの終端に到達するまで以下の処理を繰り返す // フェッチを行う: ファイルからファイル用ストリームのバッファにデータを読み込む if ((error = reader.Fetch()) == SFERR_NO_ERROR) { // buffer 変数のサイズを設定する if ((error = buffer.SetSize(reader.GetReadableSize())) == SFERR_NO_ERROR) { // ファイル用ストリームのバッファから buffer 変数にデータを読み込む if ((error = reader.Read(&buffer)) == SFERR_NO_ERROR) { // buffer 変数から HTTP 用ストリームのバッファへデータを書き込む if ((error = writer.Write(buffer)) == SFERR_NO_ERROR) { // フラッシュを行う: HTTP 用ストリームのバッファから HTTP リクエストボディにデータを書き込む // ※ Flush 関数を呼び出さないかぎり、データは書き込まれない error = writer.Flush(); } } } } } } } // ファイル読み込み用ストリームを解放する reader.Release(); // HTTP リクエストボディ書き込み用ストリームを解放する writer.Release(); return error; } // HTTP リクエストボディにファイルストレージを設定する方法 SFCError MyClass::SetRequestContentToFileStorage(SFXFileRef file) { UInt32 size; // アップロードするファイルのサイズ SFCError error; // エラー値 // ファイルサイズを取得する if ((error = SFXFile::GetSize(SFXPath(SOURCE_FILE_PATH), &size)) == SFERR_NO_ERROR) { // HTTP リクエストボディにファイルストレージとそのサイズを設定する error = _http.SetRequestContent(file, size); } // size 引数を省略して、以下のように書いても良い // ※ この場合、ファイルサイズが HTTP リクエストボディのサイズとして自動的に設定される // error = _http.SetRequestContent(file); return error; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); if (error == SFERR_NO_ERROR) { // HTTP ステータスコードを検査する TRACE("> result code : %d", _http.GetResultCode()); if (_http.GetResultCode() == 200) { // HTTP レスポンスボディ読み込み用ストリームを取得する if ((error = _http.GetStreamReader(1024, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } } } else { error = SFERR_INVALID_STATE; } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; } // 読み込み(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; // HTTP レスポンスボディ読み込み用ストリームからフェッチした文字列 TRACE("> fetched... : %d", error); if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) { // _string 変数に string 変数を追加する if ((error = _string.Add(string)) == SFERR_NO_ERROR) { // 残りのデータをチェックする if (_reader.Ends()) { // すべてのデータを読み込んだとき: // HTTP レスポンスボディをデバッグウィンドウに表示する TRACE("--------"); TRACE("%s", _string.GetCString()); TRACE("--------"); // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } else { // 読み込むデータがまだ存在するとき: // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // 接続を閉じる _http.Close(); } return; }
SetRequestContentToFileData 関数は、 メモリストレージ(SFXMemory)と SFXHTTPConnection::SetRequestContent 関数を使用して、 以下のように実装することも可能です。
例 16.10. SetRequestContentToFileData 関数の別の実装
class MyClass { private: ... SFXMemory _memory; // メモリストレージ ... public: .... }; SFCError MyClass::Start(Void) { ... if (error != SFERR_NO_ERROR) { // エラーが発生したとき // メモリを閉じる _memory.Close(); // ファイルを閉じる file.Close(); // 接続を閉じる _http.Close(); } return error; } // メモリストレージを使用して HTTP リクエストボディを設定する方法 SFCError MyClass::SetRequestContentToFileData(SFXFileRef file) { SFXBinaryStreamReader reader; // ファイル読み込み用ストリーム SFXBinaryStreamWriter writer; // メモリ書き込み用ストリーム SFXBuffer buffer; // ファイルから読み込んだデータ用バッファ SFCError error; // エラー値 // メモリを開く if ((error = _memory.Open()) == SFERR_NO_ERROR) { // メモリ書き込み用ストリームを取得する if ((error = _memory.GetStreamWriter(1024, &writer)) == SFERR_NO_ERROR) { // ファイル読み込み用ストリームを取得する if ((error = file.GetStreamReader(1024, &reader)) == SFERR_NO_ERROR) { // ファイルからメモリへデータをコピーする while ((error == SFERR_NO_ERROR) & !reader.Ends()) { // ※ ファイルの終端に到達するまで以下の処理を繰り返す // フェッチを行う: ファイルからファイル用ストリームのバッファにデータを読み込む if ((error = reader.Fetch()) == SFERR_NO_ERROR) { // buffer 変数のサイズを設定する if ((error = buffer.SetSize(reader.GetReadableSize())) == SFERR_NO_ERROR) { // ファイル用ストリームのバッファから buffer 変数にデータを読み込む if ((error = reader.Read(&buffer)) == SFERR_NO_ERROR) { // buffer 変数からメモリ用ストリームのバッファへデータを書き込む if ((error = writer.Write(buffer)) == SFERR_NO_ERROR) { // フラッシュを行う: メモリ用ストリームのバッファからメモリにデータを書き込む // ※ Flush 関数を呼び出さないかぎり、データは書き込まれない error = writer.Flush(); } } } } } } } if (error == SFERR_NO_ERROR) { // HTTP リクエストボディにメモリとそのサイズを設定する error = _http.SetRequestContent(_memory, _memory.GetSize()); // ※ "error = _http.SetRequestContent(_memory);" と記述しても良い } // ファイル読み込み用ストリームを解放する reader.Release(); // メモリ書き込み用ストリームを解放する writer.Release(); return error; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); // メモリを閉じる _memory.Close(); if (error == SFERR_NO_ERROR) { ... }
以下は、 ファイルをセグメントに分割して Web サーバーへアップロードするコードです。
例 16.11. ファイルの分割アップロード
#define SOURCE_FILE_PATH "/data.txt" // アップロードするファイル #define SEGMENT_SIZE 1535 // セグメントサイズ // コールバック関数で使用するので _http はクラスのメンバ変数として定義する class MyClass { private: SFXHTTPConnection _http; // HTTP 接続 SFXAnsiStringStreamReader _reader; // HTTP レスポンスボディ読み込み用ストリーム SFXAnsiString _string; // 読み込んだ HTTP レスポンスボディの内容 SFXFile _file; // ファイル UInt32 _fileSize; // ファイルサイズ UInt32 _sentSize; // 送信済みデータのサイズ public: SFCError Start(Void); SFCError UploadFileSegment(Void); SFCError SetFileSegment(SFXFileRef file); XALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; SFCError MyClass::Start(Void) { SFCError error; // エラー値 // HTTP 接続を開く if ((error = _http.Open()) == SFERR_NO_ERROR) { // ファイルを開く if ((error = _file.OpenReadOnly(SFXPath(SOURCE_FILE_PATH))) == SFERR_NO_ERROR) { // ファイルサイズを取得する if ((error = SFXFile::GetSize(SFXPath(SOURCE_FILE_PATH), &_fileSize)) == SFERR_NO_ERROR) { // リクエストメソッドを POST に設定する // ※ POST メソッドの場合、テキストだけでなく、バイナリも送信できる if ((error = _http.SetMethod("POST")) == SFERR_NO_ERROR) { // 最初のファイルセグメントをアップロードする error = UploadFileSegment(); } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ファイルを閉じる _file.Close(); // 接続を閉じる _http.Close(); } return error; } // ファイルセグメントをアップロードする SFCError MyClass::UploadFileSegment(Void) { SFCError error; // ファイルセグメントを設定する if ((error = SetFileSegment(_file)) == SFERR_NO_ERROR) { // Web サーバーへ接続する // ※ 接続要求の結果は、OnConnect 関数に通知される if ((error = _http.Connect("http://www.example.com/cgi-bin/fileupload.cgi", XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { TRACE("> connecting..."); } } return error; } // ファイルセグメントを設定する SFCError MyClass::SetFileSegment(SFXFileRef file) { UInt32 diff; // 残りデータのサイズ(SEGMENT_SIZE 以下のサイズのとき) SFCError error(SFERR_NO_ERROR); // エラー値 if (_sentSize + SEGMENT_SIZE < _fileSize) { _sentSize += SEGMENT_SIZE; // HTTP リクエストボディに現在のファイルポインタの位置から SEGMENT_SIZE 分のデータを設定する error = _http.SetRequestContent(file, SEGMENT_SIZE); } else { if (_fileSize > _sentSize) { diff = _fileSize - _sentSize; _sentSize = _fileSize; // HTTP リクエストボディに現在のファイルポインタの位置から diff 分のデータを設定する error = _http.SetRequestContent(file, diff); } else { error = SFERR_FAILED; } } return error; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error) { TRACE("> connected... : %d", error); if (error == SFERR_NO_ERROR) { // HTTP ステータスコードを検査する TRACE("> result code : %d", _http.GetResultCode()); if (_http.GetResultCode() == 200) { // HTTP レスポンスボディ読み込み用ストリームを取得する if ((error = _http.GetStreamReader(1024, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } } } else { error = SFERR_INVALID_STATE; } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // ファイルを閉じる _file.Close(); // 接続を閉じる _http.Close(); } return; } // 読み込み(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; // HTTP レスポンスボディ読み込み用ストリームからフェッチした文字列 TRACE("> fetched... : %d", error); if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) { // _string 変数に string 変数を追加する if ((error = _string.Add(string)) == SFERR_NO_ERROR) { // 残りのデータをチェックする if (_reader.Ends()) { // すべてのデータを読み込んだとき: // HTTP レスポンスボディをデバッグウィンドウに表示する TRACE("--------"); TRACE("%s", _string.GetCString()); TRACE("--------"); // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); if (_sentSize == _fileSize) { // すべてのファイルセグメントをアップロードしたとき: // ファイルを閉じる _file.Close(); // 接続を閉じる _http.Close(); } else { // まだアップロードすべきファイルセグメントが存在するとき: // 次のファイルセグメントをアップロードする error = UploadFileSegment(); } } else { // 読み込むデータがまだ存在するとき: // フェッチを行う: HTTP レスポンスボディからストリームバッファにデータを読み込む // ※ 読み込み(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // HTTP レスポンスボディ読み込み用ストリームを解放する _reader.Release(); // ファイルを閉じる _file.Close(); // 接続を閉じる _http.Close(); } return; }
Copyright(c) 2002 - 2024 Sophia Cradle Incorporated All Rights Reserved. |