ホーム > デベロッパ > BREW プログラミング入門 > HTTP ネットワークプログラミング > - 1 / 3 -

HTTP ネットワークプログラミング - 1 / 3 -

IWeb

IWeb は HTTP プロトコルを処理する BREW インターフェースです。URL などの HTTP 通信パラメーターを設定し、HTTP 通信をするコールバック関数を登録して、応答を待ちます。

アプリの概要

最初に、"Push Select Key..."と表示します。
セレクトキーが押されると、通信が開始します。HTTP 通信が終了すると、受け取った HTML データを表示します。

MIF ファイルの設定

MIF ファイルには「ネットワーク」と「 Web アクセス」の特権レベルを設定します。

MIF エディタ

準備

IWeb インターフェースを利用する際は、パラメーターが多いので構造体を利用して簡潔にコードを記述します。

■ アプレット構造体の宣言

typedef struct WebApp WebApp;

struct WebApp {
    AEEApplet a; // アプレット構造体の先頭メンバは必ず AEEApplet 型にすること。
    Common common; // 画面描画用

    IWeb* web;           // IWeb インターフェースのインスタンス変数
    WebAction webaction; // コールバック関数 WebAction_GotResp の引数
};

■ 通信用構造体の宣言

typedef struct WebAction {
    WebApp* parent;
    AEECallback callback;
    IWebResp* webresp; // IWebResp インターフェースのインスタンス変数
    IGetLine* getline; // IGetLine インターフェースのインスタンス変数
} WebAction;

※ その他 : " AEEWeb.h " ヘッダーファイルのインクルードが必要です。

IWeb インターフェースの初期化

ISHELL_CreateInstance 関数を使って IWeb インターフェースのインスタンスを生成します。

次に、IWEB_AddOpt 関数を使って、WebOpt 構造体の配列 webopts に HTTP 通信に必要なパラメータを設定します。( 参考 : IWeb インターフェースのオプション )

WebOpt 構造体はキーとその値のペアのリストで構成されます。以下のコードでは、タイムアウトのキー WEBOPT_CONNECTTIMEOUT を 10000 ミリ秒に設定しています。パラメーターの最後は WEBOPT_END で閉じます。

IWeb インターフェースを使って HTTP 通信した結果は、IWebResp インターフェースのインスタンス変数 webresp に格納されます。

// アプレットが開始したときに呼び出される。
static boolean OnAppStart(WebApp* app)
{
    IShell* shell = app->a.m_pIShell;
    IDisplay* display = app->a.m_pIDisplay;
    WebOpt webopts[2];

    app->web = NULL;
    ISHELL_CreateInstance(shell, AEECLSID_WEB, (void**)&app->web);

    // 接続のタイムアウト時間の設定 (ms)
    webopts[0].nId = WEBOPT_CONNECTTIMEOUT;
    webopts[0].pVal = (void*)10000;

    // WebOpt 終了マーク
    webopts[1].nId = WEBOPT_END;

    // オプション設定
    IWEB_AddOpt(app->web, webopts);

    app->webaction.parent = app;

    //(略)
    return TRUE;
}

HTTP 通信の開始

CALLBACK_Init マクロ関数を呼んで、コールバック関数 WebAction_GotResp とその引数を AEECallback 構造体 の変数 webaction->callback に設定します。

次に、IWEB_GetResponse マクロ関数を使って WebAction_GotResp 関数をコールバック関数として登録します。

※ IWEB_GetResponse マクロ関数の 2 つ目の引数はリスト構造になっています。マクロ関数なので、任意の数の引数が持てます。リスト構造の 2 つ目の引数のうち、url 以降が、IWeb インターフェースに渡すパラメータです。キーと値をセットにして、最後は WEBOPT_END とします。

// HTTP 通信開始
static void WebAction_Start(WebAction* webaction, char* url)
{
    WebApp* app = webaction->parent;

    CALLBACK_Init(&webaction->callback, WebAction_GotResp, webaction);
    IWEB_GetResponse(app->web,
                    (app->web, &webaction->webresp, &webaction->callback, url,
                    WEBOPT_HANDLERDATA, webaction,
                    WEBOPT_HEADER, "X-Method: GET\r\n",
                    WEBOPT_HEADERHANDLER, WebAction_Header,
                    WEBOPT_STATUSHANDLER, WebAction_Status,
                    WEBOPT_END));
    return;
}

