# FileUpload mit commons HttpClient



## FriFra (24. Mai 2010)

Hallo zusammen, 

ich versuche gerade erfolglos eine Datei hoch zu laden...

HTML-Form:

```
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Rufnummern (Kurzwahl- und Telefonbuch)</title>
</head>

<body class="d3">
<form name="import_form" method="post" action="http://192.168.123.8/telefonbuch_kurzwahl?im_file=kurzwahlen&actionNo=12" accept-charset="ISO-8859-1" enctype="multipart/form-data">
<input type="file" name="im_file" size="70">
<input type=submit>
</form>
</body>
</html>
```

Mein Java-Code sieht wie folgt aus:

```
...
				httpost = new HttpPost(sURL+"/telefonbuch_kurzwahl?im_file=kurzwahlen&actionNo=12");
				File file = new File("d:/rufnummern.txt");
				FileEntity reqEntity = new FileEntity(file, "binary/octet-stream");
				httpost.setEntity(reqEntity);
				reqEntity.setContentType("binary/octet-stream");
				System.out.println("executing request " + httpost.getRequestLine());

			
			     response = httpclient.execute(httpost);			     
	     		entity = response.getEntity();
				System.out.println("Status*: " + response.getStatusLine());

...
```


ich bekomme zwar als Status 200 OK... aber der "Upload" geht viel zu schnell und die Daten kommen auch nicht an. Was mache ich falsch?


----------



## kay73 (24. Mai 2010)

FriFra hat gesagt.:


> aber der "Upload" geht viel zu schnell und die Daten kommen auch nicht an. Was mache ich falsch?


File Uploads macht man mit dem HttpClient - Multipart Post Method
API mit Code-Beispiel: HttpClient 3.1 API


----------



## FriFra (24. Mai 2010)

kay73 hat gesagt.:


> File Uploads macht man mit dem HttpClient - Multipart Post Method
> API mit Code-Beispiel: HttpClient 3.1 API



Die sind allerdings nicht in import org.apache.http. ... enthalten, sondern in org.apache.commons.httpclient. ... Ich kann irgendwie kein funktionierendes Beispiel finden... entweder muss man raten, welche imports noch fehlen, oder es funktioniert einfach nicht.
Gibt es denn kein Beispiel? Ich kann auf der unter "Code-Beispiel" genannten Seite kein Beispiel finden...


----------



## kay73 (24. Mai 2010)

FriFra hat gesagt.:


> Ich kann auf der unter "Code-Beispiel" genannten Seite kein Beispiel finden...



Sorry. Hier:
MultipartRequestEntity (HttpClient 3.1 API)

```
File f = new File("/path/fileToUpload.txt");
  PostMethod filePost = new PostMethod("http://host/some_path");
  Part[] parts = {
      new StringPart("param_name", "value"),
      new FilePart(f.getName(), f)
  };
  filePost.setRequestEntity(
      new MultipartRequestEntity(parts, filePost.getParams())
      );
  HttpClient client = new HttpClient();
  int status = client.executeMethod(filePost);
```


----------



## FriFra (24. Mai 2010)

Ich verwende aber Version 4.0.1 und da finde ich keine "PostMethod" ...


----------



## FriFra (24. Mai 2010)

Hab jetzt folgenden Code:

```
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

				HttpPost httppost = new HttpPost(sURL+"/telefonbuch_kurzwahl?im_file=kurzwahlen&actionNo=12");
				File file = new File("d:/rufnummern.txt");

				MultipartEntity mpEntity = new MultipartEntity();
				ContentBody cbFile = new FileBody(file, "text/plain");
				mpEntity.addPart("im_file", cbFile);

				httppost.setEntity(mpEntity);
				System.out.println("executing request " + httppost.getRequestLine());
				response = httpclient.execute(httppost);
				HttpEntity resEntity = response.getEntity();

				System.out.println(response.getStatusLine());
				if (resEntity != null) {
					System.out.println(EntityUtils.toString(resEntity));
				}
				if (resEntity != null) {
					resEntity.consumeContent();
				}
```

Allerdings kommt die Datei nach wie vor nicht an...


----------



## kay73 (24. Mai 2010)

Sorry, der 3er ist wohl sehr outdatet. So gehts mit 4.0.1 und Multipart (zwar schludrig aber funktioniert). 

Ich kann zu Deinem Code nicht wirklich einen Unterschried entdecken; ich tippe auf 
	
	
	
	





```
new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
```
. 

Die Datei wird auf jeden Fall mitgeschickt. Wenn es jetzt nicht klappt, liegt es an falschen POST-Daten oder am Netz.

```
package com.mycompany.app;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;

public class App {
	public static void main(String[] args) throws IOException {
		
		final HttpClient httpclient = new DefaultHttpClient();

		final HttpPost httpPost = new HttpPost("/");

		final MultipartEntity multipartEntity = new MultipartEntity(
				HttpMultipartMode.BROWSER_COMPATIBLE);

		final ContentBody contentBody = new FileBody(new File(
				"/home/kay/Dokumente/tmp/my-app/pom.xml"), "text/plain");

		multipartEntity.addPart("upload_file", contentBody);
		httpPost.setEntity(multipartEntity);

		final HttpResponse response = httpclient.execute(new HttpHost(
				"localhost"), httpPost);

		System.out.println(response.getStatusLine());

		final HttpEntity entity = response.getEntity();

		if (entity != null) {
			final BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
			System.out.println(reader.readLine());
			
			httpclient.getConnectionManager().shutdown();
		}
	}
}
```


