[java] NULL-bytes in requestbody by com.sun.net.httpserver.*

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
Ik ben een klein webservertje aan't schrijven en heb te maken met vervelende verdwaalde NULL-bytes.

Zodra ik een POST-request stuur met een lengte rond de 1000 bytes, verschijnen er zomaar NULL-bytes na ongeveer 950 bytes.

De code die ik gebruik is deze testcode:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.IOException;
import com.sun.net.httpserver.*;
import java.net.*;

public class Main {
    public static void main(String[] args) {
        try {
            HttpServer server = HttpServer.create(new InetSocketAddress(8080), 120);
            server.createContext("/", new HttpHandler() {
                public void handle(HttpExchange he) throws IOException {
                    String contentType = he.getRequestHeaders().getFirst("Content-Type");
                    if(contentType.startsWith("application/x-www-form-urlencoded")) {
                        String lengthString = he.getRequestHeaders().getFirst("Content-Length");
                        if(lengthString != null) {
                            int contentLength = Integer.parseInt(lengthString);
                            if(contentLength>0) {

                                byte[] bytes = new byte[contentLength]; 
                                he.getRequestBody().read(bytes); //Hier worden de bytes gelezen

                                StringBuilder hexdump = new StringBuilder();
                                for(int rp=0;rp<bytes.length;rp++) {
                                    if(rp%32==0) {
                                        hexdump.append('\n');
                                    } else if(rp%4==0) {
                                        hexdump.append(' ');
                                    }
                                    String hex = Integer.toHexString(bytes[rp]);
                                    if(hex.length()==1) {
                                        hexdump.append('0');
                                    }
                                    hexdump.append(hex);
                                }
                                System.out.println(hexdump);

                                String string = new String(bytes, "UTF-8");
                                System.out.println(string.length()+", "+bytes.length+", "+contentLength);
                                System.out.println(string);

                                he.close();
                            }
                        }
                    }
                }
            });
            server.start();
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}


Als ik met firefox de volgende POST-request verstuur:
code:
1
Content-Type: application/x-www-form-urlencoded Content-Length: 1102 msg=123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789+END

Bron: firebug NET-tab

Dan krijg ik de volgende output te zien van mijn java-app:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
6d73673d 31323334 35363738 392b3132 33343536 3738392b 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 39253044 25304131 32333435
36373839 2b313233 34353637 38392b31 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 25304425 30413132 33343536 3738392b 31323334
35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536
37383925 30442530 41313233 34353637 38392b31 32333435 36373839 2b313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392530 44253041
31323334 35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 39253044 25304131 32333435 36373839
2b313233 34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31
32333435 36373839 25304425 30413132 33343536 3738392b 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536 37383925
30442530 41313233 34353637 38392b31 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 2b313233 34353637 38392530 44253041 31323334
35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536
3738392b 31323334 35363738 39253044 25304131 32333435 36373839 2b313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435
36373839 25304425 30413132 33343536 3738392b 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 392b3132 33343536 37383925 30442530
41313233 34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31
32333435 36373839 2b313233 34353637 38392530 44253041 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536 3738392b
31323334 35363738 39253044 25304131 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435 36373839
25304425 30413132 33343536 3738392b 31323334 35363738 392b3132 33343536
3738392b 31323334 35363738 392b3132 33343536 37383925 30442530 41313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435
36373839 2b313233 34353637 38392530 44253041 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 392b3132 33343536 3738392b 31323334
35363738 39253044 25304131 32333435 36373839 2b313233 34000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 0000
1102, 1102, 1102
msg=123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+1234


Nou is mijn vraag: Wat is hier aan de hand? Waarom wordt de request zomaar afgesneden? Waarom verschijnen er NULL-bytes zonder een EOFException?

btw, de documentatie van com.sun.net.httpserver.* is hier te vinden:
http://java.sun.com/javas...rver/package-summary.html

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Lees even de JavaDoc van InputStream.read() (kijk vooral naar wat de methode teruggeeft en wat dat betekent).

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
Herko_ter_Horst schreef op woensdag 17 maart 2010 @ 20:47:
Lees even de JavaDoc van InputStream.read() (kijk vooral naar wat de methode teruggeeft en wat dat betekent).
Aaah, dus moet het gewoon in een loop gooien en de gelezen bytes achter elkaar plakken, totdat die -1 teruggeeft.
Even proberen.

edit:
Ah het werkt.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
6d73673d 31323334 35363738 392b3132 33343536 3738392b 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 39253044 25304131 32333435
36373839 2b313233 34353637 38392b31 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 25304425 30413132 33343536 3738392b 31323334
35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536
37383925 30442530 41313233 34353637 38392b31 32333435 36373839 2b313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392530 44253041
31323334 35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 39253044 25304131 32333435 36373839
2b313233 34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31
32333435 36373839 25304425 30413132 33343536 3738392b 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536 37383925
30442530 41313233 34353637 38392b31 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 2b313233 34353637 38392530 44253041 31323334
35363738 392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536
3738392b 31323334 35363738 39253044 25304131 32333435 36373839 2b313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435
36373839 25304425 30413132 33343536 3738392b 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 392b3132 33343536 37383925 30442530
41313233 34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31
32333435 36373839 2b313233 34353637 38392530 44253041 31323334 35363738
392b3132 33343536 3738392b 31323334 35363738 392b3132 33343536 3738392b
31323334 35363738 39253044 25304131 32333435 36373839 2b313233 34353637
38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435 36373839
25304425 30413132 33343536 3738392b 31323334 35363738 392b3132 33343536
3738392b 31323334 35363738 392b3132 33343536 37383925 30442530 41313233
34353637 38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435
36373839 2b313233 34353637 38392530 44253041 31323334 35363738 392b3132
33343536 3738392b 31323334 35363738 392b3132 33343536 3738392b 31323334
35363738 39253044 25304131 32333435 36373839 2b313233 34353637 38392b31
32333435 36373839 2b313233 34353637 38392b31 32333435 36373839 25304425
30413132 33343536 3738392b 31323334 35363738 392b3132 33343536 3738392b
31323334 35363738 392b3132 33343536 37383925 30442530 41313233 34353637
38392b31 32333435 36373839 2b313233 34353637 38392b31 32333435 36373839
2b313233 34353637 38392b45 4e44
1102, 1102, 1102
msg=123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789%0D%0A123456789+123456789+123456789+123456789+123456789+END

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
try {
    HttpServer server = HttpServer.create(new InetSocketAddress(8080), 120);
    server.createContext("/", new HttpHandler() {
        public void handle(HttpExchange he) throws IOException {
            String contentType = he.getRequestHeaders().getFirst("Content-Type");
            if(contentType.startsWith("application/x-www-form-urlencoded")) {
                String lengthString = he.getRequestHeaders().getFirst("Content-Length");
                if(lengthString != null) {
                    int contentLength = Integer.parseInt(lengthString);
                    if(contentLength>0) {

                        int offset = 0;
                        byte[] bytes = new byte[contentLength];
                        do {
                            int readBytes = he.getRequestBody().read(bytes,offset,contentLength-offset);
                            offset += readBytes;
                        } while(offset < contentLength);

                        StringBuilder hexdump = new StringBuilder();
                        for(int rp=0;rp<bytes.length;rp++) {
                            if(rp%32==0) {
                                hexdump.append('\n');
                            } else if(rp%4==0) {
                                hexdump.append(' ');
                            }
                            String hex = Integer.toHexString(bytes[rp]);
                            if(hex.length()==1) {
                                hexdump.append('0');
                            }
                            hexdump.append(hex);
                        }
                        System.out.println(hexdump);

                        String string = new String(bytes, "UTF-8");
                        System.out.println(string.length()+", "+bytes.length+", "+contentLength);
                        System.out.println(string);

                        he.close();
                    }
                }
            }
        }
    });
    server.start();
} catch(Exception e){
    e.printStackTrace();
}


Bedankt :D
Dat was nog eens een snelle oplossing :P

edit:
owja, als er nu -1 teruggegeven wordt het je een eindeloze loop, maar dat los ik wel op :P

[ Voor 86% gewijzigd door Gamebuster op 17-03-2010 20:57 ]

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Dat, en er niet vanuit gaan dat je array helemaal volgelezen is.

Verder zou ik de content length header niet persé vertrouwen. En er in elk geval niet van afhankelijk zijn (wat als die header niet gezet is?).
Bedankt :D
Dat was nog eens een snelle oplossing :P
NP. Er staan dan ook werkelijk de gekste dingen in de JavaDoc, zelfs hoe je een methode moet gebruiken ;)

[ Voor 82% gewijzigd door Herko_ter_Horst op 17-03-2010 20:59 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
Herko_ter_Horst schreef op woensdag 17 maart 2010 @ 20:53:
Dat, en er niet vanuit gaan dat je array helemaal volgelezen is.

Verder zou ik de content length header niet persé vertrouwen. En er in elk geval niet van afhankelijk zijn (wat als die header niet gezet is?).


[...]


NP. Er staan dan ook werkelijk de gekste dingen in de JavaDoc, zelfs hoe je een methode moet gebruiken ;)
Als de header niet gezet is, is er geen request body. Dan wordt er niks gelezen.

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Ok, kan zijn dat jouw clients zo in elkaar zitten, maar volgens de RFC is de content length header niet verplicht, daarom noemde ik het even.

[ Voor 50% gewijzigd door Herko_ter_Horst op 17-03-2010 21:11 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:20
Sowieso is er geen garantie dat de gegeven content length ook correct is. De server gebruikt die data wel om te zien waar de ene request eindigt en de volgende begint (wat nodig is om persistente connecties te ondersteunen) maar bij het afhandelen van individuele requests heb je 'm eigenlijk niet echt nodig. Lees gewoon alle beschikbare data (dus lezen tot read() een waarde kleiner dan 0 returnt) en doe 't daarmee.

Acties:
  • 0 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 15-09 23:08
Soultaker schreef op woensdag 17 maart 2010 @ 21:27:
Sowieso is er geen garantie dat de gegeven content length ook correct is. De server gebruikt die data wel om te zien waar de ene request eindigt en de volgende begint (wat nodig is om persistente connecties te ondersteunen) maar bij het afhandelen van individuele requests heb je 'm eigenlijk niet echt nodig. Lees gewoon alle beschikbare data (dus lezen tot read() een waarde kleiner dan 0 returnt) en doe 't daarmee.
En persistent connections dan?
Of zal ik dat alleen doen wanneer er wel een request-body moet zijn volgens de request method maar er geen content-length is opgegeven? Bijv.:

code:
1
2
3
POST / HTTP/1.0

a=1&b=2


^ Die request is dus gewoon valid (?) maar wordt op dit moment niet ondersteund door mijn server. Als ik toch de body ga lezen tot het einde wanneer er geen content-length opgegeven is werkt die request gewoon. Of zijn er ook andere gevallen waar ik rekening mee moet houden?

Overigens heb ik aardig wat voorbeeld-requests laten log'gen maar ben volgens mij nog nooit zo'n request tegen gekomen, maar dat kan ook komen omdat ik toen vooral aan het letten was op de requests zelf en niet zo zeer op POST-requests.

[ Voor 28% gewijzigd door Gamebuster op 17-03-2010 22:27 ]

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:20
Ik ben niet bekend met Sun's HttpServer implementatie, maar ik neem aan dat die er voor zorgt dat je binnen een request niet voorbij het einde van de request body kan lezen. Of de server daar de waarde van de Content-Length header voor gebruikt, of een andere manier, maakt voor het afhandelen van zo'n request niet uit. :)
Overigens heb ik aardig wat voorbeeld-requests laten log'gen maar ben volgens mij nog nooit zo'n request tegen gekomen, maar dat kan ook komen omdat ik toen vooral aan het letten was op de requests zelf en niet zo zeer op POST-requests.
De meest gangbare browsers zullen de Content-Length wel gewoon meesturen, maar het is natuurlijk netter om daar niet van uit te gaan.

Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Soultaker schreef op woensdag 17 maart 2010 @ 23:13:
De meest gangbare browsers zullen de Content-Length wel gewoon meesturen, maar het is natuurlijk netter om daar niet van uit te gaan.
Als je HTTP 1.1 ondersteunt, dan moet je ook om kunnen gaan met chunked data.

[ Voor 34% gewijzigd door Remus op 19-03-2010 14:24 ]

Pagina: 1