Web サイトとの対話

Curl アプレットは通常 Web サイトの一部ですが、アプレットと Web サイトの他の部分とのインタラクションが必要な場合がよくあります。たとえば、次のようなインタラクションが考えれられます。
この章ではアプレットと Web サイトの対話方法について説明します。
注意: この章に掲載されている多くの例は Web サイト上で表示しなければ適切な動作が確認できません。例のコードの下に表示されているリンクをクリックすると、Curl Web サイトで実際の動作を確認することかできます。この章にある対話型の例を実行するには Web サイトへのアクセスが必要であり、したがってインターネット接続が確立されている必要があります。

Web サイトのファイルを読む

要約:
  • Web サイトからファイルを読み取るのは、ローカル ファイル システムから読み取るのと同じです。
  • http: および https: スキーム の URL を使用して Web サーバーのファイルを読みます。
Curl® 実行環境 は、ディスクまたは他のリソースからファイルを読むのと同じ方法で Web サーバー上のリモート ファイルの読み取りをサポートします。ローカル ファイルと Web サーバーのファイルの読み取りで唯一異なる点は、ファイルへのアクセスに URL が使用されることです。
http: スキームを使用する URL は、HTTP (Hypertext Transfer Protocol) 経由で Web サーバーから取得されます。https: を使用する URL は、セキュア HTTP を使用して Web サーバーから取得されます。HTTPS はセキュア ソケット レイヤ (SSL) ネットワーク接続を使用して、データを暗号化して保護します。詳細は 「ファイルおよび他のリソースへのアクセス」 を参照してください。
http: または https: URL 上の TextInputStream を開くには read-open プロシージャを使用します。ByteInputStream を開くには read-open-byte プロシージャを使用します。file: URL とは異なり、http: および https: URL を開いてこれに書き込みや追加を行なうことはできません。
次のコードは Curl ホームページの HTML ソースを読み込んで TextFlowBox に表示します。
{value
   let web-buffer:TextFlowBox =
       {TextFlowBox width = 5in, border-width = 1pt,
           border-color = "black", margin = 2pt
       }
   let connect-button:CommandButton =
       {CommandButton
           label = "Get the Curl home page!",
           {on Action do
               {web-buffer.clear}
               let weburl:Url = {abs-url "http://www.curl.com"}
               let webdata:#TextInputStream
               {try
                   || Add the results to the TextFlowBox
                   set webdata = {read-open weburl}
                   || Keep getting stuff until there's no more
                   {until webdata.end-of-stream? do
                       {web-buffer.add {webdata.read-one-line}}
                       {web-buffer.add {br}}
                   }

                catch http-ex:HttpException do
                   {web-buffer.add
                       {text
                           color="red", Some sort of error
                           occurred connecting to {value weburl}:
                           {italic {value http-ex.value}}
                       }
                   }
                finally {if-non-null webdata then {webdata.close}}
               }
           }
       }
   {spaced-vbox
       connect-button,
       {text Results:},
       web-buffer
   }
}

上の例が Curl の Web サイトで動作しているのを確認することが出来ます。 デモページ から 「Accessing Files via HTTP」 を選択してください。
HttpFile クラスのメソッドにより、リクエスト メソッドやリクエスト ヘッダーの設定、リクエスト データの送信およびレスポンス ヘッダーへのアクセス機能など、Curl® アプレットをHTTP 上で制御することができます。次の例は前述の例のバリエーションです。この例では、URL のコンテンツの代わりにレスポンス ヘッダーを表示します。
HTTP URL の read-openHttpTextInputStream のインスタンスを返します。レスポンス ヘッダーは response-headers アクセッサを介して利用できます。同様に、HTTP URL の read-open-byteHttpByteInputStream のインスタンスを返します。HttpByteInputStream にも response-headers アクセッサがあります。
次のコードはレスポンス ヘッダーへのアクセスを示しています。
{value
    let web-buffer:TextFlowBox =
        {TextFlowBox width = 5in, border-width = 1pt,
            border-color = "black", margin = 2pt
        }
    let connect-button:CommandButton =
        {CommandButton
            label = "Get the Curl home page!",
            || when button is clicked ...
            {on Action do
                let web-url:Url = {abs-url "http://www.curl.com"}
                let http-file:HttpFile =
                    {web-url.instantiate-File} asa HttpFile
                || open the Url
                let web-stream:HttpTextInputStream =
                    {http-file.http-read-open
                        || don't redirect
                        auto-redirect? = false,
                        || return response headers even if error status
                        always-return-response-headers? = true}
                || display status
                {web-buffer.add
                    "Status: " &
                    web-stream.response-headers.status}
                || display response headers
                {for value:String key name:String in
                    web-stream.response-headers do
                    {web-buffer.add {br}}
                    {web-buffer.add
                        name &
                        {if value == "" then
                            ""
                         else
                            ": " & value}
                    }
                }
                {web-stream.close}
                web-buffer
            }
        }
    {spaced-vbox
        connect-button,
        {HBox {text Response Headers:}},
        {HBox width=5in, web-buffer}
    }
}
上の例が Curl Web サイトで動作するのを確認することが出来ます。デモページ から 「Accessing Response Header」 を選択してください。
非特権アプレットのファイル読み取り権限には制限があります。詳細は 「セキュリティ」 の章を参照してください。

Web フォームの作成

要約:
  • HttpForm クラスを使用して Web フォームを作成します。
  • name オプションが設定された HttpForm 内のコントロールは、Web サイトに送信されるリクエストの一部になります。
  • HttpForm.submit メソッドを呼び出してサイトにフォームを送信します。
  • HttpForm.reset を呼び出してフォーム上のコントロールを元の状態にリセットします。
  • データを検証するには、各コントロールで Submit イベントをキャッチしてコンテンツを確認します。
  • HttpForm.submit-open を使用して、Web サイトのレスポンス自体をアプレットに読み込みます。
  • Web サイトを直接クエリする場合、アプレットは HttpFormData オブジェクトを作成して Web サイトにリクエストを送信することができます。
