Location

CGIでリダイレクトをする場合は、Locationヘッダを出力するだけ。

Locationヘッダを使ってジャンプする | beginners CGI

location.cで、

とする。

こう入力すると
こう入力すると

こう入力すると、

こっちにリダイレクト
こっちにリダイレクト

こっちにリダイレクト。

自動で302になるんだなあ・・・。
自動で302になるんだなあ・・・。

自動で302になるんだなあ・・・。

Sample/cgi/Location/Location/src/Location at master · bg1bgst333/Sample · GitHub

Location

Locationヘッダはリダイレクト先を指す。

Location - HTTP | MDN

いろんなレスポンスに使われる。
今回は302で使ってみる。

"HTTP/1.1 302 Found"に変えただけ。

リダイレクトされる
リダイレクトされる

前回と同様にリダイレクトされる。

レスポンスはこう
レスポンスはこう

レスポンスはこう。

Sample/http/Location/Location/src/Location at master · bg1bgst333/Sample · GitHub

HTTP 301 Moved Permanently

301は、別のURLにリダイレクトする時に返す。

301 Moved Permanently - HTTP | MDN

http_server.cで、

として、

ここにアクセス
ここにアクセス

ここにアクセス。
すると、

ここに飛ぶ
ここに飛ぶ

ここに飛ぶ。
そして、

レスポンスもこうなってる
レスポンスもこうなってる

最初のレスポンスもこうなってる。
(ただ、ブラウザのキャッシュを消さないと、キャッシュを利用してリダイレクトしてしまい、サーバ側でリダイレクト先が変わっていても、以前のリダイレクト先に行ってしまうので注意。)

Sample/http/http_status_code/301/src/http_status_code at master · bg1bgst333/Sample · GitHub

text/plain

"Content-type: text/plain"にすると、プレーンテキストで解釈される。

MIME タイプ (IANA メディアタイプ) - HTTP | MDN

content_type.cを、

にすると、

確かにHTMLとしては解釈されず、プレーンテキストとして解釈される。
確かにHTMLとしては解釈されず、プレーンテキストとして解釈される。

Sample/cgi/Content-type/text_plain/src/Content-type at master · bg1bgst333/Sample · GitHub

text/html

"Content-type: text/html"にしておけば、HTMLとして解釈される。

MIME タイプ (IANA メディアタイプ) - HTTP | MDN

content_type.cを、

とすると、

HTMLのリンクになってる
HTMLのリンクになってる

HTMLのリンクになってる。

リンククリックでここに飛ぶし
リンククリックでここに飛ぶし

リンククリックでここに飛ぶし、

Content-Typeはtext/htmlになってる
Content-Typeはtext/htmlになってる

Content-Typeはtext/htmlになってる。

Sample/cgi/Content-type/text_html/src/Content-type at master · bg1bgst333/Sample · GitHub

Content-type

ここからは、CGIについて扱っていく。
HTTPヘッダの"Content-Type"を付けるには、CGIプログラムにもそれを書かないといけない。
(大文字小文字を区別しないので、"Content-Type"でも"Content-type"でもいいけど、"Content-type"と書く人が多いなあ・・・。)

CGIの仕様 - とほほのWWW入門

まず、CGIを書いてみる。
あえてのC言語で。

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* CGIとして文字列の出力. */
  printf("ABCDE"); /* printfで"ABCDE"(改行無し)の出力. */

  /* プログラムの終了 */
  return 0; /* 0を返して正常終了. */

}

"ABCDE"という文字列をCGIのページに出したい場合には、標準出力に出力するだけ。

$ vi content_type.c
$ gcc content_type.c -o content_type.cgi

コンパイルして拡張子は".cgi"にする。

$ sudo cp content_type.cgi /var/www/cgi-bin/
$ cd /var/www/cgi-bin/
$ ls -al content_type.cgi
-rwxr-xr-x 1 root root 8520 xxx xx xx:xx content_type.cgi
$

/var/www/cgi-binに置いて、実行権限があればいい。

あらら、Internal Server Error
あらら、Internal Server Error

あらら、Internal Server Error
こういう時のエラーの原因を特定するのがCGIはめんどい・・・。
エラーログを見ると、

[xxx xxx xx xx:xx:xx.638888 2021] [cgi:error] [pid 21033] [client xxx.xxx.xx.xx:61571] End of script output before headers: content_type.cgi

ヘッダの前にスクリプト出力が終わったよと・・・。
ちょっとなにいってんのかわからない・・・。
本来HTTPとしては、ヘッダ行を出力して、1行空けて、ボディ行("ABCDE"の事)を書いていくのだけど、何のヘッダも出力してないということはあり得ないと思うので、

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */

/* main関数の定義 */
int main(void){

  /* CGIとして文字列の出力. */
  printf("\n"); /* printfで改行を出力. */
  printf("ABCDE"); /* printfで"ABCDE"(改行無し)の出力. */

  /* プログラムの終了 */
  return 0; /* 0を返して正常終了. */

}

改行を前に置いただけにしてみた。

そしたらうまくいっちゃった
そしたらうまくいっちゃった

そしたらうまくいっちゃった。
とはいえ、

Content-typeは付いてない
Content-typeは付いてない

Content-typeは付いてない。
たぶんtext/plainとして判断されてる。

"Content-type: text/plain"をちゃんと指定。

今度はちゃんとついてる
今度はちゃんとついてる

今度はちゃんとついてる。

Sample/cgi/Content-type/Content-type/src/Content-type at master · bg1bgst333/Sample · GitHub

POST

HTTPメソッドのPOSTを使って、サーバにデータを送信する。

POST - HTTP | MDN

とはいえ、サーバは送られたリクエストをどう処理するか、Apacheでデフォルトの処理みたいなのは決められていない(それらの処理はCGIなどを作って自分で処理する。)ので、今回はログだけ出してみる。
前回のGETのリクエストの場合、

$ sudo cat /var/log/httpd/access_log

アクセスログを見ると、最後の方で、

xx.xxx.xx.xxx - - [xx/xxx/2021:xx:xx:xx +0900] "GET /index.html HTTP/1.0" 200 484 "-" "-"
xxx.xxx.xx.xx - - [xx/xxx/2021:xx:xx:xx +0900] "GET /cgi-bin/test.cgi HTTP/1.1" 200 88 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
$

こう出てる。
上は前回の自作クライアントでindex.html、下はChromecgi-binの下のtest.cgiにアクセス。
では、POSTにしてみる。

このように書く。
argv[4]がPOSTで送る文字列。
一応、Content-Lengthや、Content-Typeを付けて、"ABCDE"という単純な文字列をHTTPボディに。

$ vi http_client.c
$ gcc http_client.c -o http_client
$ ./http_client bgstation0.com 80 /cgi-bin/test.cgi ABCDE
connect success.
HTTP/1.1 200 OK
Date: xxx, xx xxx 2021 xx:xx:xx GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips
Connection: close
Content-Type: text/html

<html>
<head>
<title>hello</title>
</head>
<body>
<p>
Howdy, Perl!
</p>
</body>
</html>

$

"/cgi-bin/test.cgi"にアクセスしてるけど、これ自体はあまり意味ない。
アクセスログを見ると、

xx.xx.xx.xxx - - [xx/xxx/xxxx:xx:xx:xx +0900] "POST /cgi-bin/test.cgi HTTP/1.0" 200 88 "-" "-"
$

POSTでもログは残ってるなあ。

HTTP POST でデータを送って中身を確認したい - Qiita

ログに記録されないのはPOSTで送ったBODYのことかな。
ちゃんとログに記録されるかconfを調べる。

$ sudo vi /etc/httpd/conf/httpd.conf

これで"LoadModule"で検索すると、

#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
Include conf.modules.d/*.conf

conf.modules.dの下の.confを見ればいいのか。

$ sudo vi /etc/httpd/conf.modules.d/00-base.conf

ここを見てたら、

LoadModule dumpio_module modules/mod_dumpio.so

mod_dumpio.soは既に入ってた。
ただ、error_logにはそれっぽいログが無かったので、

#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
Include conf.modules.d/*.conf
DumpIOInput On

"DumpIOInput On"を追加。

#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
#LogLevel warn
LogLevel debug dumpio:trace7

ログレベルも変更。

$ sudo systemctl restart httpd.service

再起動。
で、またPOSTで投げてみる。

$ sudo cat /var/log/httpd/error_log

エラーログを見ると、

[xxx xxx xx xx:xx:xx.561261 xxxx] [dumpio:trace7] [pid 20778] mod_dumpio.c(140): [client xx.xxx.xx.xxx:56296] mod_dumpio: dumpio_in [readbytes-blocking] 5 readbytes
[xxx xxx xx xx:xx:xx.561307 2021] [dumpio:trace7] [pid 20778] mod_dumpio.c(63): [client xx.xxx.xx.xxx:56296] mod_dumpio:  dumpio_in (data-HEAP): 5 bytes
[xxx xxx xx xx:xx:xx.561317 2021] [dumpio:trace7] [pid 20778] mod_dumpio.c(103): [client xx.xxx.xx.xxx:56296] mod_dumpio:  dumpio_in (data-HEAP): ABCDE
$

こんな感じでPOSTのBODYにある"ABCDE"が見れた。
読み込んだバイト数も出てる。
というか、この前にヘッダのContent-Lengthとか、Content-Typeとかも、値がいくつかとか出てる。

Sample/http/http_method/POST/src/http_method at master · bg1bgst333/Sample · GitHub