Moin Moin!
Warum reitest Du eigentlich so auf Handles herum?
Ich bin halt ein Low-Level-Fuzzi ;)
Nö, Du frickelst ziemlich planlos herum.
Du willst doch ohnehin einen (binären) String verarbeiten, und so lange der nicht zu groß für den Speicher wird, kannst Du den String direkt weiterverarbeiten. Da sind außer dem HTTP-Socket überhaupt keine Handles im Spiel.
BinärSequenzen in einen String (scalar) schreiben ist ok, aber Lesen erfordert ein Handle, ein String ist dafür ungeeignet.
Woher kommt denn diese Fehlinformation? Ist die aus Deinem Kopf gewachsen oder hat Dir jemand diesen Unsinn eingeflüstert?
So lange ich in Perl 5 einen String nicht explizit als Unicode-String kennzeichne (Encode, :utf8- und :encoding-Layer für Filehandles, XS-Module die Unicode-Strings liefern wie z.B. DBD::ODBC, ...), gilt: 1 Zeichen = 1 Byte. Das kann ich notfalls per use bytes;
erzwingen. Anders als in C gibt es in Perl keine "magischen" Bytes in Strings, die irgendeine besondere Bedeutung haben. Ein String kann jedes beliebige Byte enthalten, und so viele Bytes, wie es der zur Verfügung stehende reale und virtuelle Speicher erlaubt.
Eine Binary wird Byte für Byte (oder SeqenzLänge für SequenzLänge) aus einem Handle gelesen mit der Funktion, die aus einem Handle lesen kann: read().
Ach ja?
use strict;
use warnings;
use 5.010;
my $data=''; $data.=chr(rand(256)) for 1..30;
while ($data=~/\G(.{5})/g) {
my $rec=$1;
printf '%02x',ord substr($rec,$_,1) for 0..4;
print "\n";
}
say "---";
my $d=$data;
while (length($d)>=5) {
my $rec=substr($d,0,5,'');
say unpack('H10',$rec);
}
say "---";
my @recs=unpack('(H10)*',$data);
say for @recs;
unpack, pack, perlpacktut, substr, \G in perlop
Vielleicht kann ich Dich ein bischen neugierig machen: Ich entwickle z.Z. (solange ich die Zeit noch habe) ein System zum Übertragen von Binaries über HTTP als Client-Server-Anwendung. Die Binaries können Multipart-Messages sein, MP3s oder DB-Dumps oder was auch immer (auch Text), das System ist unabhängig von Inhalten und damit auch unabhängig von Zeichenkodierungen; es geht eben nur um Bytes (Darstellung auch, aber später und woanders).
Ist schon fertig, wird im allgemeinen als HTTP-Upload bezeichnet. Ursprung in RFC 1867 von 1995, PUT als Alternative zu POST in RFC 2616 von 1999.
Dieses System ist, so ganz nebenbei, auch als schlanke Alternative zu XML
Was soll XML in dieser Diskussion? Klar, wenn ich irgendwelche Daten in XML stopfe, kann ich die fast beliebig aufblähen.
oder Multipart-Messages nach dem MIME-Standard
Die brauchst Du bei PUT nicht.
brauchbar und funktioniert derzeit in meinen Tests einwandfrei.
Du hast HTTP PUT neu erfunden. Gratulation.
Zu STDIN am Server: Ich habe u.a. ein Script, das ist nicht über Parameter, sondern per (custom) HTTP-Header gesteuert. Damit ist der Message-Body (STDIN) frei von Parametern, Boundaries oder sonstigen Controls, die dem Script mitteilen, was es machen soll, das steht alles im Header. STDIN kann somit bytegenau gelesen werden, da steht z.B. eine Binary und warum sollte ich die erst irgendwo anders hinschreiben!? Zu unnötigen Kopieren kannst Du ja selbst ein Liedchen singen;)
STDIN funktioniert nur, weil Du die CGI-Schnittstelle benutzt. Die vom Netz kommenden Daten werden dafür eine ganze Weile durch die Gegend geschaufelt, bis sie Deinem CGI häppchenweise angefüttert werden. Sobald du eine schnelle Schnittstelle zum Webserver (mod_perl, FastCGI, ...) benutzt, funktioniert das nicht mehr, außer über eine lahme Emulationsschicht.
Dein Webserver hat STDIN garantiert geschlossen oder auf /dev/null umgebogen, wie es sich für einen Daemon gehört.
Btw.:
use strict;
use Data::Dump;
use myConfig qw($cfg);
$| = 1;
my %attr = (
'host' => 'rolfrost',
'method' => 'GET',
'uri' => '/cgi-bin/geheim.cgi',
'callback' => &callback,
'auth' => $cfg->{http}->{auth}, # Authorization: Basic encode_base64('usr:pass','')
);
binmode STDOUT;
my $s = Net::HTTP10->new(%attr) or die "Kein Socket";
$! fehlt.
#print Data::Dump::dump $s;
$s->request;
my $href = $s->read_headers;
Kommt read_headers mit [link:http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2@title=umbrochenen Header-Zeilen] klar? Und ja, die [link:http://ftp.ics.uci.edu/pub/ietf/http/rfc1945.html#Message-Headers@title=gibt's auch bei HTTP/1.0].
Weitere Gemeinheiten des Protokolls erspare ich uns an dieser Stelle mal.
print Data::Dump::dump $href;
#$s->body_callback; # Läuft ;)
>
> Ja, die gute alte Version HTTP/1.0. Kein Transfer-Encoding und keine Chunks, Body as Rock ;)
Kein HTTP PUT.
Keine Name-based virtual Hosts. Und damit für Leute, die kleinen Webspace bei großen Hostern nutzen, absolut unbrauchbar. Denn ohne HTTP/1.1 mit Host-Header enden alle Anfragen beim Default-VHost, der bestenfalls ein 404 Not Found zurückgibt.
Strato antwortet so auf einen HTTP/1.0 GET-Request (GET / HTTP/1.0):
HTTP/1.1 200 OK
Date: Mon, 21 Mar 2011 10:42:11 GMT
Server: Apache/2.2.17 (Unix)
Last-Modified: Wed, 22 Sep 2004 15:30:14 GMT
ETag: "fa92-3de-3e4af6c172d80"
Accept-Ranges: bytes
Content-Length: 990
Connection: close
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>Bitte benutzen sie nicht die IP Adresse des Servers</TITLE>
</HEAD>
<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
<BODY
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#000080"
ALINK="#FF0000"
>
<BR><BR><BR><BR>
<H1 ALIGN="CENTER">
Bitte benutzen sie nicht die IP Adresse des Servers, sondern immer
www.<Wunschname>.de !!
</H1>
<HR>
<DIV ALIGN="CENTER">
<TABLE BORDER="0">
<TR>
<TD ALIGN="center" colspan=2>
<A HREF="http://www.wunschname.de"><IMG SRC="http://www.strato.de/setup/images\_setup/visual.gif" BORDER="0" ALT="www.WUNSCHNAME.de"></A>
</TD>
<TR></TR>
<TD ALIGN="center">
<A HREF="http://www.strato.de"><IMG SRC="http://www.strato.de/images/wir/navlinks/a.gif" HEIGHT="149" BORDER="0" ALT="STRATO AG"></A>
</TD>
</TR>
</TABLE>
</DIV>
</BODY>
</HTML>
Man beachte den Status und das Protokoll:
HTTP/1.1 200 OK
Das ist dem Inhalt nach eine 404-Seite, und sollte IMHO auch mit dem Status 404 ausgeliefert werden, nicht mit Status 200.
Außerdem antwortet der Server auf eine HTTP/1.0-Anfrage mit einer HTTP/1.1-Response, die ein HTTP/1.0-Client vermutlich gar nicht vollständig verstehen kann. Hier verläßt sich Strato bzw. der Apache 2.2 offenbar sehr darauf, dass HTTP/1.0-Clients erstens fast ausgestorben sind und zweitens die ganzen zusätzlichen HTTP/1.1-Header stumpf ignorieren.
Die gleiche Response bekommt man auch für willkürlich ausgewürfelte Requests wie "GET /kjfhwkehfiwufhweiuhfwiuefhweiufhweiufhweiufhweiufhweifuwhefiu HTTP/1.0", und, was besonders problematisch sein kann, auch für "GET /cgi-bin/geheim.cgi HTTP/1.0".
>
> ~~~perl
> package Net::HTTP10; # mein neues Modul
>
> use strict;
> use IO::Socket;
> use vars qw(@ISA);
> @ISA = qw(IO::Socket);
[link:http://perldoc.perl.org/vars.html@title=use vars ist obsolete]. [link:http://perldoc.perl.org/functions/our.html@title=our] ist das neue use vars.
Und speziell für Vererbung nutzt man seit Jahren [link:http://perldoc.perl.org/base.html@title=use base] oder das schlankere [link:http://perldoc.perl.org/parent.html@title=use parent].
> use warnings;
Warum erst hier?
> use Carp;
>
HTTP::Request, HTTP::Response, LWP::UserAgent
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".