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

- 最初に、"Push Select Key..."と表示します。

- セレクトキーが押されると、通信が開始します。HTTP 通信が終了すると、受け取った HTML データを表示します。
MIF ファイルの設定
MIF ファイルには「ネットワーク」と「 Web アクセス」の特権レベルを設定します。

関連情報:" 第 11 回 TCP / IP ネットワークプログラミング − 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 | ユーザーエージェント |
関連情報:" 第 11 回 TCP / IP ネットワークプログラミング − AEECallback 構造体 − "
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 通信の処理途中でエラーが発生してもサスペンドしても強制終了されても、この関数が呼ばれれば、コールバックはキャンセルされ、インターフェースも解放されるように設計されています。
関連情報:"第 17 回 サスペンドとレジューム"

















