HTTP Header multipart/form-data boundary

Hallo,

hätte eine Frage zu einem HTTP Header. Sieht so aus.

Post: ...\r\n
...
Content-Type: multipart/form-data;
boundary=-----------------------------8863535014426\r\n
Content-Length: ...\r\n
\r\n
-----------------------------8863535014426\r\n
Content-Disposition: form-data; name="..."\r\n
\r\n
KNIPN8787nssd8asd
-----------------------------8863535014426\r\n
Content-Disposition: form-data; name="..."\r\n
\r\n
....
und immer so weiter.

Mein Frage dazu: Wie errechnet der Browser das Boundary und die dazugehörige Content-Length ? Habe ein Eingabefeld mehrmals mit gleichen Eingaben abgeschickt und Header hat immer unterschiedliche Boundaries und eine unterschiedliche length( bei der ich nicht weis, wie sie genau errechnet wird).
 
http://tools.ietf.org/html/rfc2046#section-5.1.1 hat gesagt.:
The boundary delimiter MUST NOT appear inside any of the encapsulated parts, on a
line by itself or as the prefix of any line. This implies that it is
crucial that the composing agent be able to choose and specify a
unique boundary
parameter value that does not contain the boundary
parameter value of an enclosing multipart as a prefix.
oder das eher zugehörige RFC
http://www.ietf.org/rfc/rfc2388.txt (returning Values from Forms: multipart/form-data)
4.1 Boundary

As with other multipart types, a boundary is selected that does not
occur in any of the data. Each field of the form is sent, in the
order defined by the sending appliction and form, as a part of the
multipart stream. Each part identifies the INPUT name within the

So wird's in Chrom(ium) gemacht:
https://github.com/Treeeater/Chromium_on_windows/blob/master/platform/network/FormData.cpp
Code:
m_boundary = FormDataBuilder::generateUniqueBoundaryString();
...
for (unsigned i = 0; i < 4; ++i) {
        unsigned randomness = static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0));
        randomBytes.append(alphaNumericEncodingMap[(randomness >> 24) & 0x3F]);
Mozilla/Fux:
http://people.mozilla.com/~chofmann/l10n/tree/mozilla/content/html/content/src/nsFormSubmission.cpp
Code:
  mBoundary.AssignLiteral("---------------------------");
  mBoundary.AppendInt(rand());
  mBoundary.AppendInt(rand());
  mBoundary.AppendInt(rand());

Boundaries werden also üblicherweise beim Absenden zufällig generiert ;)

Content-Length sollte der Länge des gesendeten Bodies entsprechen.
Also ganz unabhängig vom Type und den Parts - die Länge der Daten nach dem (Header+Leerzeile).
Header hat immer unterschiedliche Boundaries und eine unterschiedliche length
Achte einfach auf die Länge der generierten Boundaries ;)
 
Danke für die schnelle Antwort.
Ok, da es einfach eine Zufallszahl ist, habe ich eine Anfrage mal kopiert und nachgebaut. Es funktioniert aber immer noch nicht. bekomme eine Internal Server error. Hier mal der Code

...
Connection: keep-alive
Content-Type: multipart/form-data; boundary=-----------------------------289401118232439
Content-Length: 722

-----------------------------289401118232439
Content-Disposition: form-data; name="..."

txt
-----------------------------289401118232439
Content-Disposition: form-data; name="..."

txt
-----------------------------289401118232439
Content-Disposition: form-data; name="..."

txt
-----------------------------289401118232439
Content-Disposition: form-data; name="..."

txt
-----------------------------289401118232439
Content-Disposition: form-data; name="..."

txt
-----------------------------289401118232439
Content-Disposition: form-data; name=."..."

txt
-----------------------------289401118232439--

Ich verstehe aber nicht, wieso es nicht geht. baue ja nur genau den Request nach. Habe auch schon andere GET-Request nachgebaut, die funktionieren. Vllt mache ich beim Escapen der Anführungszeichen was falsch.
Sieht im Code so aus :
write("Content-Disposition: form-data; name=\"...\"\r\n");
 
Danke für die schnelle Antwort.
Ok, da es einfach eine Zufallszahl ist, habe ich eine Anfrage mal kopiert und nachgebaut. Es funktioniert aber immer noch nicht. bekomme eine Internal Server error. Hier mal der Code
1. Das Board hat extra dafür [ code ] [ /code ]Tags
code.png
- damit bleibt die Formatierung erhalten ;)
2. Den Server in den Debug-Modus setzen - dann sind die Fehlermeldungen aussagekräftiger.
3. Das ganze Packet vielleicht mal minimaler gestalten, so dass man auch den Fehler einfacher finden kann.