----------



## FriFra (24. Mai 2010)

Leider klappt es nicht... Irgend etwas muss noch anders sein, als mit nem richtigen Browser. So wie es jetzt ist, meldet der Zielserver: "Fehler 12002: - falsche Boundary Key"
k.A. was mir die Meldung sagen will, fakt us nur, das passiert nicht, wenn ich manuell über den Browser uploade.


----------



## kay73 (24. Mai 2010)

Dann musst Du den Paketverkehr mitschneiden und vergleichen. Vielleicht schummelt ein JavaScript einen Parameter in das Form, um das Uploaden für Nicht-Browser zu erschweren. 

Eine "Boundary" kommt im Multipart-Standard als Trenner zwischen den Abschnitten vor; aber hieße der Client würde das Forumlar falsch formatieren. Unwahrscheinlich.


----------



## FriFra (24. Mai 2010)

Es muss doch möglich sein, den Upload eines simplen HTML-Formulars (s. erstes Post) mit diesen Komponenten zu realisieren... die URL inkl. Parameter ist korrekt und es gibt nur ein einziges Feld...



kay73 hat gesagt.:


> aber hieße der Client würde das Forumlar falsch formatieren. Unwahrscheinlich.


Einzige Möglichkeit! IE - kein Problem, FF - kein Problem, apache - klappt nicht ... alle mit der gleichen Datei.


----------



## kay73 (24. Mai 2010)

Natürlich geht das; wird nur ein Detail sein (HTTP-Version, chunked encoding erwartet, falscher Entity-Name, User-Agent faken). Schneide halt mit wireshark die beiden POSTS mit und vergleiche sie. So habe ich schon schwierigere Formularuploads erledigt.


----------



## FriFra (24. Mai 2010)

Wireshark schmiert auf meinem Testrechner permanent ab... damit komme ich nicht weiter.

Firebug zeigt allerdigs auch nur das was man auch so schon sieht... Wie das Formular versendet wird, steht doch alles schon im Form-Tag... Das einzige, was mir noch einfallen würde, wäre das encoding, da wird im Form: ISO-8859-1, vorgegeben.


----------



## FriFra (26. Mai 2010)

WireShark zeigt bei mir an der entspr. Stelle überhaup keinen Request ???:L:bahnhof:

```
httpost = new HttpPost(sURL+"/telefonbuch_kurzwahl?im_file=kurzwahlen&actionNo=12");

				FileBody bin = new FileBody(new File("d:/rufnummern.txt"),"text/plain");

				MultipartEntity mpentity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);      
				mpentity.addPart("im_file", bin);
				httpost.setEntity(mpentity);
        
				System.out.println("executing request " + httpost.getRequestLine());
				System.out.println("DoPost");
				response = httpclient.execute(httpost);
				System.out.println("Done!");
				entity = response.getEntity();
				is = entity.getContent();

				System.out.println("----------------------------------------");
				System.out.println(response.getStatusLine());
				if (entity != null) {
					System.out.println("CHK: "+convertStream2String(is));
					System.out.println("Response content length: " + entity.getContentLength());
					System.out.println("Chunked?: " + entity.isChunked());
				}
				if (entity != null) {
					entity.consumeContent();
				}
```

Ich sehe zwar an der Java-Console, dass der Post problemlos "ausgeführt" wird... aber WireShark zeigt nichts... 2 Requests vorher und einer danach sind sichtbar, nur der Post nicht.


----------



## FriFra (30. Mai 2010)

Keiner eine Idee, was man da noch machen kann?

Die commons FileUpload gibt es leider z.Zt. nur auf Basis der 3er Controls... damit wäre aber alles andere, was bereits funktioniert für die Tonne.


----------



## kay73 (31. Mai 2010)

Mal der Vollständigkeit halber: Untenstehender HTML-Code, PHP-Testseite und der Client in Java funktionieren. Siehe unten den Wireshark dump. 

Gefährlich ist aber aber das 
	
	
	
	





```
Expect: 100-Continue
```
. Z. B. lighttpd kann damit nicht umgehen. Vielleicht liegt es daran. Füge mal 
	
	
	
	





```
httpPost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
```
 in Zeile 34 ein.


HTML:

```
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
	<title>Rufnummern (Kurzwahl- und Telefonbuch)</title>
	</head>
	<body >
		<form name="import_form" method="post" action="http://localhost/test_upload.php" accept-charset="ISO-8859-1" enctype="multipart/form-data">
		<input type="file" name="im_file" size="70">
		<input type="submit">
	</form>
	</body>
</html>
```
PHP Testseite:

```
<?php

$uploaddir = '/var/www/tmp/';
$uploadfile = $uploaddir . basename($_FILES['im_file']['name']);

echo '<pre>';
if (move_uploaded_file($_FILES['im_file']['tmp_name'], $uploadfile)) {
    echo "File is valid, and was successfully uploaded.\n";
} else {
    echo "Possible file upload attack!\n";
}

echo 'Here is some more debugging info:';
print_r($_FILES);

print "</pre>";

?>
```
Wireshark dump

```
POST /test_upload.php HTTP/1.1

Content-Length: 153

Content-Type: multipart/form-data; boundary=6uDLdUrR80Phz7e4tiGaH_5cp1HXR9y

Host: localhost

Connection: Keep-Alive

User-Agent: Apache-HttpClient/4.0.1 (java 1.5)

Expect: 100-Continue



HTTP/1.1 100 Continue



--6uDLdUrR80Phz7e4tiGaH_5cp1HXR9y

Content-Disposition: form-data; name="im_file"; filename="hallo.txt"



Hallo!


--6uDLdUrR80Phz7e4tiGaH_5cp1HXR9y--

HTTP/1.1 200 OK

Date: Mon, 31 May 2010 18:11:27 GMT

Server: Apache/2.2.14 (Ubuntu)

X-Powered-By: PHP/5.3.2-1ubuntu4.2

Vary: Accept-Encoding

Content-Length: 303

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Content-Type: text/html



<pre>File is valid, and was successfully uploaded.
Here is some more debugging info:Array
(
    [im_file] => Array
        (
            [name] => hallo.txt
            [type] => 
            [tmp_name] => /var/www/uploads/phpy6TjJt
            [error] => 0
            [size] => 7
        )

)
</pre>
```


```
package com.mycompany.app;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;

public class App {
	public static void main(String[] args) throws IOException {
		
		final HttpClient httpclient = new DefaultHttpClient();

		final HttpPost httpPost = new HttpPost("/test_upload.php");

		final MultipartEntity multipartEntity = new MultipartEntity(
				HttpMultipartMode.BROWSER_COMPATIBLE);

		final ContentBody contentBody = new FileBody(new File(
				"/home/kay/Dokumente/tmp/my-app/pom.xml"), "text/plain");

		multipartEntity.addPart("im_file", contentBody);
		httpPost.setEntity(multipartEntity);

		final HttpResponse response = httpclient.execute(new HttpHost(
				"localhost"), httpPost);

		System.out.println(response.getStatusLine());

		final HttpEntity entity = response.getEntity();

		if (entity != null) {
			final BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
		    final StringBuilder b = new StringBuilder();
		    String s;
		    while((s = reader.readLine()) != null) {
		    	b.append(s+"\n");
		    }
		    
		    System.out.println(b.toString());
			
			httpclient.getConnectionManager().shutdown();
		}
	}
}
```


----------



## FriFra (1. Jun 2010)

kay73 hat gesagt.:


> Füge mal
> 
> 
> 
> ...



Leider bringt das auch keine Besserung...

Falls es hilft, ich hab mal den Servernamen der Webservers auf der Telefonanlage: "Server: GoAhead-Webs"


Wireshark zeigt mir beim "original" Request über die html-Seite für den encapsulated multipart part: "Line-based text data: text/plain" und dann kommt der Inhalt der Datei im Klartext. Über den httpclient bekomme ich nur: "Data (8750 bytes)" und einen encodeten Inhalt, also nicht die Textdatei im Klartext.
Im Header des multipart part steht bei beiden Requests:
"Content-Disposition: form-data; name="im_file"; filename="rufnummern.txt"\r\n\r\n"
in der funktionierenden Version steht noch:
"Content-Type: text/plain\r\n\r\n" ... dieses Header Feld fehlt im part beim httpclient.


----------



## FriFra (1. Jun 2010)

Es liag tatsächlich am vom Client erzeugtem Boundary... Ich habe jetzt einfach mal einen Boundary-String von einem erfolgreichen Post mit dem Browser kopiert und übergeben... jetzt klappts.

```
MultipartEntity mpentity = new MultipartEntity(null,"---------------------------126372240926463",null);
```

Jetzt hab ich nur noch ein Timeout Problem bei größeren Dateien.


----------



## bennyn (6. Aug 2011)

Bei mir hat folgender Code funktioniert, um eine Datei mit dem Apache HTTPClient zu senden:


```
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

public class App
{

  static final Logger logger = Logger.getLogger(App.class.getPackage().getName());

  public static void main(String[] args) throws Exception
  {
    HttpParams params = new BasicHttpParams();
    params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpClient client = new DefaultHttpClient(params);
    HttpPost post = new HttpPost("http://localhost:8080/");

    File file = new File("C:/Temp/upload/movie.avi");
    FileEntity reqEntity = new FileEntity(file, "binary/octet-stream");
    post.setEntity(reqEntity);
      HttpResponse response = client.execute(post);
      HttpEntity entity = response.getEntity();
      if (entity != null)
      {
        System.out.println(EntityUtils.toString(entity));
      }
}
```

Vielleicht ist die Implementierung auf der Serverseite nicht korrekt? Ich habe mir einen kleinen Fileserver mit dem JBoss Netty-Framework erstellt. Hat sehr gut funktioniert!


----------