Web サイトとのインタラクションでは、ユーザーが情報を記入するフォームを作成するのが一般的です。フォームの記入が完了すると、ブラウザはフォームのコンテンツ (リクエストと呼ばれます) を Web サイトに送信します。サイトはフォームの情報を受け取ってこれを処理し、検索結果、注文の確認などリクエストの目的に該当する内容を新規のドキュメントに挿入して応答します。ブラウザは次にこの結果を表示し、通常ここでフォームか置き換えられます。
Dialog のサブクラスである HttpForm クラスを使用して、Curl® 言語で Web フォームを作成することができます。 HttpForm を使用してフォームを作成するのは基本的に Dialog で作成するのと同じですが、Web フォームの作成には 2、3 の拡張機能が追加されています。ダイアログの使用方法については 「ダイアログの使用」 を参照してください。この章の以降のセクションでは、ダイアログの使用について理解されていることを前提に説明しています。

リクエストの種類

リクエストは、get または post のメソッドのいずれかを使用してブラウザから Web サイトに送信されます。get メソッドを使用してリクエストを送信する場合、このリクエストで使用する URL にリクエストのデータがエンコードされます。サーバー側スクリプトは URL からデータを抽出してデコードします。get メソッドはオーバーヘッドが比較的少ないため、フィールド数の少ないフォームによる簡単なリクエストによく使用されます。get メソッドでは大量のデータまたはバイナリ データを処理できません。これは、データのエンコード先の URL にサイズ制限があるからです。
post メソッドはフォームのデータをリクエスト本体にエンコードします。Post リクエストではバイナリ ファイルを含む大量のデータを処理できます。get に比べてこのメソッドは複雑なデコードを行なうため、Web サーバーに送信されるデータやリクエストへの応答によって Web サーバーから送信されるデータの量が増えることになります。

Web フォームとセキュリティ

セキュリティ上の理由から、アプレットによる Web サイトへの接続には制限が設けられています。Curl 実行環境 では、コンテンツへのアクセスを許可している Web サイトにのみアプレットから接続することができます。Web サイトは、接続可能なアプレットが記載されている curl-access.txt ファイルを使用してアクセス許可を設定します。
リクエストの送信先になる Web サイトには、アプレットのアクセスを許可する curl-access.txt を置く必要があります。curl-access.txt ファイルの説明については、 「アプレットから Web サイトへのアクセス」 を参照してください。

HttpForm クラス

HttpForm クラスは、web フォームの一部であるコントロールを収めるコンテナの役割を果たします。HttpForm オブジェクトのインスタンスを作成する際に、リクエストを受信する Web サイト上の CGI プログラムの URL を指定します。
{HttpForm.default form-action:Url, method:HttpRequestMethod=HttpRequestMethod.get, encoding:String=HttpFormData.urlencoded-mime-type, target:String="_self", default-character-encoding:CharEncoding=CharEncoding.ascii, ...}
action パラメータ (CGI スクリプトの URL) のみ必要です。HttpForm コンストラクタに渡すことができるオプションのパラメータは次のとおりです。
パラメータ名有効値目的
methodHttpRequestMethod.get または HttpRequestMethod.postコントロールの値を送信するためにフォームが使用するリクエスト メソッドです。get は URL の一部として値を送信します。 post はリクエストの HTTP ヘッダーに値を格納して送信します。
encodingHttpFormData.urlencoded-mime-type または HttpFormData.multipart-mime-typeデータのエンコード方法を制御します。リクエスト内ではデータとして許可されない文字があり、これらを送信する場合はエンコードが必要になります。通常エンコーディングはリクエスト メソッドに依存します。get リクエストは常に urlencoded-mime-type を使用する必要があります。post リクエストの制限は少ないので、 multipart-mime-type が使用するのが一般的です。post リクエストにファイルが含まれる場合、 multipart-mime-type を使用する必要があります。これは、url-encoding ではバイナリ データが処理できないためです。選択したメソッドは、サーバー側スクリプトでこれを受け取る必要があります。
target
_self
_blank
_parent
_top
リクエストの結果がどこに表示されるかを制御します。

default-character-encodingCharEncodingフォーム内のテキストに使用するエンコーディング メソッドです。フォームに入力される情報が拡張文字セット (英語以外の言語) を必要としないと考えられる場合、既定の CharEncoding.ascii をそのまま指定します。選択したエンコーディングは、リクエストを処理するサーバー側スクリプトでこれを受け取る必要があります。
HttpForm オブジェクトに TextField および DropdownList などのコントロールを配置して、ユーザーがリクエストの情報を記入できるようにします (コントロールの完全なリストについては下記の 「フォームの値」 を参照してください)。name ローカル オプションが設定されたコントロールは、すべてリクエストの一部として Web サイトにコンテンツを送信します。name 属性は、CGI スクリプトに送信されるパラメータ名として使用されます。リクエストの一部として送信される各コントロールの値は、コントロールの form-value アクセッサから取得されます。ほとんどのコントロールでは、これはコントロールの value アクセッサと基本的に同じです。コントロールの値の決定方法の詳細は、「フォームの値」を参照してください。
注意: HttpForm に追加されるときに name ローカル オプションが設定されているコントロールだけがリクエストの一部になります。フォームに追加した後でコントロールの name オプションを設定しても効果はありません。
フォームの HttpForm.submit メソッドを呼び出すと、フォームが Web サイトに送信されます。
次のコードは、1 つのフィールドで構成される非常に単純な Web フォームを示しています。
{HttpForm
    {url "http://www.curl.com/cgi-bin/list-parameters.pl"},
    target="_blank",
    {spaced-hbox
        {text Your name:},
        {TextField name="name"},
        {reset-button},
        {submit-button}
    }
}
上の例のコードで作成されるフォームを次に示します。


Figure: 単一フィールドの Web フォーム
このフォームが Curl Web サイトで動作しているのを確認することが出来ます。デモページ から 「A Simple Form」 を選択してください。
上の例では、CGI スクリプトは name と呼ばれる単一フォームのパラメータを受け取ります。このパラメータは、ユーザーが TextField に入力した値に設定されています。
reset-button プロシージャは CommandButton を返し、次にこれが含まれるフォームの HttpForm.reset メソッドが呼び出されます。reset メソッドは強制的にフォーム内のすべてのコントロールを既定値に戻します。これは HTML ベースのフォームのリセット ボタンと同じ効果があります。同様に、submit-button プロシージャはこれが含まれるフォームの HttpForm.submit メソッドを呼び出す CommandButton を返します。単純な Web フォームではユーザーが入力したデータを Web サイトに送信する前にチェックする必要がないので、これらのボタンを使用するだけで十分です。

