# Probleme mit libcurl bei CURLOPT_POSTFIELDS



## badday (11. August 2010)

Moin zusammen,

ich habe gerade ein etwas merkwürdiges Problem mit einer Anwendung, die libcurl benutzt.
Zunächst einmal grob, was ich machen möchte:
Ich habe Serverseitig einen Webservice, den ich via http erreichen kann und dem ich json-Objekte schicke. 
Momentan sieht es in etwa so aus:

```
std::wstring targetaddress, source;
//....
CURL *curl;
CURLcode res;
 
curl = curl_easy_init();
if(curl) {
	curl_easy_setopt(curl, CURLOPT_URL, targetaddress.c_str());
	curl_easy_setopt(curl, CURLOPT_PORT, 8080);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, source.c_str());
 
	/* Perform the request, res will get the return code */ 
	res = curl_easy_perform(curl);
 
	/* always cleanup */ 
	curl_easy_cleanup(curl);
}
```

Wobei targetaddress die genaue Zieladresse enthält (im Beispiel http://musteradresse.de/muster ) und source die Daten, die gesendet werden sollen (als einfache json-Objekte). Der Port ist vom WS so festgelegt.

Via Browser ist der WS z. B. so erreichbar:

```
http://musteradresse.de:8080/muster.json
```
Damit kann ich dann z. B. eine json-Datei herunterladen. Beim upload verwende ich routen, die vom Webservice festgelegt sind, z. B. versuche ich auf

```
http://musteradresse.de:8080/muster
```
etwas hochzuladen. Rufe ich diese Adresse im Browser auf, bleibt das Fenster einfach weiß, aber die Seite ist vorhanden.

Nun zum Problem:
Versuche ich das mit libcurl, so erhalte ich als res von  curl_easy_perform(curl); den Fehlercode:

```
CURLE_COULDNT_RESOLVE_HOST
```

Daher meine Frage: Warum erhalte ich diesen Fehler? Die Seite ist ja im Browser aufrufbar. 


Vielen Dank.


Gruß,

badday


----------



## deepthroat (11. August 2010)

Hi.

Welche Version von libcurl verwendest du denn?

Und ich würde keine wchar_t* an curl_easy_setopt übergeben...

Gruß


----------



## badday (11. August 2010)

Moin,

es sollte die aktuelle Version sein.

Zu wchar: Kann das ein Problem sein? Werde es gleich mal ausprobieren, melde mich dann wieder.


Gruß,

badday


----------



## badday (11. August 2010)

OK, das war tatsächlich das Problem.
Eine Frage habe ich noch:
Das Senden von wchars via POSTFIELDS ist aber kein Problem, oder?

Momentan sieht es so aus:

```
if(curl) {
			
			struct curl_slist *headers=NULL;
			headers = curl_slist_append(headers, "Content-Type: application/json; charset=utf-8");

			curl_easy_setopt(curl, CURLOPT_URL, targetaddress.c_str());
			curl_easy_setopt(curl, CURLOPT_PORT, 8080);
			
			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
			curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(wchar_t)*(source.length()+1));
			curl_easy_setopt(curl, CURLOPT_POSTFIELDS, source.c_str());
			
			/* Perform the request, res will get the return code */ 
			res = curl_easy_perform(curl);
 
			/* always cleanup */ 
			curl_easy_cleanup(curl);
			curl_slist_free_all(headers);
```
targetaddress ist nun char. Allerdings sagt der Server immer, das json-Objekt sei nicht valid, ist es aber, laut jsonlint.com. Ich vermute einfach mal, dass könnte mit der Kodierung zusammenhängen?
Wäre denn die Vorgehensweise soweit richtig mit dem content-type?
Ich habe auch ein setlocale(LC_ALL, "en_US.UTF-8"); eingefügt, nur half das nicht weiter.

Bin für jeden Tipp dankbar.



Danke und Gruß,

badday


----------



## deepthroat (11. August 2010)

badday hat gesagt.:


> OK, das war tatsächlich das Problem.
> Eine Frage habe ich noch:
> Das Senden von wchars via POSTFIELDS ist aber kein Problem, oder?


Doch, da ein wchar_t Zeichen aus mehreren Bytes besteht und üblicherweise bei Zeichen aus dem ASCII-Bereich ein Byte davon \0 ist (L'a' == \x61\x00), erkennt curl (welches intern nur mit char arbeitet) nur einen String von 1 Zeichen. (strlen(L"abcdef") == 1)

Evtl. solltest du dir das was über die Leitung geht mit Wireshark anschauen.

Und wenn du schon C++ verwendest, warum verwendest du denn keinen C++ Wrapper für libcurl, z.B. http://curlpp.org/ ?

Gruß


----------



## badday (11. August 2010)

Ich schaue schon mit Wireshark, demnach wird das eigentlich schön gesendet.

Gruß,

badday


----------



## deepthroat (11. August 2010)

badday hat gesagt.:


> Ich schaue schon mit Wireshark, demnach wird das eigentlich schön gesendet.


Wenn du keine CURLOPT_POSTFIELDSIZE angibst, ermittelt curl die Länge der Post-Daten mit strlen, was für wchar_t* in der Regel kein korrektes Ergebnis liefert.

Ich weiß ja nicht wie du die Daten in den wstring bekommen hast; evtl. hast du da getrickst?

Gruß


----------



## badday (11. August 2010)

Du hast recht, ohne geht es nicht, aber wie oben geschrieben mache ich das mit CURLOPT_POSTFIELDSIZE:
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(wchar_t)*(source.length()+1));


