ホーム > デベロッパ > SophiaFramework > BREW C++ 逆引きコード集

BREW C++ プログラミング 逆引きコード集 : ネットワーク

HTTP / HTTPS 通信の行う方法

SFXHTTPConnection クラスを利用してHTTP / HTTPS 通信を行います。

// HTTP / HTTPS 通信に必要な SFXHTTPConnection クラスのインスタンス _http は
// クラスのメンバ変数として定義する
class MyClass {
private:
    SFXHTTPConnection _http;
    SFXAnsiStringStreamReader _reader;
    SFXAnsiString _receivedString;
public:
    Void Start(Void);
    CALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch)
};

Void MyClass::Start(Void)
{
    SFCError error(SFERR_NO_ERROR);

    // HTTP 接続の初期化を行う
    if ((error = _http.Open()) == SFERR_NO_ERROR) {
    
        // HTTP リクエスト メソッドを "GET" に設定する
        // 設定省略時は "GET" となる
        _http.SetMethod("GET");

        // 接続を開始する
#if 1
        // HTTP 接続の場合
        if ((error = _http.Connect("http://www.example.com/",
                         CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
#else
        // HTTPS 接続の場合: 
        //     ※ サーバー証明書が使用するCA証明書が携帯端末に標準搭載
        //          されていない場合、CA証明書を追加する必要がある
        //                                     [下記『関連情報』参照]
        //             
        // 必要に応じて検証モードを設定する
        _http.SetTrustMode(SSL_TRUST_MODE_FAIL);
        if ((error = _http.Connect("https://www.example.com/",
                         CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
#endif
            ...
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
        _http.Close();
    }
    return;
}

// 接続が完了すると呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error)
{
    SFXPropertyConstPtr header;
    SInt16 i;

    if (error == SFERR_NO_ERROR) {
        
        // 各種パラメータを表示する

        // HTTP ステータス コードを取得する
        TRACE("result code = %d", _http.GetResultCode());
        // HTTP レスポンス ヘッダーの Content-Length フィールドを取得する
        TRACE("content length = %d", _http.GetLength()); 
        // HTTP レスポンス ヘッダーの Content-Type フィールドを取得する
        TRACE("content type = %s", _http.GetType().GetCString());
        // HTTP レスポンス ヘッダーの Content-Encoding フィールドを取得する
        TRACE("content encoding = %s", _http.GetEncoding().GetCString());
        // HTTP レスポンス ヘッダーの Date フィールドを取得する
        TRACE("date = %s", 
              _http.GetDate().Format("YYYY/MM/DD hh:mm:ss").GetCString());
        // HTTP レスポンス ヘッダーの Expires フィールドを取得する
        TRACE("expires = %s", 
              _http.GetExpires().Format("YYYY/MM/DD hh:mm:ss").GetCString());
        // HTTP レスポンス ヘッダーの Last-Modified フィールドを取得する
        TRACE("last modified = %s",
         _http.GetLastModified().Format("YYYY/MM/DD hh:mm:ss").GetCString());

        
        // HTTP レスポンス ヘッダーを取得する
        header = &_http.GetResponseHeader();
        
        // HTTP レスポンス ヘッダーをすべて表示する
        for (i = 0; i < header->GetSize(); ++i) {
            TRACE("%s: %s", header->GetKey(i).GetCString(), 
                  header->GetValue(i).GetCString());
        }

        if (_http.GetResultCode() == 200) {

            // データ受信用ストリームを取得する
            if ((error = _http.GetStreamReader(1024, &_reader))
                == SFERR_NO_ERROR) {

                // フェッチ(データ受信)する
                // データ受信が完了すると、OnFetch 関数に通知される
                if ((error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch)))
                    == SFERR_NO_ERROR) {
                    ...
                }
            }
        }
        else {
            error = SFERR_INVALID_STATE;
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
       _http.Close();
    }
    return;
}

// フェッチ(データ受信)が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error)
{
    SFXAnsiString string;

    if (error == SFERR_NO_ERROR) {

        // データ受信用ストリームからデータを取得する
        if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) {

            // 断片化されたデータを結合する
            if ((error = _receivedString.Add(string)) == SFERR_NO_ERROR) {

                // 残りのデータをチェックする
                if (_reader.Ends()) {

                    // すべてのデータが受信できたので表示する
                    TRACE("--------");
                    TRACE("%s", _receivedString.GetCString());
                    TRACE("--------");

                    // 明示的にリソースを解放する
                    _reader.Release();
                    _http.Close();
                }
                else {

                    // フェッチ(データ受信)する
                    // データ受信が完了すると、OnFetch 関数に通知される
                    error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch));
                }
            }
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
        _reader.Release();
        _http.Close();
    }
    return;
      

独自にルート証明書を追加して https 通信を行う方法

https 通信を行うとき、サーバ証明書が使用するCA証明書が SSLROOTCERTS クラスに含まれない場合、BREW アプリ側で独自にルート証明書を追加する必要があります。

SophiaFramework UNIVERSE では、以下のようにして https 通信を行います。

  1. SFBX509Chain インスタンスを生成します。
  2. SFXFile , SFXPath , SFXBinaryStreamReader , SFXBuffer クラスを使って、DERエンコードされたCA証明書をバイナリデータとして読み込みます。
  3. SFBX509Chain::AddCert 関数を呼び出して、[1] で生成した SFBX509Chain インスタンスにWEBOPT_X509_ROOT_CERTS (ルート認証機関の証明書) として [2] で読み込んだ証明書(バイナリ形式)をセットします。
  4. SFXHTTPConnection::Open 関数を呼び出して https 通信をオープンします。
  5. SFXHTTPConnection::SetTrustMode 関数を呼び出して、認証モードを "SSL_TRUST_MODE_FAIL" に設定します。
  6. SFXHTTPConnection インスタンスが内部に保持する SFBWeb インスタンスを取得します。
  7. SFBWeb::AddOpt 関数を呼び出して、SFBWeb インスタンスにWEBOPT_DEFAULTSとして[1]で生成した SFBX509Chain インスタンスを追加します。
  8. SFXHTTPConnection::Connect 関数を呼び出して、https 接続を行い、以下 https プロトコルでデータ通信を行います。
  9. 最後に、SFXHTTPConnection::Close 関数を呼び出して https 通信をクローズします。

具体的なコードについては、下記のサンプルコードをご覧ください。

サンプルコードダウンロード( httpsapp.zip: 21.3kb )

(注)CA証明書読み込み時のバッファ(  SFXBuffer )および SFBX509Chain インスタンスを明示的に解放する場合は、SFXHTTPConnection::Close 関数呼出し後に行わなければいけません。そのため、CA証明書の読み込みおよび SFBX509Chain インスタンスの生成は、SFXHTTPConnection::Open 関数呼び出し前に行うことを推奨します。
      

BREW 3.1 端末でHTTPS 通信を高速化する方法

QUALCOMM 社の情報によりますと、 BREW3.1.2 以前の実装では、ISSL インターフェースが過剰にパケットを細分化するため HTTPS 通信のパフォーマンスが劣化するらしいです。(参照:関連情報)

この問題を解決するためには、 下記のように SFXHTTPConnection クラスを開いてから接続するまでの間に、 SFXHTTPConnection クラスが内部で保持する SFBWeb インスタンスを取得して、この問題が解決されている ISSL インターフェースのクラス ID「AEECLSID_SSL_101」を渡すようにします。

なお、関連情報には、 『本機能は利用例が少なく、十全な評価がされていないため、使用のリスクは御社でご判断下さい』とあります。

#include "AEESSL_WEBOPT_CLASSID.h"
#include "ISSL.bid"

_http.Open()

SFBWebOpts webopts = SFBWebOpts::NewInstance(&error);
WebOpt opt[2];
opt[0].nId = WEBOPT_SSL_CLASSID;
opt[0].pVal = (VoidPtr)AEECLSID_SSL_101;
opt[1].nId = WEBOPT_END;
opt[1].pVal = null;
webopts->AddOpt(opt);
SFBWebSmp web = _http.GetSFBWeb();
web->AddOpt(opt);

_http.Connect(url, XALLBACK_INTERNAL(OnConnect));

※ 接続時間が短縮されたもののフェッチに時間がかかる場合は、ストリームリーダーのバッファサイズを小さくしてみてください。たとえば、4096バイト(デフォルト)を2048バイトにすることで高速化された例があります。