フォームの値

先に述べたように、name 属性を持つ HttpForm 内のすべてのコントロールは、この値をフォームの送信時に Web サイトに送信します。Web サイトに送信される値はコントロールの value アクセッサではありません。コントロールの form-value が使用されます。次の表は、HttpForm 内のコントロールの種類と値の設定方法を示しています。
コントロールの種類form-value
TextFieldcontrol-name.value
PasswordFieldcontrol-name.value
TextDisplaycontrol-name.value
CheckButton
チェックされる場合は control-name.check-value
チェックされない場合は null
RadioFrame{form-string control-name.value}
RadioButtonnull。フォームで送信される値は RadioFrame で指定します。
DropdownList{form-string control-name.value}
ColorDropdown{form-string control-name.value}
ListBox
何も選択されない場合は null
1 つのアイテムが選択される場合は {form-string control-name.value}
複数のアイテムが選択される場合、各アイテムは form-string を使用して String に変換されます。値はすべて StringArray として送信されます。
次の例は、各種コントロールの form-value アクセッサが返す値を示します。

例: form-value が返す値
{let text-field-display:TextDisplay = {TextDisplay}}
{let check-button-display:TextDisplay = {TextDisplay}}
{let radio-frame-display:TextDisplay = {TextDisplay}}
{let dropdownlist-display:TextDisplay = {TextDisplay}}
{let listbox-display:TextDisplay = {TextDisplay}}
{let colordropdown-display:TextDisplay = {TextDisplay}}

{HttpForm
    {url "http://www.curl.com/"},
    {table
        width=5in,
        {row
            {cell TextField:
                {TextField
                    name="name",
                    {on ValueChanged at t:TextField do
                        || Set the display that appears next
                        || to the control to the value that would
                        || be sent. This has no impact on what would
                        || be sent to the server if the form were
                        || submitted.
                        set text-field-display.value =
                            {if-non-null t.form-value then
                                t.form-value
                             else
                                "null"
                            }
                    }
                }
            }
            {cell form-value: {value text-field-display}}
        }
        {row
            {cell
                {CheckButton
                    label="CheckButton",
                    name="check-button",
                    check-value="Button Checked",
                    {on ValueChanged at c:CheckButton do
                        set check-button-display.value =
                            {if-non-null c.form-value then
                                c.form-value
                             else
                                "null"
                            }
                    }
                }
            }
            {cell form-value: {value check-button-display}}
        }
        {row
            {cell RadioFrame:
                {RadioFrame name = "radio-button",
                    {VBox
                        {RadioButton radio-value = "Button 1"},
                        {RadioButton radio-value = "Button 2"},
                        {RadioButton radio-value = "Button 3"},
                        {RadioButton radio-value = "Button 4"}
                    },
                    {on ValueChanged at r:RadioFrame do
                        set radio-frame-display.value =
                            {if-non-null r.form-value then
                                r.form-value
                             else
                                "null"
                            }
                    }
                }
            }
            {cell form-value: {value radio-frame-display}}
        }
        {row
            {cell DropdownList:
                {DropdownList
                    name="drop-down-list",
                    {ListValueItem value="bold", {bold bold}},
                    {ListValueItem value="italic", {italic italic}},
                    {ListValueItem value="underline", {underline underline}},
                    {on ValueChanged at d:DropdownList do
                        set dropdownlist-display.value =
                            {if-non-null d.form-value then
                                d.form-value
                             else
                                "null"
                            }
                    }
                }
            }
            {cell form-value: {value dropdownlist-display}}
        }
        {row
            {cell ColorDropdown:
                {ColorDropdown
                    name="color-drop-down",
                    {on ValueChanged at cd:ColorDropdown do
                        set colordropdown-display.value =
                            {if-non-null cd.form-value then
                                cd.form-value
                         else
                                "null"
                            }
                    }
                }
            }
            {cell form-value: {value colordropdown-display}}
        }
        {row
            {cell ListBox:
                {ListBox
                    height=48pt,
                    name="listbox",
                    "Item 1", "Item 2", "Item 3", "Item 4",
                    {on ValueChanged at l:ListBox do
                        set listbox-display.value =
                            {if-non-null l.form-value then
                                let buf:StringBuf = {StringBuf}
                                || Get the strings from the array
                                {for s:String in l.form-value do
                                    {buf.concat s & " "}
                                }
                                {buf.to-String}
                             else
                                "null"
                            }

                    }
                }
            }
            {cell form-value: {value listbox-display}}
        }

        {row
            {cell {reset-button}}
        }
    }
}

フォームのコンテンツの検証

Curl 言語を使用して Web フォームを作成する利点の 1 つに、サーバーに送信する前にそのデータを簡単にチェックできることがあげられます。可能な範囲のデータ検証をクライアント側で実行することにより、CGI スクリプトが情報の欠落や修正をユーザーに要求するための応答回数を削減することができます。
フォームの最も簡単なデータ検証方法は、送信前にコンテンツの検証が必要な各フィールドで Commit イベントをキャッチすることです。このイベントは、フォームの送信時に HttpForm の各コントロールで発生します。コントロールのコンテンツに欠落または誤りがある場合は、フォームが Web サイトに送信されないように例外をスローします。
フォーム上のコントロールがスローした例外をキャッチするには、submit-button プロシージャで送信ボタンが作成される方法に依存せず、カスタムの送信ボタンを作成する必要があります。実際のところ、簡単に作成できます。CommandButtonAction イベント内で、フォームの HttpForm.submit メソッド呼び出しに try ブロックをラップするだけです (次の例を参照してください)。
Web フォーム内のコントロールはすべて form アクセッサを使用して、これらを格納している HttpForm オブジェクトにアクセスすることができます。HttpForm にないコントロールでこのアクセッサを読み取ろうとするとエラーが発生します。このエラーの発生は、特定の Web フォームにボタンを関連付ける必要がないということにつながり、したがって独自のボタンを作成する場合に非常に役に立ちます。
次のコードでは、フォームにコントロールを配置して、送信が許可される前にコントロールがコンテンツを検証します。この例では、フィールドがスローする例外をその他の可能な例外と区別するために、カスタム例外クラスが定義されています。
|| Define an exception that the fields can throw.
{define-class public HttpFieldException {inherits Exception}
  {constructor public {default message:String}
    {construct-super message}
  }
}

