#!/usr/local/bin/perl
use lib qw(PATH TO LIBRARY);
use strict;
use utf8;
use Encode;

binmode STDOUT=>":utf8";
$| = 1;

my $ref = reference->new({});

$ref->check_key_id; #

my $form = $ref->_read_form(40000,{enc=>'utf8'});
$ref->ret_err({}) unless ( $form->{'post_content'} =~ m!$ref->{to}! || $form->{'post_content'} =~ m!(?:タイトル|著者)[::].+! );

# for http signature
$ref->ret_err({code=>'401'}) if $ENV{'REQUEST_METHOD'} ne 'POST';
$ref->ret_err({code=>'401'}) if ! $ref->verify_signature({});

print "Status:200 OK\n\n";

# for get json
my $content = $ref->parse_json({content=>$form->{'post_content'}});
exit if ! $content;

# for seach sql
my $result = $ref->bookinfo({content=>$content});

# for post activity
my $posted = $ref->post_actpb({url=>$ref->{to} . '/inbox',content=>$ref->make_create({content=>$result})});
exit;

package reference;
use JSON;
use DBI;
use Crypt::Perl::RSA::Parse;
use Digest::SHA qw(sha256 sha256_base64 hmac_sha256 hmac_sha256_base64);
use MIME::Base64;
use LWP::UserAgent;
use UUID::Tiny;
use base qw( siteutil );
use vars qw( $dbh );