■ IWeb インターフェースのオプション

IWeb インターフェースのオプション 意味
WEOPT_ACTIVEXACTIONS 同時 HTTP 通信の数
WEOPT_CONNECTTIMEOUT ソケット接続のタイムアウト ( 単位 : ミリ秒 )
WEOPT_CONTENTLENGTH HTTP リクエストとレスポンスの長さ
WEOPT_HANDLERDATA HTTP 通信のコールバック処理のためのデータ
WEOPT_HEADER HTTP リクエストのヘッダー
( 各フィールドは " CR " と " LF " で区切る )
WEOPT_HEADERHANDLER HTTP 通信のヘッダー情報を取得する関数
WEOPT_IDLECONNTIMEOUT 返答が無いときのタイムアウト ( 単位 : ミリ秒 )
WEOPT_METHOD HTTP リクエストのタイプ ( デフォルトは " GET " )
WEOPT_PROXYSPEC HTTP プロキシの指定
WEOPT_STATUSHANDLER HTTP 通信の状態を取得する関数
WEOPT_USERAGENT ユーザーエージェント

WEBOPT_HEADERHANDLER

WEBOPT_HEADERHANDLER に設定された WebAction_Header 関数は、WEBOPT_HANDLERDATA の値 webaction、HTTP ヘッダーにあるパラメーターの名前と値を引数として呼び出されます。

WebAction_Header 関数は、HTTP リクエストヘッダーの名前と値を表示します。

// ヘッダー処理
static void WebAction_Header(void* p, const char* name, GetLine* val)
{
    WebAction* webaction = (WebAction*)p;
    WebApp* app = webaction->parent;

    if (name != NULL) {
        COMMON_WriteString(&app->common, name);
        COMMON_WriteString(&app->common, ":");
        COMMON_WriteString(&app->common, val->psz);
        COMMON_WriteString(&app->common, "\n");
    }
    else {
        COMMON_WriteString(&app->common, val->psz);
        COMMON_WriteString(&app->common, "\n");
    }
    COMMON_Draw(&app->common);
    return;
}

WEBOPT_STATUSHANDLER

WEBOPT_STATUSHANDLER に設定された WebAction_Status 関数は、WEBOPT_HANDLERDATA の値 webaction、HTTP 通信の状態を表す WebStatus、void* 型の値を引数として呼び出されます。

WebAction_Status 関数は、HTTP 通信の状態を表示します。

// 状態取得
static void WebAction_Status(void* p, WebStatus webstatus, void* val)
{
    char* string = NULL;
    WebAction* webaction = (WebAction*)p;
    (void)val;

    switch (webstatus) {
        case WEBS_CANCELLED:
            string = "** cancelled...\n";
            break;

        case WEBS_GETHOSTBYNAME:
            string = "** finding host...\n";
            break;

        case WEBS_CONNECT:
            string = "** connecting...\n";
            break;

        case WEBS_SENDREQUEST:
            string = "** sending...\n";
            break;

        case WEBS_READRESPONSE:
            string = "** receiving...\n";
            break;

        case WEBS_GOTREDIRECT:
            string = "** redirect...\n";
            break;

        case WEBS_CACHEHIT:
            string = "** cache hit...\n";
            break;
    }
    if (string != NULL) {
        COMMON_WriteString(&webaction->parent->common, string);
        COMMON_Draw(&webaction->parent->common);
    }
    return;
}

■ WebStatus の種類とその内容

ステータス コード 意味
WEBS_STARTING 接続が開始している
WEBS_CANCELLED 接続がキャンセルされた
WEBS_GETHOSTBYNAME リモートホストの IP アドレスが取得している
WEBS_CONNECT IWeb インターフェースが接続した
WEBS_SENDREQUEST IWeb インターフェースがリクエストを送信中である
WEBS_READRESPONSE IWeb インターフェースがレスポンスを受信中である
WEBS_GOTREDIRECT IWeb インターフェースが別の URL へのリダイレクトを受信した
WEBS_CACHEHIT IWeb インターフェースがキャッシュヒットした

メッセージの受信

次はIWeb インターフェースによる HTTP 通信が終了した時に呼び出される、コールバック関数 WebAction_GotResp です。