{HttpForm
    {url "http://www.curl.com/cgi-bin/list-parameters.pl"},
    {spaced-vbox
        halign="right",
        {spaced-hbox
            {text Name:},
            {TextField
                name="name",
                || When user submits the form, check to ensure
                || field has content.
                {on Commit at f:TextField do
                    {if f.value.empty? then
                        {throw
                            {HttpFieldException
                                "Name field must have a value."
                            }
                        }
                    }
                }
            }
        },
        {HBox
            {reset-button},
            {Fill},
            {CommandButton
                label="Submit",
                {on Action at s:CommandButton do
                    {try
                        {s.form.submit}
                     catch e:HttpFieldException do
                        {popup-message
                            {text There is a problem with
                                the form: {value e}.
                            }
                        }
                     catch e:HttpException do
                        {popup-message
                            {text An error occurred while submitting
                                the form: {value e}
                            }
                        }
                    }
                }
            }
        }
    }
}
Curl Web サイトで上の例が動作しているのを確認することが出来ます。デモページ から 「A Data-validating Form」 を選択してください。
各コントロール自体で検証が行なわれるため、このようなフォームのコンテンツの検証方法には柔軟性があります。さらに、フィールドに新規コントロールを追加する際に送信ボタンのコードを変更する必要はありません。

送信ボタンのないフォーム

HttpForm オブジェクト内のコントロールの form アクセッサを使用して、ユーザーがコントロールに値を入力すると送信されるフォームを作成することができます。たとえば、ユーザーが検索用語を入力して enter キーを押すと送信される検索フォームを作成することができます。この場合、コントロールが ActionValueFinished、またはその他のイベントを受け取ったときにフォームが送信されるようにします。
次のコードは、ユーザーが enter キーを押すと送信されるアプレット内の検索フィールドを作成する方法を示します。
{HttpForm
    {url "http://www.curl.com/cgi-bin/list-parameters.pl"},
    margin=4pt,
    {spaced-hbox
        {text Search:},
        {TextField
            name="search-term",
            {on Action at t:TextField do
                {t.form.submit}
            }
        }
    }
}
上の例が Curl Web サイトで動作しているのを確認することが出来ます。デモページ から 「A Form Without a Submit Button」 を選択してください。

フォームによるファイルの送信

