M.C.P.C. (Mamesibori Creation Plus Communication)

印刷屋から五反田のWeb屋に転職したCLのブログです。

Perl Beginners #8に参加したら206 Pertial Contentでおっさん認定された件について

昨日、Perl Beginners #8に参加してきました。

Perl Beginners: Perl Beginners #8 開催します

今回はテーマがe-mailだったのですが、会社に「うちのe-mail配信ってPerlじゃないですかー、ちょっと聞いてきたいんですけれどもー」ていうたら、勤務時間中の開催時間でしたが、直帰で参加できることになりました。Web屋ってちょろいぜ。

会社業務で出席したので、レポートは明日会社で書く。

で、懇親会でなぜかHTTPステータスコード206のPertial Contentの話をされていたのですが、最初よくわからんかったけれどもよく聞くと2009年に書いた

アドビのAcrobat用バイトサービングスクリプトが何をやっているか今ならわかる - M.C.P.C.

で書いてある、印刷業界でいう「PDFのバイトサービング」じゃねえかと気づいて、RedHat 7.2のApacheは206に対応していなかったけれどもRedHat 7.3のApacheは対応しているとかそんな昔話に参戦したらおっさん認定された。だてにおっさんやってないぜ。

どうやら、iモードなどの携帯電話コンテンツで206での分割送信が必要だったらしい。おじさん、その頃はPDF出力とか出力業務の標準化に明け暮れていた頃だな。会社で携帯電話コンテンツの受注を受けていたらもしかしたら取り組んでいたかもしれん。

家に帰ってきてから、確かseekしてreadしてたよねーとか思って、スクリプトを見ようと思ったら、アドビの野郎がデットリンクにしてやがって、アドビにはミームを伝承する気がねえクソ企業だということを改めて確認した上で、Wayback Machineから発掘してきました。

http://web.archive.org/web/20000615073408/http://www.adobe.com/support/techguides/acrobat/byteserve/bsunix.txt

#!/usr/bin/perl
#!/usr/local/bin/perl
# byteserver script
# byteserver.pl
# Last updated May 10, 1996
# This script implements the draft "Byte Range Retrieval Extension to HTTP" described at 
# "http://www.w3.org/Protocols/rfc2068/rfc2068". 
# place this script wherever you can run CGIs on your Web server.
# 1) Users should make sure that the script as placed in the cgi-bin
#directory is renamed to byteserver.pl, and has execute permission on 
#a UNIX machine. This is done  by typing: chmod 755 byteserver.pl
#2.) The first line of the byteserver.pl script contains a line of the form
#!<pathname>
#where <pathname> points to
#where perl is found on the system.
#Users should modify this line to suit their system-- on a UNIX machine
#you can find out where perl resides by typing: which perl
#if the above returns /usr/local/bin/perl
#then the first line of the byteserver.pl should read
#!/usr/local/bin/perl
#Note: if executing the command: which perl
#returns the message: perl command not found or something similar it
#means that perl is not installed on your system. You *need* perl to
#use byteserver.pl 
# query is of the form
# http://server/cgi-bin/byteserver.pl/path/name/here
#       with HTTP_RANGE specifying the ranges in the form
#       "bytes=m1-n1,m2-n2,...,mn-nn"
#       /path/name/here is relative to server root
#       m-n are ranges (0 based). If m is absent, means n bytes from EOF, if n
#       is absent, mean first m bytes of the file 
#       "bytes=..." syntax
#       STDOUT the ranges
#       The script issues HTTP1.0 206 Partial Content as a partial
#       content response.     
# Env. variables:
#       PATH_TRANSLATED is the file name
#       CONTENT_TYPE is what the server says is the mime type of file
#       REQUEST_METHOD is the request method i.e. GET, POST etc. (we only accept GET)
#       HTTP_RANGE the byte range request
# Return syntax:
# if no ;bytes= is specified, returns:
#       Accept-ranges: bytes
#       Content-type: <content-type>
#       Content-length: <file-length>
#       <the file itself>
# if ;bytes= specified, returns:
#       
#       HTTP/1.0 206 Partial Content
#       Accept-ranges: bytes
#       Content-type: multipart/x-byteranges; boundary=$boundary
#       < multipart-body >
   
