先日、理解の薄いまま同じ内容で質問して、先生方に意見されまして、さらに勉強したのですが、やはりうまくいかず、改めて質問します。
自作VC++ブラウザからサーバー上の簡単なPerlのチャットCGIを操作するコードが分かりません。
チャットCGIのコードは、以下です。
<form action="$ENV{'SCRIPT_NAME'}" method="POST">
名前:<input type="text" name="name" size="40" value="$COOKIE{'name'}"><br>
電子メール:<input type="text" name="email" size="40" value="$COOKIE{'email'}"><br>
<input type="submit" value="参加する"><br>
<input type="hidden" name="mode" value="enter">
<input type="hidden" name="entry" value="$entry">
</form>
これで名前と電子メールアドレスを入力して、「参加する」ボタンを押し、
別なところで
if($FORM{'mode'} eq 'enter') {
を処理して、チャットルームに入室するようになっています。
この操作を自作ブラウザの側でやる方法を探しています。
ネットを探して、以下のVC++のサンプルコードを見つけました。
エディットボックスがふたつあり、その値、m_sValue1、m_sValue2を、Button1クリックにより、サーバー上のCGIに送っています。
void C***View::OnBnClickedButton1()
{
UpdateData();
CInternetSession cSession("HTTP Post Test App");
try
{
// 変数やら何やら用意
CHttpConnection *pConn;
CHttpFile *pFile;
CString sServer, sObject, sData, sTemp, sHeader;
INTERNET_PORT nPort;
DWORD dwServiceType;
// URLからサーバ名とかを取り出す
::AfxParseURL(m_sURL, dwServiceType, sServer, sObject, nPort);
// サーバに対してHTTP接続を開く
pConn = cSession.GetHttpConnection(sServer, nPort);
// http接続を開く
pFile = pConn->OpenRequest("POST", sObject);
// データをURLEncodeする
sData.Format("%s=%s&%s=%s",
URLEncode("value1"), URLEncode(m_sValue1),
URLEncode("value2"), URLEncode(m_sValue2));
// ヘッダを用意する
sHeader = "Content-type: application/x-www-form-urlencoded";
// ヘッダとデータを送る
pFile->SendRequest(sHeader, (LPVOID)((LPCTSTR)sData), sData.GetLength());
}
catch(CInternetException *pEx)
{
//省略
}
UpdateData(FALSE);
}
しかしこれですと、VC++のアプリは、Button1をクリックした時に、m_sValue1、m_sValue2の値をsDataにまとめて、ヘッダ付きでサーバーに送っているだけです。
受けたCGI側がどうなっているのかと思い、IEでソースを見ようとしたのですが、なぜか見えませんでした。
まず、チャットCGI側では、この値をどのようなコードで、変数に受け取ったらいいのでしょうか。
次に、この例でいって、m_sValue1とm_sValue2に入力した名前と電子メールアドレスの値を、CGIの"name"と"email"に代入し、
"mode"を"enter"に、"entry"を"$entry"にすればいい、という理解でいいのでしょうか。
ご指導をお願いいたします。
なんだか、状況がよくわかりません。
ブラウザを自作するというのはわかりましたが
サーバ側(CGI)は自作ではないのですか?
そのCGIはIEなどの既存のブラウザでは問題なく操作できるのですか?
もし、問題なく操作できるのでしたらCGI側での変数の受取り方云々なんて質問は出そうもない→修正すべきはCGIではなく自作ブラウザの側! だと思うのですが、
そうすると自作CGIでもなく、だけど一般のブラウザで操作できないCGIって一体何者なんだろうと頭の中がハテナでいっぱいです。
以上は私の中の常識の範囲内で答えていますが…
作エムさんが開発を行っている特殊な環境というのがよくわからない→何が出来て何が出来ないのかわからない→経験や常識が通用するのかしないのか。
その辺が整理できていないと的外れな回答や逆質問が続くことになりそうです。
最終的にやりたいことは、サーバー上のチャットCGIを、VC++アプリで動かすことです。
チャットに、普通にIEで開いて参加できるだけでなく、専用のVC++アプリからも参加できるように、VC++アプリと、チャットCGIをワンセットで作ろうとしています。
なぜ、VC++アプリが必要かというと、身体的にIEを操作できない人もチャットに参加するためです。
そのために、CGIとVC++アプリの間で、データのやりとりをし、VC++アプリからCGIを動かさないといけません。
CGIのデータをVC++アプリに取り込むことは成功しました。
今、悩んでいるのは、逆にVC++アプリからCGIにデータを送ることです。
ネット上に関連サイトがあり、サンプルも開発環境のままついているのですが、肝心のCGI側のコードが公開されていません。
そのため、データを送る方法は分かるけれど、受け取り方が分からない、という情けない状態になってしまいました。
具体的には、上記コードでいって、
sHeader = "Content-type: application/x-www-form-urlencoded";
pFile->SendRequest(sHeader, (LPVOID)((LPCTSTR)sData), sData.GetLength());
でVC++アプリからCGIに送った「値」をCGI側で使うのに、CGI側では、どのようなコードで、どのようにして特定の変数に収納するのか、が判りません。
つまり、VC++側でm_sValue1とm_sValue2に収納されていて、sDataにまとめてCGIに送った値を、CGI側で、$VALUE1 と、$VALUE2(変数名はどうでもいいのですが)に「再現」するコードです。
これで説明になりますでしょうか。
前回VC++サンプルのエンコードの部分をあげていませんでしたので、それも添付します。
CString CHTTPPostTestDlg::URLEncode(LPCSTR pszSrc)
{
// pszSrc は正しい文字列である
ASSERT(AfxIsValidString(pszSrc));
CString strURL;
for (int i = 0; pszSrc[i] != '\0' ; i++)
{
CString strChar;
// 英数字 _ . - は変換しないでそのまま
if (isalnum((BYTE)pszSrc[i]) || pszSrc[i] == '_' || pszSrc[i] == '.' || pszSrc[i] == '-')
{
strChar = pszSrc[i];
}
// スペースは + に変換
else if (pszSrc[i] == ' ')
{
strChar = '+';
}
// それ以外は %3B のような形式に変換
else
{
strChar.Format("%%%02X", (BYTE)pszSrc[i]);
}
strURL += strChar;
}
return strURL;
}
もちろん、その先にVC++でCGIを操作する方法、つまりVC++アプリのボタンを押すと、入室画面を飛ばしてチャットルームに入室し、文字をキーボードに打ち込んで別なボタンを押すと発言できる、方法も未解決なのですが、まだそこまで考える余裕がありません。
VC++アプリのインターフェースについては、だいたい解決済みです。
申し訳ありませんが、ご教授いただけませんでしょうか。
申し訳ありません。また「回答」で送信してしまいました。
>でVC++アプリからCGIに送った「値」をCGI側で使うのに、CGI側では、どのようなコードで、どのようにして特定の変数に収納するのか、が判りません。
逆に、VC++ではどのようか形で値をCGIに送っているのでしょう?
このフォーマットはある程度フリーだから、CGI側はそのフォーマットに
合わせて取り込めば良いので?
何がわからないのかが、やはりわからない…
CGIってそもそもPerl?
Perlなら、デコード処理じゃないですかね?
でも、初歩の初歩だしな。
こんなところで悩んでいるとも思えないし…
# この手の開発を行う場合は、
# sniffという系統のリクエスト、レスポンスなどを表示してくれるソフトを介在させておくと何かと便利です。
やろうとしているフォームは決まっているみたいなので、
それに、ひとつひとつ対応させれば良いと思いますよ。
m_sURLには、$ENV{'SCRIPT_NAME'}に対応するURL
URLEncode("valueX"), URLEncode(m_sValueX)には、4つ
"%s=%s&%s=%s&%s=%s&%s=%s"
→ name, $COOKIE{'name'}
→ email, $COOKIE{'email'}
→ mode, enter
→ entry, $entry
# 今回の内容を見る限り、type="submit"の部分は必要ないと思われます。
# 送り手のコードなので、キーとなるURLEncode("valueX")は処理を省いて、
# そのままのリテラル(nameなど)を%sさせれば良いと思われます。念のためしておくのも良いかも…
リクエストライン、リクエストヘッダの作成は、概ね問題ないと思いますが、
リクエストに対するレスポンスを処理している部分は、省いて提示しているのでしょうか?
だいたい、以下の様なリクエストを出していると理解しておくと良いかも…
pFile = pConn->OpenRequest("POST", sObject);
→ リクエストライン
POST $ENV{'SCRIPT_NAME'} HTTP/1.x
(略)
sHeader = "Content-type: application/x-www-form-urlencoded";
sData.Format("%s=%s&%s=%s", …
pFile->SendRequest(sHeader, (LPVOID)((LPCTSTR)sData), sData.GetLength());
→ リクエストヘッダ
Content-type: application/x-www-form-urlencoded
(略)
(ここの空行は意味あり)
name=$COOKIE{'name'}&mode=enter&…
# リファラやユーザエージェントを追加したい場合は、この間に追加します。
# せっかくなので、プライベートエージェント名を考えて追加してあげてください。
# ポストに関する部分は融通が利きますが、最初は遊ばないほうが良いでしょう。
受けてのPerlは、まずは単純に、
use CGI qw(:standard);
$name = param('name');
$mode = param('mode');
# この際、CGIをPerlにせず、Cで作成されたらどうでしょうか?
その方が、手馴れている分、やりやすいような気がします。
ほんのついで、
URLEncodeの処理は、よくやるんで256インデックステーブルを作成しておいてやってます。
# これに関しては、自分の好みですが…
# AfxIsValidStringしてるので問題ないですが、ループマックスも入れてます。
for (i = 0; pszSrc[i] && i < loop_max; i++) {
strURL += TBL_URLENCODE[pszSrc[i]];
// += だとまずいですね… ごっちゃになってきた …
}
if ( i == loop_max ) TooLong();
成功しました。
http://www.xxxx.xxx/foo.cgi?name1=value1&name2=value2
でURLを送ると、
$FORM{'name1'} eq "value1"
$FORM{'name2'} eq "value2"
となるんですね。
最初に「CGI超初心者です」と前フリするべきでした。
いかにもわざとらしいと思い、書かなかったのですが、かえって意味不明な質問になってしまいました。
お騒がせしまして、申し訳ありません。
ありがとうございました。
完了していますが、このまま放置するのはさすがにまずいので。
>>6
これ入室処理ですよね?URLを直接入力して入られるのはまずいとは思わなかったのでしょうか。