# HTTPS-Requests an Server: POST-Parameter kommen nicht an



## threadi (30. Okt 2017)

Hi,

folgende Situation:
Ich habe auf einem Apache-Webserver mehrere Webseiten liegen die allesamt einzig per SSL erreichbar sind (inkl. HSTS etc.). Innerhalb der Seiten gibt es Formulare, auch mit Dateiupload, die ganz normal funktionieren und täglich von Dutzenden Besuchern normal genutzt werden. Die allermeisten Webseiten laufen mit PHP 7.0 über php-fpm, einige wenige noch auf Grund meines unten beschriebenen Problems mit PHP 5.6 über mod-php.

Jetzt habe ich einen Java-Client der auf den lokalen PCs von einigen hundert Leuten installiert ist. Dieser erzeugt in bestimmten Situationen HTTP-Requests an den Server (ebenfalls ausschließlich per SSL). Und hier entsteht auch mein Problem:

Requests vom Java-Client an den Server enthalten je nach Verwendungszweck eine unterschiedliche Anzahl POST-Parameter.
Sobald der angesprochene Vhost am Server mit PHP-FPM und PHP in Version 5.6 oder 7.0 läuft, kommen die POST-Parameter dort gar nicht am Script an.
Sobald der Vhost mit mod_php und PHP 5.6 läuft, kommen sie korrekt an.
Es ist dabei egal wie groß der Stream ist oder ob ich Binärdaten mitsende oder nicht. Es passiert auch wenn ich nur 1 POST-Parameter mit dem Wert 1 schicke.

Im Java baue ich die Requests mit folgender Funktion zusammen:


```
private String httpsPostRequest() throws IOException {
   // set the boundary for the parameters in this request
   String boundary = Long.toHexString(System.currentTimeMillis());

   // set the charset for this request
   String charset = "UTF-8";

   // set the linebreak
   String CRLF = "\r\n";

   // 1. step: get the URL
   URL myurl = new URL(this.url);

   // 2. step: open the connection and set its properties
   HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();

   // -> enable the usage of output from the request
   con.setDoOutput(true);

   // -> optimize httprequest-performance because we don't know the size of the
   //      transfered request
   con.setChunkedStreamingMode(-1);

   // -> send only POST-Requests
   con.setRequestMethod("POST");

   // -> set the timeout to 20000ms
   con.setConnectTimeout(20000);

   // -> set HTTP-Header-Data
   con.setRequestProperty("Accept-Encoding", "deflate");
   con.setRequestProperty("Accept-Language", config.getLanguage().toString() + "-" + config.getLanguage().toString());
   con.setRequestProperty("Pragma", "no-cache");
   con.setRequestProperty("Cache-Control", "no-cache");

   // -> set UserAgent
   //    -> do not change this because it's important for communication with the mapBase
   con.setRequestProperty("User-Agent", "mybrowser");

   // 3. step: if PHP-SessionId is available use it in HTTP-Header
   if( this.phpSessionId != null )
   {
       con.setRequestProperty("Cookie", "PHPSESSID=" + this.phpSessionId);
   }

   // 4. step: if token is available use it in the parameter-list
   if( this.token != null )
   {
       this.params.put("token", this.token);
   }
          
   // 5. step: set the parameter
   con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
   try (
       OutputStream output = con.getOutputStream();
       PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
   ) {
       // send the normal text-parameters
       if( !this.params.isEmpty() ) {
           for(Entry<String, String> entry : this.params.entrySet()) {
               String key = entry.getKey();
               String value = entry.getValue();
               // add normal parameter to the HTTP-Request
               writer.append("--" + boundary).append(CRLF);
               writer.append("Content-Disposition: form-data; name=\"" + key + "\"").append(CRLF);
               writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
               writer.append(CRLF).append(value).append(CRLF).flush(); // value and end of boundary
           }
       }
      
       // send the binary-data
       if( !this.binaryfiles.isEmpty() ) {
           for(Entry<String, File> entry : this.binaryfiles.entrySet()) {
               String key = entry.getKey();
               File binaryFile = entry.getValue();
              
               // add binary-file-data to the HTTP-Request
               writer.append("--" + boundary).append(CRLF);
               writer.append("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
               writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
               writer.append("Content-Transfer-Encoding: binary").append(CRLF);
               writer.append(CRLF).flush();
               Files.copy(binaryFile.toPath(), output);
               output.flush(); // important before continuing with writer!
               writer.append(CRLF).flush(); // end of boundary
           }
       }
       // end of multipart/form-data.
       writer.append("--" + boundary + "--").append(CRLF).flush();
       writer.flush();
       writer.close();
   }
   catch(IOException e) {
       // add this error to the list which could be used
       // from the calling function to analyze the problem
       // and show appropriated messages to the user
       this.error.add(e.getMessage());
   }
   InputStream ins = con.getInputStream();
   InputStreamReader isr = new InputStreamReader(ins, "UTF-8");
   BufferedReader in = new BufferedReader(isr);
   String inputLine;
   StringBuffer responseBuffer = new StringBuffer();
   while( (inputLine = in.readLine()) != null ) {
       responseBuffer.append(inputLine + "\n");
   }
   return responseBuffer.toString();
}
```


Wenn ich mit curl den gleichen Request zusammensetze, kommen die POST-Parameter normal an (auch bei PHP 7.0). Daher tippe ich derzeit auf ein Problem beim Zusammenbauen der Header in o.g. Java-Code.

Habt ihr dazu irgendeine Idee?


----------



## mrBrown (30. Okt 2017)

Du könntest mal mit netcat vergleichen


----------



## threadi (30. Okt 2017)

Hab schon mit Wireshark versucht den Datenverkehr abzugreifen. Da er SSL-verschlüsselt ist hab ich hier kaum eine Chance. :/


----------



## mrBrown (30. Okt 2017)

Wie gesagt: netcat 

Uns versuchs doch der Einfachheit-halber ohne ssl und auf localhost...


----------



## threadi (30. Okt 2017)

An netcat bin ich dann verzweifelt, kenne mich eher mit tcpdump aus  Und dort sehe ich die Daten ankommen.
Ohne SSL hatte ich es auch schon probiert, ebenso ohne Erfolg. 

Aber dein Hinweis mit localhost brachte mich darauf den Request mal an einen anderen Server zu schicken - dort bekomme ich den HTTP Status 411 zurück. Falls der jemanden nichts sagt: die Länge für den POST-Request fehlt. In o.g. Code wird der Stream auf Chunked gesetzt, was bei Nutzung von php-fpm auf dem Server offenbar nicht gut ankommt.

In der Hoffnung, dass dies nun die Ursache ist muss ich wohl meinen o.g. Code so überarbeiten, dass die reale Stream-Länge mitgeschickt wird damit der Server das dann annimmt. :/ Hab gerad keine Idee wie, aber ist ja auch schon wieder spät


----------



## mrBrown (30. Okt 2017)

Den Content erst in ein Byte-Array schreiben, zb mit ByteArray*Streams. Damit kommst du an die Länge, und kannst die zusammen mit dem Body setzen.

Bei netcat reichst hierfür, es einfach zu starten und an nem Port lauschen zu lassen, dann wird alles ankommende geprinted


----------