sub badjob {
     
local($mesg) = @_;
     
print "Status: 403 \"BOGUS\"\r\n\r\n";
     
print "<HEAD><TITLE>403 BOGUS</TITLE></HEAD>"; print "<BODY BGCOLOR="#FFFFFF" LINK="#0033CC" VLINK="#800080" ALINK="#FF0000"><H1>403 BOGUS</H1>";
print "<pre>$mesg</pre>\r\n";
print "Bad Request\r\n\r\n";
exit 1;
}
     
     
$path = $ENV{'PATH_TRANSLATED'};
$ranges = $ENV{'HTTP_RANGE'};
     
($file, $query) = split(/;/,$path);
     
$contenttype = $ENV{'CONTENT_TYPE'};
if ($contenttype eq "") 
{ 
        $contenttype = "application/pdf";
}
     
if ((! -r $file) || (length $file <= 3)) 
{ 
        &badjob("file $file not found");
}
     
if ($ENV{'REQUEST_METHOD'} ne 'GET') 
{ # not URL-based query 
        &badjob("METHOD not GET");
}
     
$size = -s $file;
     
if (($query eq "") && ($ranges eq "")) 
{
        # respond that we can do ranges
        print "Accept-ranges: bytes\r\n";
        print "Content-type: $contenttype\r\n"; 
        printf "Content-Length: %d\r\n\r\n", $size; 
        open(FILE, "< $file");
        while(read(FILE, $buffer, 4096)) {
        print STDOUT $buffer;
}
exit 0;
     
} else {
    if ($ranges ne "")
    { 
        $query = $ranges;
        $query =~ s/bytes=//;
    }
    else
    {           
        $query =~ s/\s+//g; # squeeze all whitespace out 
        $query =~ s/bytes=//; 
    }
     
    #check that the ranges are properly formatted 
    @byterangeCheck = split(/[-,=]/,$query); 
    while (defined($fbyte = shift(@byterangeCheck))) {
        $lbyte = shift(byterangeCheck);
        if (($fbyte > 0) && ($lbyte < 0)) {
                &badjob("query range malformed");
        }
        if (($fbyte < 0) && ($lbyte > 0)) {
                &badjob("query range malformed"); 
        }
        if ($fbyte > $lbyte) {
                &badjob("query range malformed");
        }
     
    }
    @byterange = split(/[,]/,$query);
}
     
# print 206 only if called with official syntax   
if ( $ranges ne "" )
{
        print "Status: 206 Partial Content\r\n";
}
# print other header info
$boundary="multipart-boundary";
print "Accept-ranges: bytes\r\n";
print "Content-type: multipart/x-byteranges; boundary=$boundary\r\n\r\n";
     
# Serve up the bytes:
     
open(FILE, "< $file");
while (defined ($range = shift(@byterange))) {
     
    ($fbyte, $lbyte) = split('-', $range); 
    $i = index($range,"-");
    if ($i == 0) { $fbyte = -1; }
    if ($fbyte < 0) {
        $fbyte = $size - $lbyte;
        $lbyte = $size;
    }
    $nbytes = $lbyte - $fbyte + 1;
     
    print "\r\n--$boundary\r\n";
    print "Content-type: $contenttype\r\n";
    printf "Content-Range: bytes %d-%d/%d\r\n\r\n", $fbyte, $lbyte, $size;
     
    seek(FILE, $fbyte, 0);
    read(FILE, $buffer, $nbytes);
    print STDOUT $buffer;
}
     
print "\r\n--$boundary--\r\n";
     
exit 0;

こういうのを体験すると、おじさん、印刷業界とIT業界が同じ地平にあると認識を強める次第。