IWEBRESP_GetInfo 関数を呼び出した時に設定される WebRespInfo 構造体のデータは次のような情報で構成されています。

typedef struct
{
    int         nCode;           // HTTP 通信の戻り値
    ISource*    pisMessage;      // 応答メッセージの内容
    long        lContentLenght;  // 応答メッセージの長さ
    const char* cpszContentType; // content-type の内容
    const char* cpszCharset;     // charset の内容
    int32       tExpires;        // 有効期限
    int32       tModified;       // 更新日時
} WebRespInfo;

応答メッセージを取得するために、 WebRespInfo 構造体の持つ ISource インターフェース のインスタンス pisMessage を ISourceUtil インターフェースで IGetLine インターフェースのインスタンスに変換します。

// メッセージの取得開始
static void WebAction_GotResp(void* p)
{
    WebAction* webaction = (WebAction*)p;
    WebApp* app = webaction->parent;
    WebRespInfo* info;
    char buffer[80];

    info = IWEBRESP_GetInfo(webaction->webresp);
    SPRINTF(buffer, "** got response...\n** info code: %d\n", info->nCode);
    COMMON_WriteString(&app->common, buffer);
    COMMON_Draw(&app->common);

    if (info->pisMessage != NULL) {
        ISourceUtil* util = NULL;

        ISHELL_CreateInstance(app->a.m_pIShell, AEECLSID_SOURCEUTIL,
            (void**)&util);
        ISOURCEUTIL_GetLineFromSource(util, info->pisMessage,
            1100, &webaction->getline);
        ISOURCEUTIL_Release(util);
    }
    if (webaction->getline != NULL) {
        WebAction_ReadLines(webaction);
    }
    else {
        COMMON_WriteString(&app->common, "** no response\n");
        COMMON_Draw(&app->common);
        WebAction_Stop(webaction);
    }
    return;
}

IGetLine インターフェースからの読み込み

IGetLine インターフェースはデータの構文解析を行うクラスで、読み込みの際に、ブロッキングが発生することもあります。

「今は読み込めないからまた後で」というような状況もありえます。

従って、WebAction_ReadLines 関数では自分自身をコールバック関数として登録します。

// メッセージ取得
static void WebAction_ReadLines(void* p)
{
    int value;
    GetLine getline;
    WebAction* webaction = (WebAction*)p;
    WebApp* app = webaction->parent;

    // 次の LF までを一行として、getline 構造体に読み込む。
    value = IGETLINE_GetLine(webaction->getline, &getline, IGETLINE_LF);
    if (value == IGETLINE_WAIT) {
        // ブロックされた場合は、コールバック関数として自分自身を再度登録する。
        CALLBACK_Init(&webaction->callback, WebAction_ReadLines, webaction);
        IGETLINE_Peekable(webaction->getline, &webaction->callback);
    }
    else {
        COMMON_WriteString(&app->common, getline.psz);
        COMMON_WriteString(&app->common, "\n");
        if (!IGETLINE_Exhausted(value)) {
            // 読み込みが完了していない場合も、コールバック登録
            CALLBACK_Init(&webaction->callback, WebAction_ReadLines, webaction);
            IGETLINE_Readable(webaction->getline, &webaction->callback);
        }
        else {
            // 読み込み完了
            COMMON_WriteString(&app->common,
                (value == IGETLINE_ERROR) ? ("\n** error\n") : ("\n** end\n"));
            COMMON_Draw(&app->common);
            WebAction_Stop(webaction);
        }
    }
    return;
}

最後に、コールバック関数 WebAction_ReadLines、WebAction_GotResp をキャンセルし、IWebResp インターフェースと IGetLine インターフェースを解放します。

// 通信終了
static void WebAction_Stop(WebAction* webaction)
{
    CALLBACK_Cancel(&webaction->callback);
    // 各種解放処理
    if (webaction->getline != NULL) {
       IGETLINE_Release(webaction->getline);
       webaction->getline = NULL;
    }
    if (webaction->webresp != NULL) {
       IWEBRESP_Release(webaction->webresp);
       webaction->webresp = NULL;
    }
    return;
}

※ WebAction_Stop 関数は、HTTP 通信の処理途中でエラーが発生してもサスペンドしても強制終了されても、この関数が呼ばれれば、コールバックはキャンセルされ、インターフェースも解放されるように設計されています。