前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

16.2. HTTP 接続

SFXHTTPConnection は、HTTP 通信を行うためのクラスです。 HTTP 接続を行うクライアント(HTTP クライアント)を実装するための機能を提供します。

[Caution] mif ファイルの設定

HTTP 接続を行うには、 mif ファイルの特権レベル設定で「Webアクセス」または「ネットワーク」の項目をオンにする必要があります。

[Caution] BREW 2.0 / 2.1 における HTTP 通信の制約事項

BREW 2.0 / 2.1 の HTTP 通信では、それぞれ 1536 / 65536 バイト以上のデータを送信できません。

この場合、データを分割して送信するか、 SFXTCPSocket / SFXSSLSocket クラス ( BREW API ISocket インターフェース)を使用してデータを送信する必要があります。

16.2.1. HTTP クライアントの実装

HTTP クライアントは、 SFXHTTPConnection クラスを使用して以下の手順で実装します。

  1. HTTP 接続(SFXHTTPConnection インスタンス)を作成します。
  2. SFXHTTPConnection::Open 関数を呼び出して、HTTP 接続を開きます。
  3. SFXHTTPConnection::SetMethod 関数を呼び出して、 HTTP リクエストメソッド(デフォルト: GET メソッド)を設定します。 SFXHTTPConnection::GetStreamWriter 関数で出力ストリームを取得しリクエストボディにデータを書き込みます。 リクエストヘッダーは、SFXHTTPConnection::SetRequestHeader 関数を使用して設定します。 なお、リクエストボディは、SFXHTTPConnection::SetRequestContent 関数を使用して設定することも可能です。
  4. HTTPS 通信の場合、 SFXHTTPConnection::SetTrustMode 関数を呼び出して、 SSL 認証モード(デフォルト: SSL_TRUST_MODE_FAIL)を設定します。
  5. SFXHTTPConnection::Connect 関数を呼び出して、Web サーバーに接続します。
  6. Web サーバーへの接続の結果は、 SFXHTTPConnection::Connect 関数で登録したコールバック関数に通知されます。 Web サーバーへの接続の結果(エラーコード)は、コールバック関数の第 1 引数に渡されます。 エラーコードが SFERR_NO_ERROR であれば、HTTP レスポンスの取得に成功しています。
  7. SFXHTTPConnection::GetResultCode 関数で HTTP ステータスコードを取得し、その内容を確認してから、 SFXHTTPConnection::GetStreamReader 関数で入力ストリームを取得してレスポンスボディを読み込みます。 レスポンスヘッダーは、SFXHTTPConnection::GetResponseHeader 関数を使用して取得します。 なお、レスポンスボディは、SFXHTTPConnection::GetResponseContent 関数を使用して取得することも可能です。
  8. SFXHTTPConnection::Close 関数を呼び出して、 HTTP 接続を閉じます。

16.2.2. GET メソッドによるテキストデータ読み込み

下記は、 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) {

        // エラーが発生したとき
        ...
    }
}
[Caution] SFXHTTPConnection インスタンス

コールバック関数が呼び出される前に、 SFXHTTPConnection インスタンスが解放されると正しく動作しません。

[Note] コールバック関数の第 1 引数

SFXHTTPConnection::Connect 関数は、 内部で BREW API の IWEB_GetResponseV 関数を呼び出します。 IWEB_GetResponseV 関数の呼び出しが失敗したときのエラー値(SFERR_FAILED)は、 コールバック関数の第 1 引数に渡されます。

16.2.3. POST メソッドによるテキストデータ読み込み

下記は、 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;
}

16.2.4. バイナリデータの読み込み

下記は、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;
}

16.2.5. ファイルのアップロード

以下は、 ファイルを Web サーバーへアップロードするコードです。

SetRequestContentToFileData 関数を利用する方法では、 ファイルから全データを HTTP リクエストボディの内容としてヒープ上に読み込んでから、 HTTP 通信でファイルをアップロードしています。 そのため、アップロードできるファイルのサイズは、 携帯電話に搭載されているメモリ容量に制約されます。

SetRequestContentToFileStorage 関数を利用する方法では、 SFXHTTPConnection::SetRequestContent 関数を使用して、 ファイルストレージを HTTP リクエストボディの内容として設定しています。 この方法では、ファイルのデータがストリーミングによりサーバーに送信されるので、 アップロード可能なファイルのサイズは携帯電話に搭載されているメモリ容量に左右されません。

[Note] 注意

SFXHTTPConnection::SetRequestContent 関数は、 SophiaFramework UNIVERSE 5.1.11 以降有効です。

[Caution] 注意

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