Gruß,

badday


----------



## deepthroat (11. August 2010)

badday hat gesagt.:


> Du hast recht, ohne geht es nicht, aber wie oben geschrieben mache ich das mit CURLOPT_POSTFIELDSIZE:
> curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(wchar_t)*(source.length()+1));


Ach so, den Code hatte ich gar nicht gesehen.

Aber warum nimmst du nicht einfach die wstring::data() Methode, da muss nicht extra ein \0 angehängt werden, dann kannst du die +1 weglassen.

Gruß


----------



## badday (22. August 2010)

Hey,

ich melde mich nochmal, weil es zwar insofern nun geht, ich aber ein weiteres Problem habe:
Es wird nach jedem Zeichen ein Leerzeichen gesendet, also statt Hund H u n d, aber auch bei Nummer, also statt 900 9 0 0. Damit ist das ganze natürlich kein valides json-Objekt mehr.
Ich sende aktuell die Enkodierung mit via


```
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: application/json; charset=utf-8");
//...
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
```

und setzt im Programm am Anfang

```
setlocale(LC_ALL, "en_US.UTF-8");
```

Wo kann das Problem liegen?


Gruß,

badday


----------



## deepthroat (23. August 2010)

Hi.





badday hat gesagt.:


> Wo kann das Problem liegen?


Du sendest kein UTF-8.

Du sendest die Daten vermutlich in UTF-32 oder UTF-16 (welches OS?).

UTF-8 Strings kannst du ganz normal mit std::string verarbeiten. (nur die Länge des Strings stimmt nicht unbedingt mit der Anzahl der Zeichen überein)

Gruß


----------



## badday (23. August 2010)

Hey,



> Du sendest die Daten vermutlich in UTF-32 oder UTF-16 (welches OS?).


OS ist Windows Server 2008 R2 (64-bit).

Ich sende also keinen UTF-8 string? Liegt der string also gar nicht als UTF-8 vor? 
Wie kann ich das ändern?



> UTF-8 Strings kannst du ganz normal mit std::string verarbeiten. (nur die Länge des Strings stimmt nicht unbedingt mit der Anzahl der Zeichen überein)


D. h., dass auch Umlaute etc. dort problemlos möglich sind?


Gruß


----------



## deepthroat (23. August 2010)

badday hat gesagt.:


> OS ist Windows Server 2008 R2 (64-bit).


Windows verwendet (intern) UTF-16.


badday hat gesagt.:


> Ich sende also keinen UTF-8 string? Liegt der string also gar nicht als UTF-8 vor?
> Wie kann ich das ändern?


Du mußt umkodieren. Siehe http://msdn.microsoft.com/en-us/library/dd374130(VS.85).aspx


badday hat gesagt.:


> D. h., dass auch Umlaute etc. dort problemlos möglich sind?


Ja, UTF-8 ist eine Unicode Kodierung.

Gruß


----------



## badday (23. August 2010)

Das Programm muss sowohl auf Windows als auch Linux laufen, daher bräuchte ich eine plattformübergreifende Möglichkeit.
Gibt es sowas?

Bedeutet das weiterhin, dass ich gar keine wstrings verwenden muss, sondern nur std::strings?


Gruß,

badday


----------



## deepthroat (23. August 2010)

badday hat gesagt.:


> Das Programm muss sowohl auf Windows als auch Linux laufen, daher bräuchte ich eine plattformübergreifende Möglichkeit.
> Gibt es sowas?


Es gibt z.B. die UCU Bibliothek von IBM. Ansonsten, schau mal hier: http://stackoverflow.com/questions/148403/utf8-to-from-wide-char-conversion-in-stl

Mußt du denn die Daten unbedingt in UTF-8 senden? Du könntest ja evtl. einfach die richtige Kodierung angeben...


badday hat gesagt.:


> Bedeutet das weiterhin, dass ich gar keine wstrings verwenden muss, sondern nur std::strings?


Ja, der Vorteil von UTF-8 ist, dass es ASCII kompatibel ist (und diese Zeichen auch weiterhin nur 1 Byte verwenden).

Gruß


----------



## badday (23. August 2010)

Was wäre ich ohne deine Hilfe?
Der Link war (mal wieder) goldrichtig, nun funktioniert es.

Vielen Dank!

Gruß,

badday


----------