コントロールの値だけでなく、HttpForm オブジェクトでは Web サイトへのリクエストとしてファイルのコンテンツを送信することもできます。この機能により、クライアント システムから Web サイトに写真、履歴書やその他のファイルをアップロードするアプレットを作成することができます。
HttpForm がサイトに送信するデータにファイルを追加するには、 add-file メソッドを呼び出してそれにパラメータ名およびファイルの URL を渡します。ファイル名は自動的にファイル データと一緒に送信されます。または、 add-file-data メソッドを呼び出してこれにパラメータ名、ファイル名およびファイルのデータを格納する {Array-of byte} を指定することによって、バイト配列をファイルとして送信することもできます。このメソッドは、アプレットがすでにファイルをメモリに読み込んでいる場合 (イメージにフィルタが適用されている場合など) に有効です。
非特権アプレットは、ユーザーからアクセス権が与えられている場合のみローカル ファイルにアクセスできます。ここでは、アップロードするファイルへのアクセス権を得るためにアプレットは通常 choose-filechoose-multiple-files または choose-location を呼び出します。アプレットのセキュリティの詳細については、「セキュリティ」の章を参照してください。標準のファイル ダイアログの使用方法については、「ファイル ダイアログの作成」を参照してください。
ファイル データは URL 内でエンコードできないことから、フォームの一部としてファイルを送信する場合は、post 送信メソッドを使用してコンテンツをマルチーパート エンコーディングでエンコードする必要があります。
次のコードでは、単一のユーザー指定ファイルを含むリクエストの送信フォームを作成しています。ユーザーは送信するファイルを選択するのに Choose File ボタンをクリックします。このボタンは choose-file を呼び出し、結果を file-url 変数に格納します。ユーザーが Submit ボタンを押すと、フォームの add-file メソッドが呼び出され、選択したファイルがフォームに追加されます。
|| Holds the URL of the file the user wants to upload
{let my-file-url:#Url}
{let submit-button:CommandButton =
    {CommandButton
        enabled?=false,
        label="Submit",
        {on Action do
            || Add the file to the form
            {submit-button.form.add-file
                "uploaded-file",
                || will not be null when Submit button is enabled
                {non-null my-file-url}
            }
            || Submit the request
            {submit-button.form.submit}
            set submit-button.enabled? = false
            set submit-button.label = "Submit"
            {submit-button.form.reset}
        }
    }
}

{HttpForm
    {url "http://www.curl.com/cgi-bin/file-upload.pl"},
    margin=6pt,
    method=HttpRequestMethod.post,
    encoding=HttpFormData.multipart-mime-type,
    {spaced-hbox
        {CommandButton
            border-style=BorderStyle.raised,
            label="Choose File",
            || Ask the user for a file.
            {on Action do
                set my-file-url =
                    {choose-file title="Select a file to upload"}
                {if-non-null my-file-url then
                    || Display the name of the selected file
                    set submit-button.label = "Submit " & my-file-url.name
                    set submit-button.enabled? = true
                }
            }
        },
        submit-button
    }
}
上の例が Curl Web サイトで動作しているのを確認することが出来ます。デモページ から 「A Form That Uploads Files」 を選択してください。

リクエストの結果を読む

前述の Web フォームの例では、リクエストに対する Web サイトの応答はブラウザに返送され、既存のコンテンツ (フォームを含む Curl アプレット) をこれに置き換えています。この応答は通常 HTML ページですが、動的に生成された Curl アプレット、イメージまたはブラウザで処理できるその他のファイルである場合もあります。このリクエストとレスポンスのサイクルは、HTML フォームを使用する場合と基本的に同じです。
より高度なアプリケーションでは、Curl アプレットでリクエストを送信して、結果を同じアプレットに読み取らせることができます。アプレットでは、任意の方法で結果を表示することができます。このメソッドの使用では変更が必要なコンテンツが常に更新されることから、円滑なアプレット環境をユーザーに提供することができます。
リクエストの結果を読み取るには、アプレットは submit ではなく HttpForm.submit-open を呼び出してリクエストを Web サイトに送信する必要があります。サーバーからの結果がテキストではなくバイナリ データ (イメージなど) である可能性がある場合は、アプレットは HttpForm.submit-open-byte を使用する必要があります。これらのメソッドは入力ストリーム (HttpTextInputStream または HttpByteInputStream) を返し、アプレットはここから Web サーバーの返送結果を読み取ります。
次の例では、スクリプトにリクエストを送信して結果を読み取っています。Web サイトからの応答は HTML コードになり、TextFlowBox に示されます。

例: リクエストの結果の読み取り
{let results:TextFlowBox = {TextFlowBox}}

{HttpForm
    {url "http://www.curl.com/cgi-bin/list-parameters.pl"},
    {spaced-hbox
        {text Search:},
        {TextField
            name="search-term",
            {on Action at t:TextField do
                || Clear out the results
                {results.clear}
                || Send request and read results
            let reply:#HttpTextInputStream
                {try
                    set reply = {t.form.submit-open}
                    {results.add {reply.read-one-string}}

                 catch e:Exception do
                    {results.add
                        {text An error occurred while contacting the
                            server. The error was {italic {value e.value}}
                        }
                    }
                }
            }
        }
    }
}
{value results}

Web サイトを直接にクエリする

フォームでのユーザー入力を必要とせずに、アプレットがリクエストを Web サイトに直接送信することができます。HttpFormData オブジェクトを作成し、リクエストのパラメータをこのオブジェクトに追加することにより、アプレットは直接リクエストを作成します。次にアプレットは Applet.browse-url-post または HttpFile.http-read-open を呼び出して、Web サイトにリクエストを送信します。Applet オブジェクトについては、「ブラウザとの対話」の章で説明されています。
HttpFormData はコレクションのようなクラスで、HttpFormData.append を使用してこのクラスにパラメータ名および 1 つ以上の値を追加します。各パラメータは HttpFormBytesParamHttpFormFilesParam または HttpFormStringParam のいずれかのインスタンスで表されます。すべてのパラメータを HttpFormData オブジェクトに追加したら、これを Applet.browse-url-post または HttpFile.http-read-open メソッドにパラメータとして渡します。
Applet.browse-url-post メソッドは Applet.browse-url と同じように動作しますが、HttpFormData パラメータがあり、これを Web サイトに送信する点で異なります。Applet.browse-url 呼び出しの場合と同様に、Web サイトの応答によりブラウザ内のアプレットが更新されます。
次の例では、HttpFormData および Applet.browse-url-post を使用してリクエストを Web サイトに送信します。
|| Create a single String parameter for the request
{let request-param:HttpFormStringParam =
    {HttpFormStringParam
        "search-query", "curl"
    }
}

|| Create the form data and add the parameter to it.
{let my-request:HttpFormData =
    {HttpFormData}
}

{my-request.append request-param}

|| Call browse-url-form when user clicks a button

{CommandButton
    label="Click me!",
    {on Action do
        {{get-the-applet}.browse-url-post
            || This is the URL we are sending the request to (usually
            || some sort of CGI script)
            {url "http://www.curl.com/cgi-bin/list-parameters.pl"},
            my-request
        }
    }
}
上の例が Curl Web サイトで動作しているのを確認することが出来ます。デモページ から 「Directly Querying Web Sites」 を選択してください。
HttpFormData オブジェクトのコンテンツからクエリ文字列を作成して URL に含めるには、オブジェクトの request-data-urlencoded-string メソッドを呼び出します。Url.set-query を呼び出して、このメソッドが返すクエリ文字列を Url に追加します。次に read-open を使用して、URL エンコードのリクエストを処理する CGI スクリプトからのストリームを開きます。

HTTP Cookie へのアクセス

Web サイトでは、クライアント システムのブラウザが cookie と呼ばれる少量の情報を格納するように設定する場合がよくあります。Cookie は HTTP リクエストのヘッダーに定義されます。セッションの識別やユーザー名など、リクエスト間の状態を保持するのに使用されます。HTML ベースの Web アプリケーションでは、Web サーバーへのリクエスト間の状態を保持するのにこの方法を使用するのが一般的です。cookie を使用して、サーバーはクライアントからのリクエストを進行中のセッションに関連付けることができます。
Curl アプレットでは、情報を保持するために cookie に依存する必要がありません。通常、ブラウザは最初にサイトからアプレットをロードし、ユーザーが作業を完了するまでアプレットは実行を続けます。アプレットはセッション間の少量のデータを格納するのにパーシスタント データを使用し、これによりユーザーが最後にアプレットを実行したときの設定を回復することができます。
ただし、他のページが設定した cookie にアクセスしたり、他のページからアクセス可能な cookie を作成できると便利な場合があります。cookie へのアクセスにより、HTML ベースのサーバー側アプリケーションから Curl ベースのアプリケーションへの移行、またはその逆の移行をシームレスに行なうことができます。 さらに、アプレットは cookie に格納されている既存のデータを利用することもできます。
cookie は HTTP リクエストのヘッダーの一部なので、ブラウザから Web サイトにこれを送信して、HTML ドキュメントだけでなく Web サイト上の任意のファイルをリクエストすることができます。Cookie は、ブラウザがイメージ、データ ファイル、Curl アプレットを要求するとき、または cookie で有効な任意のリクエストに対して送信されます。
ユーザーは、特定のcookieもしくは全てのcookieの受け入れを拒否するようにブラウザを設定していることがあります。あなたのWebアプリケーションが動作する為に、cookieを受け入れてもらうことが必要な場合には、ユーザーにその旨を伝える必要があります。

Cookie へのアクセス

アプレットは get-http-cookies プロシージャを使用して、特定の URL をリクエストする際にブラウザが送信する cookie にアクセスすることができます。非特権アプレットの場合は、それ自体の URL のリクエストの一部としてブラウザが送信する cookie リスト、またはアプレットと同じディレクトリにあるファイルの URL にのみアクセスすることができます。セキュリティ対策の詳細は、「セキュリティ」の章を参照してください。
get-http-cookies を呼び出すと、URL のリクエスト時にブラウザが Web サイトに送信する cookie をすべて表す Array-of HttpCookie を返します。get-http-cookies によって返される配列内の各 HttpCookie には、cookie 名、値、有効期限および他の情報のフィールドが含まれます。cookie によっては、これらのフィールドがすべて含まれていないものもあります。ただし、すべての cookie 名と値は HttpCookie オブジェクトに格納されています。
次のコードでは、アプレット自体の URL をリクエストする際にブラウザが Web サイトに渡す cookie にアクセスします。
|| Get the cookies for this applet's URL.
{let cookies:{Array-of HttpCookie} =
    {get-http-cookies
        {get-the-applet}.url
    }
}

|| Table to list cookies in
{let cookie-list:Visual =
    {Table
        {row-prototype
            font-weight="bold",
            "Name",
            "Value",
            "Expiration"
        }
    }
}

{if cookies.empty? then
    || There were no cookies
    {set cookie-list = {text No cookie for you!}}
 else
    {for cookie:HttpCookie in cookies do
        {cookie-list.add
            {row-prototype
                cookie.name,
                cookie.value,
                || Expires and other fields may return null,
                || If expires means null, then this is a cookie
                || that only lasts until the current session
                || ends (i.e. user closes the browser).
                {if-non-null cookie.expires then
                    cookie.expires
                 else
                    {text Session-only}
                }
            }
        }
    }
}

{value cookie-list}
上記のコードが Curl Web サイトで動作しているのを確認することが出来ます。デモページから 「Getting Cookies」 を選択してください。

Cookie の設定

アプレットは set-secure-http-cookie および set-insecure-http-cookie を使用して HTTP cookie を設定することができます。set-secure-http-cookieプロシージャは、リクエスト時にセキュア HTTP 接続が使用される場合のみ、ブラウザが Web サイトに返送する cookie を設定します。この cookie はディスクに保存されません。set-insecure-http-cookie プロシージャでは、リクエスト時にセキュア接続が使用されるかどうかにかかわらず、ブラウザが常に Web サイトに返す cookie を設定します。
いずれの cookie 設定プロシージャも Url および HttpCookie を取ります。Url は有効な cookie の URL です。この URL を使用する任意のリクエスト、または URL で指定されたディレクトリの子ディレクトリからのリクエストに対して、ブラウザは Web サイトに cookie を返信します。URL に Web サイトのルート (すなわち http://www.example.com/) だけを指定する場合、サイトからのすべてのリクエストに対してブラウザが Web サイトに返す cookie が作成されます。
非特権アプレットについては cookie の取得に関する制限と同様に、アプレット自体を含むディレクトリ以外の URL に対して、cookie を設定することはできません。
{let cookie-name:TextField = {TextField}}
{let cookie-value:TextField = {TextField}}

{let change-it:CommandButton =
    {CommandButton
        label="Set cookie",
        {on Action do
            {if not (cookie-name.value.empty? or cookie-value.value.empty?)
             then
                || Construct the cookie
                let cookie:HttpCookie =
                    {HttpCookie
                        cookie-name.value,
                        cookie-value.value
                    }
                || Set the cookie so that the browser will
                || submit it to the server for any requests
                || under the applet's directory.
                {set-insecure-http-cookie
                    {get-the-applet}.url,
                    cookie
                }
                || Now load the applet that displays the
                || cookies.
                {{get-the-applet}.browse-url
                    {url "get-cookies.curl"}
                }
             else
                {popup-message
                    {text You must provide both a cookie name
                        and a value.}
                }
            }
        }
    }
}

|| Lay out the controls.
{VBox
    halign="right",
    {spaced-hbox {text Cookie name:}, cookie-name},
    {spaced-hbox {text Cookie value:}, cookie-value},
    {spaced-hbox {Fill},change-it}
}
Curl Web サイトで、上の例が動作しているのを確認することが出来ます。デモページ から 「Setting Cookies」 を選択して下さい。

ブラウザ常駐 HTTP

デフォルトでは、アプレットによる全てのHTTPに関連した呼び出しは、アプレットのプロセスで実行されます。この状況下においては、Curlアプレットは、ブラウザとcookieやログイン状態のような情報を共有する限られた能力しか持っていません。アプレットは、インターネット・エクスプローラとのみcookieを共有することが出来、他のブラウザとは共有できません。Curlアプレットは、将来日付の有効期限を持ったcookieのみインターネット・エクスプローラと共有することが出来ます。 このようなcookieはディスクに書き込まれ、アプレットと共有することが出来ます。
Curl RTE と IE7 との間で共有されている HTTP cookie は Vista 上ではそれ以前の Windows のオペレーティング システム上でのようには動作しません。cookie を共有するには、ユーザーは [Curl コントロール パネル][セキュリティ] タブを使用して web サイトのホストを特権を与えられたホストのリストにくわえなければなりません。この問題についての詳細な説明は、「Microsoft 社のサポート記事」をご覧ください。
インターネット・エクスプローラ以外のブラウザで実行されているアプレットは、パッケージのインポートやファイルやイメージのインクルードのようなアプレットが実行する全てのHTTPトランザクションのヘッダ内にWebサイトが格納して送るcookieにだけアクセスすることが出来ます。
Webアプリケーションが、CurlアプレットとHTMLベースのページと状態を共有する必要があり、かつインターネット・エクスプローラ以外のブラウザをサポートしなければならない時は、アプレットのダウンロードに使用されるURL内にWebサイトでエンコードされたデータを持たせるか、共有データを含むCurlアプレットを動的に生成することが出来ます。
別の選択肢は、request-browser-resident-httpプロシージャを使用して、HTTPに関する呼び出しをブラウザのプロセスで実行するように要求することです。Browser resident HTTPをサポートするブラウザでは、全てのHTTP cookie呼び出し、HTTP認証呼び出し、"http:" や"https:"を使用した呼び出しは、Webブラウザと同じcookieと同じ認証情報を使用します。Browser resident HTTP は、インターネット・エクスプローラではフルサポートされますが、他のブラウザにおいては、サポートの範囲が限定されます。
先立って呼び出されるrequest-browser-resident-httpが、Browser resident HTTPのいずれかのレベルを利用可能にすることが出来ていると、プロシージャbrowser-resident-http-enabled? は、trueを返します。
BrowserResidentHttpStyleは、Browser resident HTTPのサポートレベルを示します。プロシージャget-browser-resident-http-style は、その時点で利用可能なサポートレベルを返します。
アプレットで Browser resident HTTPが適正に機能することが必要な時はまず最初にrequest-browser-resident-httpを呼び出す必要があります。そして次にbrowser-resident-http-enabled? または get-browser-resident-http-styleを呼び出して、アプレットが実行されている環境が、Browser resident HTTPをサポートするかどうか判定する必要があります。サポートしない環境の場合には、ユーザーに通知してください。

ユースケース: 完全なBrowser Resident HTTPが必要な場合。

アプレットが、完全な Browser resident HTTPのサポートを必要とする場合には、引数無しでrequest-browser-resident-httpを呼び出してください。
{request-browser-resident-http}
これは、完全な Browser resident HTTPを要求します。Windowsプラットフォームでのインターネット・エクスプローラ上でのみ利用可能です。

ユースケース: 最低限のBrowser Resident HTTPで十分な場合。

アプレットが、Browser resident HTTP全機能を利用できない場合には、最低レベルのサポートを示す引数を指定してrequest-browser-resident-http を呼び出してください。
{request-browser-resident-http BrowserResidentHttpStyle.minimal}
この呼び出しは、最低限の Browser resident HTTPを要求します。 アプレットは現在のブラウザで利用可能なサポートを取得します。

Browser Resident HTTPの最低限のサポート

Browser resident HTTP の最低限のサポートは、フルサポートに比べてに明らかに機能が少なくなります。そのサポートの正確なレベルはブラウザ毎に異なります。このセクションでは、それらの制限の幾つかを説明します。
HTTP cookiesを取得、設定する以下のプロシージャは、機能しません。 get-http-cookies は空の配列を返します。他のプロシージャはただ失敗します。
HTTP認証に基づいたAPIを実行する以下のプロシージャは、ただ失敗します。フルサポートの環境下では、これらはユーザー名とパスワードをセットします。最小サポートの環境下では 、これらは動作しません。ユーザー名とパスワードを必要とするリクエストは、ダイアログ・ボックスをポップアップさせて、ユーザー名とパスワードを尋ねます。
レスポンス ヘッダーを取得したり、レスポンス ステータス コードを取得したり、missing filepermission deniedなどの場合のステータス コードに基づく特殊な例外を取得する以下のプロシージャ、メソッドは、幾つかの新しい Webブラウザ上で、時々しか動作しません。レスポンスに現れるヘッダは、Last-ModifiedContent-LengthContent-Type だけです。 Content-Typeには、charset パラメータがありません。 より新しい Webブラウザでは、成功したリクエストの完全なヘッダーを持つ場合があります。古い Webブラウザでは、ステータス コードは、200と404だけです。404は、新しいWebブラウザ上では、他のステータス コードが使われるべき失敗の場合にも使われる時があります。古い Webブラウザでは、HTTPヘッダーに基づいたテキスト ストリームへのCharEncoding の設定もまた動作しません。
以下のメソッドによって、スローされる例外に幾つかの問題があります。HTTPリクエストが失敗した時、例外がスローされます。最低限の Browser resident HTTPでは、例外のスローは必ずしも失敗の本当の理由をあらわしているとは限りません。他のタイプのhttp exceptionを受け取るべきところで、HttpExceptionHttpMissingFileExceptionを受け取る時があります。決してHttpPermissionDeniedFileExceptionを受け取ることはありません。リクエストが動作している時には例外を受け取ることはありません。 しかしながら、Netscape 4.xのような幾つかのブラウザでは、webサーバーからエラーページを受け取っており、例外を受け取らなければならないような時でも、成功しているように見える時があります。
with-file-caching-styleを使用する際、HEADメソッド、GETメソッドに対するFileCachingStyleの設定は機能しません。この事は、ほとんどのパッケージとマニフェストの再同期の動作が通常と異なることを意味します。
アプレットから他のページに移動すると、現行のHTTPリクエストはキャンセルされ、例外がスローされます。
以下のメソッドに対して、若干の制限が加えられます:
これらの制限は:

特定のブラウザにおける既知の問題

ディプロイメントの問題

最低限の Browser resident HTTP を利用したアプレットをディプロイする時、 このHTTPの実装はファイルのリロードを実行できないという制限に対処する為に、幾つかの追加の処置を行う必要があります。同期の問題に関する一般的な論述は キャッシュと同期 をご覧ください。
ユーザーが更新された内容をすぐ見ることが出来るようにする為、、アプレットの起動ファイルの有効期限が直ちに切れるようにWebサーバーを設定する必要があります。さらに変更を加えたファイルの名前もしくはディレクトリを変更するか、変更を加えたファイルの有効期限が切れているように設定する必要があります。 起動ファイルやマニフェスト以外の多くのファイルにおいては、有効期限が切れているように設定するよりも、ファイルのパスを変更するのが良い方法です。
ファイルの有効期限は、再同期の前にどれだけの期間そのファイルがキャッシュされうるのかを示す期限を設定します。ファイルがクライアントにキャッシュされてしまうと、その有効期限を設定することはできません。ですからアプリケーションをディプロイする時に有効期限を指定する必要があります。ディプロイする時点で、ファイル内容を変更することがあるかどうか、またどれだけ頻繁に変更することになるのか分からないかもしれません。多くのファイルをすぐに有効期限が切れるようにすると、クライアントとサーバー間で余分な同期を発生させる可能性があります。それは、特に接続が遅い時にかなりの時間を要する可能性があります。有効期限がすぐに切れるように設定したファイルがアプレット自身のみだった場合、そのアプレットは、リロードされる時に無条件で同期されなければならない唯一のものになります。 Curlが、HTTPの呼び出しを自分で行う場合は、 アプレットのresync-as-of属性をそのまま実行することが出来、ディプロイする時にファイル名の変更をする必要はありません。Browser resident HTTPを使う場合には、Curlは、ブラウザに再同期させる方法を持たないので、ディプロイする人は、更新されたファイルを以前にクライアントにキャッシュされたことが無い新しいファイル名に変更するか、または前もって、変更する可能性があるファイルの有効期限が切れるように準備する必要があります。この場合はアプレットが遅くなる可能性があります。
メイン マニフェスト ファイルもまた移動するか有効期限が切れているように設定する必要があります。メイン マニフェスト ファイルがresync-as-of属性を持っていた場合、そのresync-as-ofの時刻は、アプレットで使用されている何かが変更された時はいつでも更新しなければなりません。マニフェストでresync-as-of属性を使用している場合は、メタデータに小さな値をセットするcache-duration属性も追加したくなるかもしれません。そのようなcache-duration属性は、Curl RTEが頻繁にメイン マニフェスト ファイルをチェックするようにします。cache-durationの設定に関するより詳細な情報については、 パッケージおよびマニフェストでの cache-duration の使用 をご覧ください。
他の方法は、アプレット ファイルの中にresync-as-of属性を記述することです。アプレット ファイルのresync-as-of属性は、アプレットで使用されているパッケージが変更された時は更新されなければなりませんが、最適な同期動作を提供します。アプレット ファイル内のresync-as-of属性は、メイン マニフェスト内のresync-as-of属性をオーバーライドします。IDEディプロイメントは自動的にメイン マニフェスト内のresync-as-of属性を処理しますが、アプレット ファイル内のresync-as-of属性は処理しません。
パッケージのマニフェストや、一緒に使用されるパッケージのライブラリのマニフェストにdelegate-toを使うことも出来ます。マニフェストの委譲を使うと、より効率的に変更されたパッケージだけ更新することが出来ます。画像のようなサポートファイルをロードする為にmanifest-urlを使うと、サポートファイルが移動した時にアプレットやパッケージを変更する必要がありません。いずれの場合でも、全てのマニフェストファイルは、移動するかすぐに期限切れになるように設定しなければなりません。 アプレットもしくはメイン マニフェストがresync-as-of属性を持っている時には、何らかの変更があった時にはいつでもresync-as-of属性が更新されなければならないこと覚えておいてください。委譲されたマニフェスト内のresync-as-of属性は無視されます。
例えば、以下のような構成のアプレットがある時:
    appletX
        start.curl (直ちに有効期限を切るように設定されています)
        manifest.mcurl (直ちに有効期限を切るように設定されています)
    packageA
        manifest.mcurl (直ちに有効期限を切るように設定されています)
        1.0
        load.pcurl
    packageB
        manifest.mcurl (直ちに有効期限を切るように設定されています)
        1.1
        load.pcurl
        image.jpg
packageBを更新したら、以下のように変更します。:
    appletX
        start.curl (直ちに有効期限を切るように設定されています)
            resync-as-of, 使用していたら変更します。
    manifest.mcurl (直ちに有効期限を切るように設定されています)
            resync-as-of, 使用していたら変更します。
    packageA
        manifest.mcurl (直ちに有効期限を切るように設定されています)
        1.0
        load.pcurl
    packageB
        manifest.mcurl (直ちに有効期限を切るように設定されています)
            load.pcurlとimage.jpgのパスを変更します。
        1.2
            新バージョンの為の新しいディレクトリ名
        load.pcurl
            目的のコードとバージョンナンバーだけ変更します。
        image.jpg

翻訳ファイルの問題

翻訳ファイルの指定で記述されている翻訳ファイルの指定に関するメソッドは、Netscape4.7で最低限の Browser resident HTTPを使うと正しく動作しません。何故ならば、missing fileが期待通りに扱われないからです。この状況においては、パッケージ プロジェクトのマニフェストに記述されなければならないパッケージの翻訳ファイルを記述しなければなりません。マニフェストを使用した翻訳ファイルの位置付けをご覧ください。

OCCディプロイメントの問題

occ-install-or-updateを呼び出し、最低限のstyle Browser resident HTTPも使用しているアプレットをディプロイする時には、特殊な手順が必要になります。また、アプレットを適切に更新する為に幾つかの手順を加える必要があります。OCCを使ったアプレットの設計に関する論述は随時接続コンピューティング(OCC)をご覧ください
ルート インストーラーにおいて、curl-timestamp.txtcurl-contents.txt または、curl-archive.car のいずれかが使われている場合、それら全ては、直ちに有効期限が切れるように設定しなければなりません。 もしもcurl-contents.txtファイルが使われている場合は、 通常のディプロイメントの為に削除されたファイルが存在すると、curl-contents.txtの中のリストが変更されます。
モジュール インストーラーにおいて、全てのcurl-modules.txtファイルは、直ちに有効期限が切れるように設定する必要があります。ルート インストーラーと同時に使用する場合には、全てのcurl-timestamp.txt curl-contents.txtcurl-archive.car は直ちに有効期限が切れるように設定する必要があります。

Apacheでの有効期限の実装

Apacheサーバーに推奨された有効期限を設定するには、以下にあげるような行を設定に加えてください。これらの行は、.htaccessファイルまたは、主要設定ファイルの<Directory>セクションに記述してください。マニフェストやアプレットに起動ファイル名に別の名前を使用している場合には、正規表現を修正してください。
# matches curl-contents.txt, curl-modules.txt, curl-timestamp.txt,
# curl-archive.car, manifest.mcurl and start.curl
<FilesMatch "^(curl-(contents|modules|timestamp)\.txt|curl-archive\.car|manifest\.mcurl|start\.curl)$">
ExpiresActive On
# expire immediately
ExpiresDefault A0
</FilesMatch>
IISに設定するには、全てのコンテンツが直ちに有効期限が切れるようにディレクトリのプロパティを設定してください。