hotti: Wo liegen die Daten wirklich?

hi,

Formular: <input id="myfiles" multiple type="file" accept="image/*">

JS:
    document.querySelector("#myfiles").onchange = pullfiles;

und damit in pullfiles:
    var fileInput = document.querySelector("#myfiles");
    var files = fileInput.files;

gibt es den Zugriff auf die Dateiinhalte. Aber wo liegen diese Inhalte wirklich? Ich vermute mal, dass bis hierhin lediglich eine Referenz erzeugt wurde, schwer vorstellbar, dass bspw. Inhalte von 200 Dateien mit insgesamt weit über 300 MB innerhalb von Bruchteilen einer Sekunde in den Hauptspeicher gelesen werden. Also das IO später erfolgt, wenn auf files[0], files[1] usw. zugegriffen wird. Ist das so?

Dankwart Horst

  1. Hallo,

    Also das IO später erfolgt, wenn auf files[0], files[1] usw. zugegriffen wird.

    Auch das gibt dir nur eine Referenz auf ein Dateiobjekt, nicht den Inhalt. Die I/O erfolgt erst, wenn du wirklich mit einem FileReader anfängst zu lesen. Vorher wurde nur ein fstat oder ähnliches aufgerufen.

    Mathias

    1. Hallo,

      Also das IO später erfolgt, wenn auf files[0], files[1] usw. zugegriffen wird.

      Auch das gibt dir nur eine Referenz auf ein Dateiobjekt, nicht den Inhalt. Die I/O erfolgt erst, wenn du wirklich mit einem FileReader anfängst zu lesen. Vorher wurde nur ein fstat oder ähnliches aufgerufen.

      Hab ichs mir doch gedacht, auf Dich ist Verlass, danke Dir!!

      Viele Grüße!

    2. Hallo,

      Also das IO später erfolgt, wenn auf files[0], files[1] usw. zugegriffen wird.

      Auch das gibt dir nur eine Referenz auf ein Dateiobjekt, nicht den Inhalt. Die I/O erfolgt erst, wenn du wirklich mit einem FileReader anfängst zu lesen. Vorher wurde nur ein fstat oder ähnliches aufgerufen.

      So ganz klar isses mir noch nicht, wann genau der I/O erfolgt, weil ich hier keinen FileReader einsetze sondern einfach nur die Blobs als Eigenschaften an ein Objekt zuweise. Vermutlich passierts erst, wenn das XHR-Objekt den Bulk (Blob of Blobs) als Daten übergeben bekommt (für Request-Method PUT).

      Schönes Wochenende,
      Dankwart, Horst

      1. Meine Herren!

        So ganz klar isses mir noch nicht, wann genau der I/O erfolgt, weil ich hier keinen FileReader einsetze sondern einfach nur die Blobs als Eigenschaften an ein Objekt zuweise.

        Mit diesen beiden Zeilen holst du dir Referenz auf ein FileList

        var fileInput = document.querySelector("#myfiles");  
                var files = fileInput.files;
        

        Das FileList-Objekt ist selber relativ uninteressant, interessant sind die File-Objekte, die es enthält.

        Das File-Interface spezifiziert aber auch noch nicht, wie aus der Datei gelesen werden soll. Es wird lediglich empfohlen, dass Browser zum Zeitpunkt des Erstellens erstmal eine Arbeitskopie der Datei anlegen.

        Wie genau gelesen werden soll, wird hingegen durch die read-Operation festgelegt.

        Diese abstrakte read-Operationen kann von verschiedenen anderen Methoden aufgerufen, zum Beispiel von den Methoden: readAsArrayBuffer oder reasAsText.

        Das ist aber immer noch nicht die einzige Möglichkeit, wie Datei-Streams in den Arbeitsspeicher gelangen können. Bei einem 0815-Datei-Upload muss der Browser auch irgendwann die Dateien laden.

        Alles in allem sind die APIs so abstrakt formuliert, dass man völlig agnostisch von der Tatsache, wann die Dateien faktisch im Arbeitsspeicher geladen werden, entwickeln kann. Es kann in einzeln Fällen natürlich trotzdem interessant sein, den genauen Zeitpunkt zu kennen, zum Beispiel, weil Ressourcen-Knappheit herrscht und man die File-API als Flaschenhals identifiziert hat. In dem Fall hilft einem aber die Spezifikation nicht viel weiter, da muss man sich dann die konkreten Implementationen vornehmen.

        --
        “All right, then, I'll go to hell.” – Huck Finn
        1. hi,

          Alles in allem sind die APIs so abstrakt formuliert, dass man völlig agnostisch von der Tatsache, wann die Dateien faktisch im Arbeitsspeicher geladen werden, entwickeln kann.

          Grundsätzlich haste da Recht :)

          Es kann in einzeln Fällen natürlich trotzdem interessant sein, den genauen Zeitpunkt zu kennen, zum Beispiel, weil Ressourcen-Knappheit herrscht und man die File-API als Flaschenhals identifiziert hat. In dem Fall hilft einem aber die Spezifikation nicht viel weiter, da muss man sich dann die konkreten Implementationen vornehmen.

          Mein Ziel, für dessen Umsetzung ich heute Gelegenheit hatte, ist die Nutzung der neuen Features moderner Browser, die so nach und nach das können, was ich seit Jahren mit einem proprietären UserAgent (Perl) mache: Content-Management, d.h., nicht nur Upload/Download sondern beispielsweise auch remote Zugriffe in Datenbanken via HTTP wobei ich dazu auch die Request-Method PUT nutze zum Übertragen komplexer Datenstrukturen, die neben reinen Binaries (Daten aller Genres) auch Code enthalten, welcher dann serverseitig ausgeführt wird. Das braucht keinen Enctype und schon gar nicht eine Verpackung die im Presentation-Layer angesiedelt ist (was habe ich heute gelesen: Präsentation binärer Daten... What the Fuck).

          Das JS-Objekt FormData ist im Prinzip auch nüscht neues, es implementiert hornalte RFCs, die ich schon lange als museumsreif bezeichne, die nur aus Kompatibilitätsgründen immer noch ihre Daseinsberechtigung haben (multipart/form-data). Für eine anwendungsinterne Kommunikation zwischen Browser/XHR und Server (ajax) lässt sich das ganze Geschnatter auf Byte-Ebene runterbrechen, so gibts beim PUT auch keinen Stress mit temporären Dateien auf dem Server und weiteren I/O den der Parser verursacht, sofern POST verwendet wird.

          Multiple-File-Upload mit PUT, Yes, we can!

          Btw., Du 1UP hast mal vor einiger Zeit geschrieben: Zeige mir Dein Framework. Hier ist die wahrscheinlich umfangreichste Dokumentation die ein Framework bekommen kann, extra für Dich und da hst Du Einiges zu lesen :)

          Schönes Wochenende.

          1. Meine Herren!

            Okay, der Zusammenhang ist mir nicht ganz klar, aber Threaddrift ist ja keine Schande.

            Mein Ziel, für dessen Umsetzung ich heute Gelegenheit hatte […]

            Ich finde das unglaublich umständlich. Ich sehe ganz viel Overhead und es findet keine erkennbare Abstraktion statt, die das rechtfertigen würde.

            proprietären UserAgent (Perl)

            Perl ist eine freie Programmiersprache. Ich verstehe den Bezug zu einem Browser auch nicht.

            Das braucht keinen Enctype

            Der Content-Type ist kein unnötiger Ballast, er trägt die Information, wie die Daten zu interpretieren sind.
            Du operierst diese Information weg. Wenn du diese Information mal wieder brauchst, weil deine Anwendung über ein bloßes Daten-"Echo" hinaus geht, musst du das wieder ausbügeln.

            Das JS-Objekt FormData ist im Prinzip auch nüscht neues, es implementiert hornalte RFCs, die ich schon lange als museumsreif bezeichne

            Das FormData-Interface wird vom W3C und WhatWG spezifiziert. Die letzte Version dieses Standards stammt vom 17.01.2012. Und diesen Standard implementieren auch die Browser.

            Für eine anwendungsinterne Kommunikation zwischen Browser/XHR und Server (ajax) lässt sich das ganze Geschnatter auf Byte-Ebene runterbrechen

            Wieso sollte man das wollen? Das gute alte HTTP hat viele nützliche Funktionen. Wenn HTTP ungeeignet ist, würde ich nicht auf Ajax setzen. Dann könnte man sich für ein anderes Kommunikations-Protokoll (WebSocket, WebRTC-basiert) setzen. Ein WebSocket lässt sich auch als Kanal für andere TCP-basierte Protokolle benutzen. Ich sehe jedenfalls keinen praktischen oder theoretischen Nutzen pure binär-Datenströme zu verwenden, wenn man nicht nur pure Binär-Daten verschicken will.

            so gibts beim PUT auch keinen Stress mit temporären Dateien auf dem Server

            Von welchem Stress sprichst du?

            und weiteren I/O den der Parser verursacht, sofern POST verwendet wird.

            Welcher Parser?

            Multiple-File-Upload mit PUT, Yes, we can!

            Das ist auch keine große Kunst:

            var form = document.querySelector('form');  
            var request = new XMLHttpRequest();  
            request.open('PUT);  
            request.send( form );
            

            In Zukunft brauchen wir dafür nicht mal mehr JavaScript:

            <form method="put">

            Btw., Du 1UP hast mal vor einiger Zeit geschrieben: Zeige mir Dein Framework.

            Ich erinnere mich, damals hab ich kritisiert, dass du eine Frage im Forum mit einem Verweis auf dein proprietäres closed-source Framework beantwortet hast. Das habe ich für wenig hilfreich empfunden.

            extra für Dich und da hst Du Einiges zu lesen

            Ich lese ja auch fleißig mit, wenn du uns hier etwas vorsetzt und kommentiere das auch oft.

            --
            “All right, then, I'll go to hell.” – Huck Finn
            1. hi,

              so gibts beim PUT auch keinen Stress mit temporären Dateien auf dem Server

              Von welchem Stress sprichst du?

              und weiteren I/O den der Parser verursacht, sofern POST verwendet wird.

              Welcher Parser?

              Oops, ich denke Du solltest Dir mal angucken, wie der Enctype="multipart/form-data" aussieht bzw. das, was da serverseitig in STDIN ankommt. Natürlich braucht das einen Parser, der so ein vorsintflutliches Vehikel erstmal temporär auf die Platte schreibt um es dann in seine Einzelteile zerlegen zu können anhand der Boundary die im Request-Header mitgesendet wird.

              Erst dann liegen die einzelnen Komponenten mit definierten Content-Types vor, egal ob der Parser PHP oder Perl redet.

              Hier ist die moderne Alternative, ich hab noch was dazu geschrieben.

              Was hierbei die Content-Types betrifft: Die werden selbstverständlich auch übertragen, die liefert schon der Browser. Wenn ich die serverseitig brauche, greife ich nur in den Hash, den nicht ein Parser liefert sondern ein Serializer (nur andersrum) und dieser Hash sieht dem Javascript-Objekt täuschend ähnlich, aber sowas von :)

              Schönen Abend.

              1. Meine Herren!

                Welcher Parser?

                Oops, ich denke Du solltest Dir mal angucken, wie der Enctype="multipart/form-data"

                Ach du redest vom Request-Body der HTTP-Anfrage. Benenn ihn doch so ;)

                der so ein vorsintflutliches Vehikel erstmal temporär auf die Platte schreibt um es dann in seine Einzelteile zerlegen zu können anhand der Boundary die im Request-Header mitgesendet wird.
                Erst dann liegen die einzelnen Komponenten mit definierten Content-Types vor, egal ob der Parser PHP oder Perl redet.

                Das sind doch alles Implementations-Details, die durch schöne Browser-APIs wie FormData von uns abgekapselt werden. Der Browser kümmert sich alleine darum, die Daten in eine HTTP-konforme Form zu bringen. Genau wie der WebServer sich um die empfangenen Daten kümmert und für den Web-Entwickler wieder aufbereitet.

                Was hierbei die Content-Types betrifft: Die werden selbstverständlich auch übertragen, die liefert schon der Browser. Wenn ich die serverseitig brauche, greife ich nur in den Hash, den nicht ein Parser liefert sondern ein Serializer (nur andersrum) und dieser Hash sieht dem Javascript-Objekt täuschend ähnlich, aber sowas von :)

                Tut mir leid, ich kann den Vorteil immer noch nicht erkennen. Im Gegenteil ich halte das sogar für schlechtes Software-Design. Du entscheidest dich bewusst gegen die Standard-Direktive von HTTP um den Content-Type zu übertragen. Stattdessen überträgst du eine Hashmap an den Server. Server und Client müssen also wissen wie diese Hashmap aufgebaut ist. Dieses gemeinsame Wissen, um die Hashmap, lässt sich als Protokoll interpretieren. Solange Server und Client dieses Protokoll sprechen ist das alles schön und gut. Einen qualitativen Mehrwert bietet dein Protkoll, gegenüber HTTP aber nicht. Du beschneidest erst das Potenzial von HTTP und baust es dann wieder nach.  Du replizierst damit also nur wieder das Verhalten von HTTP, du entwickelst eine innere Platform, das ist ein bekanntest Anti-Pattern, auch wenn die Ausmaße sich in deinem Fall in bescheidenen Grenzen halten. Wenn dir als nächstes aber der Gedanke kommen sollte die HTTP-Verben POST, GET usw. zu ersetzen, dann solltest du dich spätestens daran erinnern ;) Das Hauptproblem damit ist, dass deine Anwendung nicht mehr in der Lage ist mit jedem anderen herkömmlichen WebServer zu reden, weil sie dein Protokoll nicht sprechen. Mal als Beispiel: Wenn du die Daten so an einen Apache mit PHP sendest, landen die Dateien nicht erwartungsgemäß im $_FILES-Array. Der PHP-Entwickler müsste also auch erstmal dein Protokoll implementieren. Natürlich fällt immer Arbeit an, wenn ein System in ein anderes System migriert werden muss, aber in diesem Fall ließe sich das vermeiden.

                und dieser Hash sieht dem Javascript-Objekt täuschend ähnlich, aber sowas von :)

                Ich finde dieser Hash sollte nur die Daten halten, und keine Informationen darüber wie diese Daten interpretiert werden sollen. Letzeres sollte auf einer niedrigeren Protokollschicht geschehen, dann sind diese Aspekte sauber entkoppelt.

                Die eigentlichen Daten (wenn es keine Binärdaten sind) würde ich auch nicht als Blob (der Name kommt nich von ungefähr) versenden, da würde ich zu JSON greifen, das ist menschenlesbar, maschinenlesbar, im Web zu Hause und wohl auch der zukunftsträchtigste Kandidat.

                CouchDB ist für mich eine große Inspiration beim Entwurf von klar strukturierten HTTP-Schnittstellen.

                --
                “All right, then, I'll go to hell.” – Huck Finn
      2. Hallo,

        weil ich hier keinen FileReader einsetze sondern einfach nur die Blobs als Eigenschaften an ein Objekt zuweise. Vermutlich passierts erst, wenn das XHR-Objekt den Bulk (Blob of Blobs) als Daten übergeben bekommt (für Request-Method PUT).

        Ehrlich gesagt durchblicke ich deinen Code nicht und verstehe auch ich nicht, warum du da so ein Gefummel machst, aber ich würde sagen: ja, erst wenn du die Blobs letztlich an XHR#send übergibst, wird der Dateiinhalt eingelesen.

        Mathias

  2. Moin,

    es gibt noch ein anderes, uraltes Problem, welchem ich hier entgegentrete: Abhörsicherheit bei Uploads.

    Mal ein bischen weiter ausgeholt:

    Beim Datei-Upload werden serverseitig temporäre Dateien angelegt, das ist in PHP genauso wie in Perl.

    Die Sicherheitslücke besteht darin, dass in dem Zeitraum, wo es diese temporären Dateien gibt, ein Eindringling (Hacker) auf dem Server auch Zugriff darauf hat. Ein bösartiger Hacker kann diese Daten also für eigene Zwecke missbrauchen, ohne dass der Anwender etwas davon mitbekommt.

    Meine Entwicklung ermöglicht Uploads unter Verzicht auf temporäre Dateien.

    Somit sind derartige Lauschangriffe nicht mehr möglich.

    MfG

    1. Hello,

      es gibt noch ein anderes, uraltes Problem, welchem ich hier entgegentrete: Abhörsicherheit bei Uploads.

      Mal ein bischen weiter ausgeholt:

      Beim Datei-Upload werden serverseitig temporäre Dateien angelegt, das ist in PHP genauso wie in Perl.

      Die Sicherheitslücke besteht darin, dass in dem Zeitraum, wo es diese temporären Dateien gibt, ein Eindringling (Hacker) auf dem Server auch Zugriff darauf hat. Ein bösartiger Hacker kann diese Daten also für eigene Zwecke missbrauchen, ohne dass der Anwender etwas davon mitbekommt.

      Wenn ein Eindringling der Klasse "NSA" etwas lesen will, dann benötigt er keine temporären Dateien dafür. Er hat vollen Zugriff auf Leitungen und Host, mit allen darauf befindlichen Servern und Filesystemen.

      Wenn Du allerdings an die Sicherheitslücke zwischen den Nutzern denkst, die es beim Shared Hosting oft gibt bei Sessiondaten und bei Temporärdateien, da die bei falsch eingerichteten Systemen gemeinsam genutzt werden, dann gebe ich Dir Recht. Die sit aber behebbar. Und die NSA oder [deleted] professionelle Kriminlelle werden sich damit bestimmt nicht abgeben.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      Die ultimative Seite für Selbermacher
    2. Hallo,

      Die Sicherheitslücke besteht darin, dass in dem Zeitraum, wo es diese temporären Dateien gibt,

      Du meinst wahrscheinlich, dass /tmp und die fraglichen Dateien world-readable sind und dem User gehören, unter dem der Perl-Prozess läuft, also für andere Nutzer auf dem Server prinzipiell lesbar. Das ist bei Shared-Hostern natürlich ein Problem, weshalb sie m.W. zumindest tmp-Verzeichnisse pro User verwenden.

      ein Eindringling (Hacker) auf dem Server auch Zugriff darauf hat.

      Angenommen der Hacker hat den Server geknackt und Root-Zugriff, hat er kompletten Zugriff auf sämtliche Web-Kommunikation. Ob die Datei dann /tmp durchläuft oder nicht, ist nicht mehr ausschlaggebend.

      Ein bösartiger Hacker kann diese Daten also für eigene Zwecke missbrauchen, ohne dass der Anwender etwas davon mitbekommt.

      Und der Hacker kann das nach dem Abschluss des Uploads mit den persistenten Dateien nicht mehr?! Speicherst du die Datei etwa nicht auf dem Server…?

      Von solcher IT-Security sollte man als Laie die Finger lassen. Schon gar nicht Versprechungen machen, man könne mit primitiven Maßnahmen die systematische und totale Internetüberwachung von staatlichen Stellen umgehen. Das ist äußerst unseriös und zeigt, dass man von Angriffsvektoren wenig verstanden hat.

      Mathias

      1. Moin molily,

        ein Eindringling (Hacker) auf dem Server auch Zugriff darauf hat.

        Angenommen der Hacker hat den Server geknackt und Root-Zugriff, hat er kompletten Zugriff auf sämtliche Web-Kommunikation. Ob die Datei dann /tmp durchläuft oder nicht, ist nicht mehr ausschlaggebend.

        /dev/kmem bzw /dev/mem nicht zu vergessen.

        Von solcher IT-Security sollte man als Laie die Finger lassen. Schon gar nicht Versprechungen machen, man könne mit primitiven Maßnahmen die systematische und totale Internetüberwachung von staatlichen Stellen umgehen. Das ist äußerst unseriös und zeigt, dass man von Angriffsvektoren wenig verstanden hat.

        ACK.

        LG,
         CK