Falls 2 und 3 nicht möglich sind, bräuchte man trotzdem den vollständigen Request und am besten den zugehörigen Codeabschnitt. Aus der schematischen Darstellung werde ich jedenfalls nicht schlau.

Habe auch schon andere GET-Request nachgebaut, die funktionieren. Vllt mache ich beim Escapen der Anführungszeichen was falsch.
Damit wir uns nicht missverstehen: Du sendest aber schon einen POST und nicht GET?
Normalerweise nutzt man dafür ausgereifte Libs ('requests','urllib3' bei Python, curl/libcurl lässt sich auch von sehr vielen Sprachen aus einbinden)
 
Sorry, ja es ist schon ein POST, habe mich nur verschrieben :).

Es ist ein Jetty-Server, aber das ist ja auch egal. Ich schneide ja nur das Protokoll meines Browsers mit (und da funktiooniert alles) und baue den Request nach. Also muss auch hier den Fehler sein.
Der Anfang des Headers ist richtig, habe ich ja schon getestet. Vielleicht mache ich mit den Zeilenumbrüchen was falsch.
Hier nochmal der Code mit CRLFs.

Code:
Connection: keep-alive\r\n
Content-Type: multipart/form-data; boundary=-----------------------------289401118232439\r\n
Content-Length: 722\r\n
\r\n
-----------------------------289401118232439\r\n
Content-Disposition: form-data; name="..."\r\n
\r\n
txt\r\n
-----------------------------289401118232439\r\n
Content-Disposition: form-data; name="..."\r\n
\r\n
txt\r\n
-----------------------------289401118232439\r\n
Content-Disposition: form-data; name="..."
\r\n
txt\r\n
-----------------------------289401118232439--\r\n
 
Zum einen, wie kommst Du hier auf eine Content-Length von 722?
Falls der hier gepostete Body vollständig sein sollte, so komme ich nur auf 349 (wobei der Wert nicht genau stimmen muss, da ich nur C&P + len() in der Konsole gemacht habe)

Vielleicht mal den kompletten Request dumpen und als Datei hier anhängen (denn es ist etwas verwirrend, im Code "\r\n" UND Zeilenumbrüche zu sehen ;) )
Es ist ein Jetty-Server, aber das ist ja auch egal. Ich schneide ja nur das Protokoll meines Browsers mit (und da funktiooniert alles) und baue den Request nach. Also muss auch hier den Fehler sein.
Falls es Dein Server ist, hilft der Debugmodus schon weiter, da dann die Fehlermeldungen deutlich mehr Details enthalten ;)
Jetty/Tutorial/RequestLog - Eclipsepedia
Jetty/Feature/Jetty Logging - Eclipsepedia
 
Ok, danke.
Das ist nicht der ganze Content, die Length stimmt aber, da ich es ja nur vom Browser mitgeschnitten habe.
Das mit den Newlines habe ich nur eingefügt, damit man sieht, falls ich was mit den Zeilenumbrüchen falsch mache.
Werde mir den Request mal nochmal anschauen. Is aber ziehmlich nervig, wenn man den Code sehr oft anschaut und einfach keine Fehler sieht...:)
 
da ich es ja nur vom Browser mitgeschnitten hab
Ist es jetzt die exakte Kopie der Daten, die der Browser sendet (nur eben als Nachbau) oder sind da eigene Daten drin?

Damit man nicht auf Sand baut ;) , ein Requestdumper in Python (2.7)
PHP:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from SocketServer import ThreadingMixIn, TCPServer, BaseRequestHandler


class Server(ThreadingMixIn, TCPServer):
    pass


class Handler(BaseRequestHandler):
    dumpcount = 0
        
    def handle(self):
        Handler.dumpcount += 1
        data = self.request.recv(4096)
        with open('dump%d.txt' % Handler.dumpcount, 'wb') as dumpfile:
            dumpfile.write(data)
        try:
            print "real content-length:", len(data.split("\r\n\r\n", 1)[1])
        except IndexError:
            print "there is no content :("

Server(('localhost', 2000), Handler).serve_forever()
erstellt pro Request eine "dump<num>.txt" und zeigt zudem an, wieviel Bytes als Body rüberkamen.
Die Daten werden als "binary" geschrieben(d.h. nicht durch irgendwelche Autokonvertierungen verstümmelt) - am besten schaut man sich diese mit einem Hexeditor an.
 
Zurück
Oben