Docker + Alpine3.5 + Apache2.4 + Python3.6で、CGIのリダイレクトを使ってみた

以前、SSIを使ってみました。
Docker + Alpine3.5 + Apache2.4 + Python3.6で、SSIを使ってみた - メモ的な思考的な

今回はCGIのリダイレクトを使ってみます。

目次

 

環境

  • Mac OS X 10.11.6
  • Docker for Mac 17.03.1-ce-mac12
  • Alpine3.5 + Apache2.4.25 + Python 3.6.1

 
なお、Dockerfileは以前のものを流用し、Dockerは以下のコマンドで利用しています。

## DockerfileからDockerイメージをビルド
$ docker image build -t alpine:python3_httpd24_redirect .

## Dockerコンテナを起動し、CGIのディレクトリをホストと共有
$ docker container run -p 8081:80 --name redirect -v `pwd`/cgi/:/usr/local/apache2/cgi-bin/ alpine:python3_httpd24_redirect

 
また、動作確認にはcurlを使います。
インターネットにアクセスしよう 番外編 : curlの使い方 - Cocoaはやっぱり!

 

Locationヘッダを使ったリダイレクト

今回はLocationヘッダを使ったリダイレクトを試します。

LocationヘッダのURLの仕様は、RFC7231にあり、

Location = URI-reference

7.1.2. Location | RFC 7231 — HTTP/1.1: Semantics and Content (日本語訳)

とのことです。

URI-referenceの定義は、RFC3986にあり、

URI-reference は、URI か相対的参照のどちらかである。 URI-reference の先頭がコロン分離記号を従えるスキームの構文に合致しなければ、URI-reference は相対的参照である。

4.1. URI 参照 | Uniform Resource Identifier (URI): 一般的構文 - RFC3986 日本語訳の複製

とのことです。

そのため、今回は相対的参照として、ホスト以下を記載します。

以上をもとに、

  • リダイレクト前:redirect.py
  • リダイレクト後:done_redirect.py

の2ファイルを用意します。

redirect.py

#!/usr/bin/python3

# HTTPレスポンスヘッダ
print('Location: /cgi-bin/done_redirect.py')
print('')

 
done_redirect.py

#!/usr/bin/python3

# HTTPレスポンスヘッダ
print('Content-Type: text/plain;charset=utf-8')
print('')

print('Hello')

 
curlLオプションでリダイレクトに対応し、vオプションで実際の往復を見てみます。

$ curl -L -v http://localhost:8081/cgi-bin/redirect.py
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#0)
> GET /cgi-bin/redirect.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 20 May 2017 21:22:27 GMT
< Server: Apache/2.4.25 (Unix)
< Transfer-Encoding: chunked
< Content-Type: text/plain;charset=utf-8
< 
Hello
* Connection #0 to host localhost left intact

リダイレクトが行われているようですが、ステータスコードが200になっていました。

 

NPHスクリプトによる、Locationヘッダを使ったリダイレクト

ステータスコードも自由に変更できる方法を探したところ、書籍「CGIプログラミング 第2版」の3章にApacheNPH (Non Parsed Headers)スクリプトを使う方法が紹介されていました*1

CGIプログラミング

CGIプログラミング

 
また、RFC3875などにも記載があります。

 
書籍ではPerlを使っていましたが、今回はPythonで書いてみます。

NPHスクリプトの場合、

  • ファイル名の接頭辞にnph-を付ける
  • 少なくとも、ステータス行、Conent-Typeヘッダ、Serverヘッダを出力する

とのことですので、以下のPythonスクリプトを書きました。

nph-redirect_hardcord.py

#!/usr/bin/python3

# HTTPレスポンスヘッダ
# NPHなので、ステータスラインも記述する
print('HTTP/1.1 302 Found')
print('Location: /cgi-bin/done_redirect.py')
print('Server: hoge')
print('')

 
curlにて確認します。

$ curl -L -v http://localhost:8081/cgi-bin/nph-redirect_hardcord.py
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#0)
> GET /cgi-bin/nph-redirect_hardcord.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 302 Found
< Location: /cgi-bin/done_redirect.py
< Server: hoge
* no chunk, no close, no size. Assume close to signal end
< 
* Closing connection 0
* Issue another request to this URL: 'http://localhost:8081/cgi-bin/done_redirect.py'
* Hostname localhost was found in DNS cache
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#1)
> GET /cgi-bin/done_redirect.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 20 May 2017 22:14:46 GMT
< Server: Apache/2.4.25 (Unix)
< Transfer-Encoding: chunked
< Content-Type: text/plain;charset=utf-8
< 
Hello
* Connection #1 to host localhost left intact

302リダイレクトになりました。

 

NPHスクリプト + 環境変数による、Locationヘッダを使ったリダイレクト

上記のNPHスクリプトでは色々とハードコーディングしていたため、

を使うように変更します。

 
nph-redirect_environ.py

#!/usr/bin/python3

import os
# ステータスコードとメッセージはPythonの定数を使う
# https://docs.python.jp/3/library/http.html
from http import HTTPStatus

# CGIの環境変数からプロトコルとバージョン・ホストを取得する
protocol = os.environ.get('SERVER_PROTOCOL')
server = os.environ.get('SERVER_SOFTWARE')

# HTTPレスポンスヘッダ
print(f'{protocol} {HTTPStatus.FOUND.value} {HTTPStatus.FOUND.phrase}')
print('Location: /cgi-bin/done_redirect.py')
print(f'Server: {server}')
print('')

 
curlで確認します。

$ curl -L -v http://localhost:8081/cgi-bin/nph-redirect_environ.py

> GET /cgi-bin/nph-redirect_environ.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 302 Found
< Location: /cgi-bin/done_redirect.py
< Server: Apache/2.4.25 (Unix)
< 
> GET /cgi-bin/done_redirect.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 20 May 2017 22:23:31 GMT
< Server: Apache/2.4.25 (Unix)
< Transfer-Encoding: chunked
< Content-Type: text/plain;charset=utf-8
< 
Hello

同じく、302リダイレクトになりました。

 

その他

NPHスクリプトを使う際、環境によっては以下のエラーが出るようです。
apache - Apache2 sends two HTTP headers with a mapped “nph-” CGI - Stack Overflow

 

ソースコード

GitHubに上げました。alpine_apache_python36_redirectディレクトリの中が今回のものです。
thinkAmi-sandbox/Docker_Apache-sample

*1:旧版の英語版であれば、オライリーの「O'Reilly Open Books Project」により公開されています:http://www.oreilly.com/openbook/cgi/ch03_08.html