sub new{
	my $invocant = shift;
	my $class = ref($invocant) || $invocant;
	my $args = shift;
	my ( $obj )  = bless {
		root=>'/bookshelf',
		db_path => '/db/',
		dbname=>'00001',

		ap_url=>'https://bookshelf.doncha.net/',
		actor=>'librarian',
		keyid=>'https://bookshelf.doncha.net/librarian#main-key',
		# only bookshelf owner
		to=>'https://tokoroten.doncha.net/t2aki',
		to_name=>'@t2aki@tokoroten.doncha.net',

		%$args,
		@_
	}, $class;
	if( $dbh eq '' ){
		$obj->connect_db;
	}
	return $obj;
}
sub DESTROY {
	my $self = shift;
	$dbh->disconnect;
	exit;
}
####
sub vacuum_db{
	my $self = shift;
	$dbh->do('VACUUM');
	return;
}
sub connect_db{
	my $self = shift;
	my $dbname = (shift || $self->{dbname});
	$dbname = $self->{root} . $self->{db_path} . $dbname . '.sqlite';
	$dbh = DBI->connect( "dbi:SQLite:dbname=$dbname","","",{ RaiseError => 1, AutoCommit=>1 });
	if( ! $dbh ) { die 'cannot connect db'; }
	return $dbh;
}
sub disconnect_db{
	my $self = shift;
	return if ! $dbh;
	$dbh->disconnect;
	undef $dbh;
}
###
sub execute_sql{
	my $self = shift;
	my $sql  = shift;
	return if ! $sql;
	eval {
		my $sth = $dbh->prepare($sql);
		my $r   = $sth->execute;
	};
	if( $@ ){
		print qq{<Content-type:text/html\n\n><html><body>};
		print '<br /> Unable execute....' . $sql;
		print qq{</body></html>};
		exit;
	}
	return;
}
sub select_data{
	my $self = shift;
	my $sql  = shift;
	my $cols = shift;
	return if ! $sql;
	my $sth; my $r;
	eval{
		$sth = $dbh->prepare($sql);
		$r   = $sth->execute;
	};
	if( $@ ){
		open(LOG,'>>','_check.log');
		 printf LOG qq{%s\n<br />%s},$sql, $@;
		 close(LOG);
		 exit;
	}
	$cols= $sth->{NAME} if ! $cols;
	my @buf;
	while( my $p = $sth->fetchrow_arrayref){
		my %h;
		map{$_ = $self->touch_decode($_)} @{$p};
		map{$_ =~ s/\'\'/\'/g;} @{$p}; # for sqlite escape
		@h{ @{$cols} } = @{$p};
		push(@buf, \%h);
	}
	return \@buf;
}
###
sub make_create{
	my $self = shift;
	my $args = shift;

	return if ! $args->{content};

	my ($sec,$mi,$h, $d,$m,$y) = (gmtime(time))[0..5]; ++$m; $y+=1900;
	my $datetime = sprintf qq{%s-%02d-%02dT%02d:%02d:%02dZ}, $y,$m,$d, $h,$mi,$sec;
	my $uuid = create_UUID_as_string(UUID_V1);
	my $cid = sprintf qq{%s%s/activity/%s}, $self->{ap_url},$self->{actor},  $uuid;
	my $oid = sprintf qq{%s%s/item/%s}, $self->{ap_url},$self->{actor},  $uuid;
	my $ref = {
		'@context'=>[
			"https://www.w3.org/ns/activitystreams",
			{'Hashtag'=>'as:Hashtag'},
			"https://w3id.org/security/v1"
			],
		'type'=>'Create',
		'id'=>$cid,
		'url'=>$cid,
		'published'=>$datetime,
		'actor'=>$self->{ap_url} . $self->{actor},
		'to'=>[$self->{to}],
		'cc'=>[],
		'object'=>{
			'type'=>'Note',
			'id'=>$oid,
			'url'=>$oid,
			'published'=>$datetime,
			'to'=>[$self->{to}],
			'cc'=>[],
      		'attributedTo'=>$self->{ap_url} . $self->{actor},
			'content'=>$args->{content},
			'tag'=>[
				{
				'href'=>$self->{ap_url} . $self->{actor},
				'name'=>$self->{to_name},
				'type'=>'Mention'
				}
			]
		},
	};
	my $json = JSON->new->canonical(1)->utf8(1)->indent(0)->space_before(0)->space_after(0)->encode($ref);
	return $json;
}
###
sub post_actpb{
	my $self = shift;
	my $args = shift;

	return if ! $args->{url};
	return if ! $args->{content};

	my $url = $args->{url}; $url =~ s!/$!!;
	my $res;
	my $req;
	if( $args->{ver} ){
		if( $args->{ver} eq 'RFC9421' ){
			$req = $self->signature_RFC9421({url=>$url,content=>$args->{content}}); 
		}
		elsif( $args->{ver} eq 'legacy' ){
			$req = $self->signature_legacy({url=>$url,content=>$args->{content}}); 
		}
		$res = $self->_request({req=>$req});
	}
	else{
		# 1st HTTP Signature RFC9421
		$res = $self->_request({req=>$self->signature_RFC9421({url=>$url,content=>$args->{content}})});
		# 2nd HTTP Signature legacy
		if( ! $res->is_success ){
			undef $res;
			$res = $self->_request({req=>$self->signature_legacy({url=>$url,content=>$args->{content}})});
		}
	}
	if( ! $res->is_success ){
		printf qq{ERROR get_actpb : %s}, $url;
	}
	return $res;
}
sub get_actpb{
	my $self = shift;
	my $args = shift;

	return if ! $args->{url};

	my $url = $args->{url};
	if( ref($url) =~ m!(ARRAY|Hash)! ){
		print $url;
		print $args->{filename};
		return;
	}
	$url =~ s!\#main\-key!!;
	$url =~ s!/$!!;

	my $res;
	my $req;
	if( $args->{ver} ){
		if( $args->{ver} eq 'RFC9421' ){
			$req = $self->signature_RFC9421({method=>'GET',url=>$url,accept=>'application/activity+json',auth=>$args->{auth}}); 
		}
		elsif( $args->{ver} eq 'legacy' ){
			$req = $self->signature_legacy({method=>'GET',url=>$url,accept=>'application/activity+json',auth=>$args->{auth}}); 
		}
		$res = $self->_request({req=>$req});
	}
	else{
		# 1st HTTP Signature RFC9421
		$res = $self->_request({req=>$self->signature_RFC9421({method=>'GET',url=>$url,accept=>'application/activity+json',auth=>$args->{auth}})});
		# 2nd HTTP Signature legacy
		if( ! $res->is_success ){
			undef $res;
			$res = $self->_request({req=>$self->signature_legacy({method=>'GET',url=>$url,accept=>'application/activity+json',auth=>$args->{auth}})});
		}
	}
	if( ! $res->is_success ){
		printf qq{ERROR get_actpb : %s}, $url;
		return;
	}
	return $res->decoded_content; #gzip 対応
}
sub _request{
	my $self = shift;
	my $args = shift;

	return if ! $args->{req};

	my $ua = LWP::UserAgent->new(agent=>'http.pl/5.38 (bookshelf/0.1.0; +https://bookshelf.doncha.net/)');
	$ua->timeout( $self->{timeout} );

	my $res;
	eval{
		local $SIG{ALRM} = sub{die "timeout";};
		alarm $self->{timeout};
		$res = $ua->request($args->{req});
		alarm 0;
	};
	alarm 0;
	if( $@ ){
		printf qq{ERROR _request:  %s},$@;
		return;
	}
	return $res;
}
###
sub sign{
	my $self = shift;
	my $args = shift;

	return if ! $args->{signature_base};
	my $buf = $self->select_data(qq{select private_key from KEYS});
	my $priv = Crypt::Perl::RSA::Parse::private($buf->[0]{private_key});

	my $sign = $priv->sign_RS256($args->{signature_base});
	return encode_base64($sign, "");
}
sub verify_signature{
	my $self = shift;
	my $args = shift;

	my $item = $self->prepare_verify_signature({});
	if( ! $item ){
		printf qq{ERROR verify signature: %s\n}, $args->{logfile} unless $self->{script} =~ m!tameike\-pool\.pl!;
		return;
	}

	my $pub = $item->{pubkey};
	my $publickey  = Crypt::Perl::RSA::Parse::public($pub);
	my $decoded = decode_base64($item->{signature});
	return $publickey->verify_RS256($item->{signature_base}, $decoded);
}
sub prepare_verify_signature{
	my $self = shift;
	my $args = shift;

	my $http_ref = $self->parse_http_env({});
	if( ! $http_ref->{sig}->{keyid} ){
		return;
	}

	my $req; my $ver;
	if( ! $http_ref->{http}->{'signature-input'}){
		$req = $self->signature_legacy({url=>$http_ref->{sig}->{keyid}, content=>'', method=>'GET',accept=>'application/activity+json'});
		$ver = 'legacy';
	}
	else{
		$req = $self->signature_RFC9421({url=>$http_ref->{sig}->{keyid}, content=>'', method=>'GET',accept=>'application/activity+json'});
		$ver = 'RFC9421';
	}
	my $content = $self->get_actpb({url=>$http_ref->{sig}->{keyid}, req=>$req, ver=>$ver});
	if( ! $content ){
		printf qq{prepare verify No content: %s}, $http_ref->{sig}->{keyid} unless $self->{script} =~ m!tameike\-pool\.pl!;
		return;
	}
	my $json;
	eval{ $json = decode_json($content) };
	if($@){
		printf qq{prepare verify Json ERROR: %s<br/>\n%s}, $http_ref->{sig}->{keyid}, $@ unless $self->{script} =~ m!tameike\-pool\.pl!;
		return;
	}
	my $base = $self->_make_signature_base({sig=>$http_ref->{sig}, http=>$http_ref->{http}});
	if(! $base ){
		printf qq{prepare verify No Signature base: %s<br/>\n%s}, $http_ref->{sig}->{keyid}, $@ unless $self->{script} =~ m!tameike\-pool\.pl!;
		return;
	}
	return {signature=>$http_ref->{sig}->{signature}, signature_base=>$base,pubkey=>$json->{publicKey}->{publicKeyPem}};
}
sub parse_http_env{
	my $self = shift;
	my $args = shift;

	my $env = ( $args->{env} || \%ENV );
	my $http;
	foreach (keys %{$env}){
		my $k = $_;
		$k =~ s!^HTTP_!!; $k =~ s!^REQUEST_!!; $k =~ tr/A-Z/a-z/; $k =~ s!_!-!g;
		$http->{$k} = $env->{$_};
	}
	my $sig;
	foreach my $k (keys %{$http} ){
		if( $k eq 'signature' ){
			$sig->{sign} = $http->{$k};
		}
		elsif( $k eq 'signature-input' ){
			$sig->{base} = $http->{$k};
		}
	}
	if( ! $sig->{base} ){
		my @buf = split(',', $sig->{sign});
		foreach (@buf){
			my ($k,$v) = split('='); $v =~ s!^"!!; $v =~ s!"$!!;
			if( $k =~ m!keyId!i ){
				$sig->{keyid} = $v;
			}
			elsif( $k =~ m!^alg! ){
				$sig->{alg} = $v;
			}
			elsif( $k =~ m!signature! ){
				$sig->{signature} = $v;
			}
			elsif( $k =~ m!headers! ){
				$sig->{headers} = $v;
			}
		}
		foreach my $k ( split(' ', $sig->{headers}) ){
			$sig->{$k} = $http->{$k};
		}
	}
	else{
		my @buf = split(';', $sig->{base});
		foreach (@buf){
			my($k,$v) = split('='); $v =~ s!^"!!; $v =~ s!"$!!;
			if( $k =~ m!keyid!i ){
				$sig->{keyid} = $v;
			}
			elsif( $k =~ m!alg! ){
				$sig->{alg}	= $v;
			}
			elsif( $k =~ m!created! ){
				$sig->{created} = $v;
			}
			elsif( $k =~ m!sig\d! ){
				$sig->{params} = $v;
			}
		}
		# legacyに合わせて%$sigのsignatureに入れておく
		$sig->{signature} = $http->{'signature'}; $sig->{signature} =~ s!sig\d=:!!; $sig->{signature} =~ s!:$!!;
	}
	return {sig=>$sig, http=>$http};
}
# for verify signature base
sub _make_signature_base{
	my $self = shift;
	my $args = shift;

	my $base;
	if( $args->{sig}->{headers} ){
		my @buf;
		foreach (split(' ', $args->{sig}->{headers})){
			if( $_ eq '(request-target)' ){
				$args->{http}->{method} =~ tr/A-Z/a-z/;
				push(@buf, sprintf(qq{%s: %s %s},$_, $args->{http}->{method}, $args->{http}->{uri}));
			}
			else{
				push(@buf, sprintf(qq{%s: %s},$_, $args->{http}->{$_}));
			}
		}
		$base = join("\n", @buf);
	}
	else{
		my @buf;
		$args->{sig}->{params} =~ s!^\(!!; $args->{sig}->{params} =~ s!\)$!!;
		my @params = split(' ',$args->{sig}->{params});
		foreach my $k ( @params ){
			$k =~ s!^"!!; $k =~ s!"$!!;
			if($args->{http}->{$k}){
				push(@buf, sprintf(qq{"%s": %s},$k, $args->{http}->{$k}));
				next;
			}
			push(@buf, sprintf(qq{"%s": %s},$k, $args->{http}->{method})) , next if $k eq '@method';
			push(@buf, sprintf(qq{"%s": %s},$k, $args->{http}->{host})), next if $k eq '@authority';
			push(@buf, sprintf(qq{"%s": %s://%s%s},$k, $args->{http}->{scheme},$args->{http}->{host}, $args->{http}->{uri})), next if $k eq '@target-uri';
			push(@buf, sprintf(qq{"%s": %s://%s%s},$k, $args->{http}->{scheme},$args->{http}->{host}, $args->{http}->{uri})), next if $k eq '@request-target';
		}
		if(scalar(@buf) != scalar(@params)){
			printf qq{_make signature base:  buf:%s params:%s\n}, scalar(@buf), scalar(@params);
			return;
		}
		my $sig_base = $args->{sig}->{base}; $sig_base =~ s!sig\d=!!;
		push(@buf, sprintf( qq{"\@signature-params": %s}, $sig_base));
		$base = join("\n", @buf);
	}
	return $base;
}
###
sub signature_legacy{
	my $self = shift;
	my $args = shift;

	return if ! $args->{url};
	my $method = ($args->{method} || 'POST');

	my $url = $args->{url}; $url =~ s!^"!!; $url =~ s!"$!!; $url =~ s!/$!!;
	my $content;
	if( $args->{content} ){
		$content = $args->{content};
		$content = Encode::encode('utf8', $content) if Encode::is_utf8($content);
	}
	my $accept = $args->{accept}; # for get request

	my $req = HTTP::Request->new($method=>$url);
	$req->content_type('application/activity+json');

	my @items;
	if( $method eq 'GET'){
		@items = ('(request-target)','host','date');
	}
	else{
		@items = ('(request-target)','host','date','digest','content-type');
	}
	my $host = $url; $host =~ s!^"!!; $host =~ s!"$!!; $host =~ s!^https://!!; $host =~ s!/.+$!!;
	my ($target) = $url =~ m!$host(.+)!;
	$target = sprintf qq{%s %s}, $method, $target; $target =~ tr/A-Z/a-z/;
	$req->headers->date(time);

	my $digest = encode_base64(sha256($content),"") if $content;
	my $item;
	$item->{'(request-target)'} = $target;
	$item->{'host'} = $host;
	$item->{'date'} = $req->headers->header('date');
	$item->{'digest'} = 'SHA-256=' . $digest if $content;
	$item->{'content-type'} = 'application/activity+json' if $content;

	my @buf1;
	foreach (@items){
		push(@buf1, sprintf(qq{%s: %s},$_,$item->{$_}));
	}
	my $base = join("\n", @buf1);
	my $signature = $self->sign({signature_base=>$base});

	my $keyid = $self->{keyid};
	my $params = sprintf qq{keyId="%s",algorithm="rsa-sha256",headers="%s",signature="%s"},
	$keyid,join(' ', @items), $signature;

	$req->headers->push_header('Signature'=>$params);
	$req->headers->push_header('Digest'=>'SHA-256=' . $digest) if $content;
	$req->headers->push_header('host'=>$host);
	$req->headers->push_header('Accept'=>$accept) if $accept;
	$req->headers->push_header('Authorization'=>$args->{auth}) if $args->{auth};
	$req->content($content) if $content;
	return $req;
}
###
sub signature_RFC9421{
	my $self = shift;
	my $args = shift;

	return if ! $args->{url};
	my $method = ($args->{method} || 'POST');
	my $url = $args->{url}; $url =~ s!^"!!; $url =~ s!"$!!; $url =~ s!/$!!;

	my @items;
	if( $method eq 'GET' ){
		@items = ('@target-uri','host','date');
	}
	else{
		@items = ('@method','@target-uri','content-digest');
	}
	my $content;
	if( $args->{content} ){
		$content = $args->{content};
		$content = Encode::encode('utf8', $content) if Encode::is_utf8($content);
	}
	my $accept = $args->{accept}; # for get request

	my $req = HTTP::Request->new($method=>$url);
	$req->content_type('application/activity+json');

	my $host = $url; $host =~ s!^https://!!; $host =~ s!/.+$!!;
	$req->headers->date(time);

	my $digest = encode_base64(sha256($content),"") if $content;
	my $item;
	$item->{'@method'} = $method;
	$item->{'@authority'} = $host;
	$item->{'@target-uri'} = $url;
	$item->{'@request-target'} = $url;
	$item->{'content-digest'} = 'sha-256=:' . $digest . ':' if $content;
	$item->{'host'} = $host;
	$item->{'date'} = $req->headers->header('date');

	my @buf0;
	foreach (@items){
		push(@buf0, sprintf qq{"%s"}, $_);
	}
	my $keyid = $self->{keyid};
	my $params = sprintf qq{(%s);alg="rsa-v1_5-sha256";keyid="%s";created=%s}, join(' ',@buf0), $keyid, (time);
	my @buf1;
	foreach (@items){
		push(@buf1, sprintf(qq{"%s": %s},$_,$item->{$_}));
	}
	my $base = join("\n", @buf1) . "\n" . '"@signature-params": ' . $params;
	my $signature = $self->sign({signature_base=>$base});

	$req->headers->push_header('Signature'=>'sig1=:'. $signature . ':');
	$req->headers->push_header('Signature-Input'=>'sig1=' . $params);
	$req->headers->push_header('Content-Digest'=>'sha-256=:' . $digest . ':') if $content;
	$req->headers->push_header('host'=>$host);
	$req->headers->push_header('Accept'=>$accept) if $accept;
	$req->headers->push_header('Authorization'=>$args->{auth}) if $args->{auth};
	$req->content($content) if $content;
	return $req;
}

###
sub parse_json{
	my $self = shift;
	my $args = shift;

	return if ! $args->{content};
	my $content = Encode::encode('utf8',$args->{content});
	$content =~ s!\r?\n!!g;
	my $json;
	eval{ $json = decode_json($content); };
	if( $@ ){
		return;
	}
	unless( $json->{object}->{attributedTo} =~ m!$self->{to}! ){
		return;
	}
	return $json->{object}->{content};
}
#
sub bookinfo{
	my $self = shift;
	my $args = shift;

	return if ! $args->{content};

	my ($title) = $args->{content} =~ m!タイトル[::](.+)!;
	my ($author) = $args->{content} =~ m!著者[::](.+)!;

	$title =~ s!^ *!!; $title =~ s! *$!!; $title =~ s![;:\'=<>]!!;
	$author =~ s!^ *!!; $author =~ s! *$!!; $author =~ s![;:\'=<>]!!;

	my $sql;
	if($title && $author){
		$sql = qq{select books_list.title,authors_list.author,books_memo.comment,books_list.ymd,books_list.readed from books_list
		inner join authors_list on books_list.bookid = authors_list.bookid
		left outer join books_memo on books_list.bookid = books_memo.bookid
		where books_list.title like '%$title%' and authors_list.author like '%$author%'};
	}
	elsif( $title ){
		$sql = qq{select books_list.title,authors_list.author,books_memo.comment,books_list.ymd,books_list.readed from books_list
		inner join authors_list on books_list.bookid = authors_list.bookid
		left outer join books_memo on books_list.bookid = books_memo.bookid
		where books_list.title like '%$title%'};
	}
	elsif( $author ){
		$sql = qq{select books_list.title,authors_list.author,books_memo.comment,books_list.ymd,books_list.readed from books_list
		inner join authors_list on books_list.bookid = authors_list.bookid
		left outer join books_memo on books_list.bookid = books_memo.bookid
		where authors_list.author like '%$author%'};

	}
	my $buf;
	if( $sql ){
		$buf = $self->select_data($sql);
	}
	my @list;
	my $info;
	if( $buf ){
		my $zzz;
		foreach ( @{$buf} ){
			push(@list, $_->{title}) if ! $zzz->{$_->{title}}++;
			if( ! $zzz->{$_->{author}}++ ){
				$info->{$_->{title}}->{author} .= sprintf qq{%s\t}, $_->{author};
			}
			if( $_->{comment} ){
				$info->{$_->{title}}->{comment} .= sprintf qq{%s\t}, $_->{comment};
			}
			$info->{$_->{title}}->{readed} = $_->{readed};
		}
	}
	my $res;
	if(@list){
		foreach (@list){
			$info->{$_}->{author} =~ s!\t$!!; $info->{$_}->{author} =~ s!\t!:!g;
			$info->{$_}->{comment} =~ s!\t$!!; $info->{$_}->{comment} =~ s!\t!<br/>--------------<br/>!g; $info->{$_}->{comment} =~ s!\r?\n!<br/>!g;
			$res .= sprintf qq{%s<br/>%s『%s』%s},
			$info->{$_}->{author}, $info->{$_}->{readed} ? '[既]':'[未]', $_,
			$info->{$_}->{comment} ? sprintf(qq{<br/>%s<br/>}, $info->{$_}->{comment}) : '';
		}
	}
	else{
		$res = sprintf qq{登録はありません};
	}
	return $res;
	
}
sub check_key_id{
	my $self = shift;
	my $args = shift;

	my $keyid;
	if( $ENV{HTTP_SIGNATURE_INPUT} ){
		($keyid) = $ENV{HTTP_SIGNATURE_INPUT} =~ m!keyid="([^"]+)"!;
	}
	else{
		($keyid) = $ENV{HTTP_SIGNATURE} =~ m!keyId="([^"]+)"!;
	}

	unless( $keyid =~ m!$self->{to}! ){
		$self->ret_err({});
	}
	return;
}
#
sub ret_err{
	my $self = shift;
	my $args = shift;
	
	my $code = ( $args->{code} || 404 );
	my $response = {401=>'Unauthorized', 403=>'Forbidden', 404=>'Not Found',410=>'gone'};
	printf qq{Status: %s %s\n\n}, $code, $response->{$code};
	exit;
}
#
sub _read_form{
	my $self  = shift;
	my $limit = shift;
	my $opt   = shift;
	my($buf,$form_name, $form_value, $pair,@pairs);
	my %form;
	my %zzz;
	my $post_content;
	if( $ENV{'REQUEST_METHOD'} eq 'POST' ){
		read(STDIN, $buf, $ENV{'CONTENT_LENGTH'});
# 2025-03-18 08:32:49
# POST の場合、FORMデータ(本文)に「key=value&key=value」のような文字列のことがあるので「=」でsplitしてkey valueを取得するのが定番
# だけど、Activityの場合は、ActivityのJSONだけなのでバラすフェーズはスキップしてここでreturnする
		$buf  = Encode::decode('utf8', $buf)  if ! Encode::is_utf8($buf);
		$form{'post_content'} = $buf if( $buf );
		return \%form;
	}
	else{
		$buf = $ENV{'QUERY_STRING'};
	}
	@pairs = split(/&/,$buf);
	foreach $pair (@pairs){
		($form_name, $form_value) = split(/=/,$pair);
		$form_value =~ tr/+/ /;
		$form_value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;

		my $enc;
		if( $opt->{enc} ){
			$enc = $opt->{enc};
		}
		else{
			my $guess = Encode::Guess->guess($form_value);
			$enc = ref($guess) ? $guess->name : 'utf8';
		}
		$form_value = Encode::encode('utf8',Encode::decode($enc, $form_value));

		$form_name  = Encode::decode('utf8', $form_name)  if ! Encode::is_utf8($form_name);
		$form_value = Encode::decode('utf8', $form_value) if ! Encode::is_utf8($form_value);

		$form_value =~ s/\x0D\x0A/\n/g;
		$form_value =~ s/\x0D/\n/g;
		$form_value =~ s/\</\</g;
		$form_value =~ s/\>/\>/g;
		$form_name =~ s!\t!_TAB_!g;
		$form_value =~ s!\t!_TAB_!g;

		if( ! $zzz{$form_name}++ ){
			$form{$form_name} = $form_value;
		}
		else{
			$form{$form_name} .= "\t" . $form_value;
		}
	}

	return \%form;
}