Http connection using apache.DefaultHttpClient goes into TIME_WAIT not getting reused - connection-pooling

We have a pool(GenericObjectPool) of HttpClient(apache.DefaultHttpClient) objects. HttpPost objects are put into for execution through these clients may Post request are sent simultaneously. The protocol used is: HTTP/1.1 with keepalive.
Observed during load testing through netstat that new socket connections are indiscriminately created and old connections goes to TIME_WAIT.
Log Excerpts:-
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "POST /INBOX/4504a09e-13c0-3853-a285-9e2b9a22f65e/1e1e5a20-a8c1-11e2-99b8-7c19e9129271 HTTP/1.1[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "Content-Type: application/json; charset=UTF-8[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "Content-Length: 117[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "Host: rwcdtgxb0402:15010[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "Connection: Keep-Alive[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "User-Agent: Apache-HttpClient/4.2.1 (java 1.5)[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - >> "[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - << "HTTP/1.1 200 OK[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - << "Content-Length: 0[\r][\n]"
[Worker-2] org.apache.http.impl.conn.Wire 63 - << "[\r][\n]"
[Worker-2] org.apache.http.impl.conn.DefaultClientConnection 254 - Receiving response: HTTP/1.1 200 OK
[Worker-2] org.apache.http.impl.conn.DefaultClientConnection 257 - << HTTP/1.1 200 OK
[Worker-2] org.apache.http.impl.conn.DefaultClientConnection 260 - << Content-Length: 0
[Worker-2] org.apache.http.impl.client.DefaultRequestDirector 540 - Connection can be kept alive indefinitely
**[Worker-2] org.apache.http.impl.conn.DefaultClientConnection 154 - Connection 0.0.0.0:51211<->192.168.88.172:15010 shut down**
[Worker-2] org.apache.http.impl.conn.BasicClientConnectionManager 189 - Releasing connection org.apache.http.impl.conn.ManagedClientConnectionImpl#12f65ce5
Is DefaultClientConnection.shutdown (Connection 0.0.0.0:51210<->192.168.88.172:15010 shut down) closing the connection from Client end? How is it getting invoked?
In code after receiving the response (200OK) from server httpPost.releaseConnection() is only executed in client side code.
What should I do to keep the connections in ESTABLISHED state and reuse them instead of creating the connection for every request and they going into TIME_WAIT.
Any help will be highly appreciated. Thank you.

Note calling EntityUtils.consume(entity) does a bit more and should be used:
/**
* Ensures that the entity content is fully consumed and
* the content stream, if exists, is closed.
*
* #param entity the entity to consume.
* #throws IOException if an error occurs reading the input stream
*
* #since 4.1
*/
public static void consume(final HttpEntity entity) throws IOException {
if (entity == null) {
return;
}
if (entity.isStreaming()) {
final InputStream inStream = entity.getContent();
if (inStream != null) {
inStream.close();
}
}
}

Got the problem resolved few days back.
Mistake: calling releaseConnection() on the HttpClient object. BUT, avoiding it did not solve the problem either.
Correction:
The action to be taken for keeping the connections alive (in state ESTABLISHED) was through following sample code:
HttpClient client = new org.apache.http.impl.client.DefaultHttpClient();
...
org.apache.http.HttpResponse response = client.executed(HttpPost) ;
org.apache.http.HttpEntity en = response.getEntity();
if (en != null) {
en.getContent().close();
}
Once the HttpResponse is received, in order to reuse and maintain the created connection it is necessary to close only the InputStream (en.getContent()) on the http-response. Do not call any other release method on HttpPost or Client objects.
Tested this handling with JMeter load and found it working. Haven't observed any side effects yet!

Related

HTTPS Post Request with ESP8266

I'm trying to send an HTTPS POST request with a ESP8266. I can make the request just fine with python and cURL just when I try it with the ESP it doesn't work. A segment of my code is below
const char *host = "api.pushbullet.com";
const int httpsPort = 443;
const char fingerprint[] PROGMEM = "4C 70 C5 AE F3 30 E8 29 D1 9C 18 C6 2F 08 D0 6A A9 AA 19 0F";
Link = "/post";
httpsClient.print(String("POST ") + Link + " HTTP/1.1\r\n" +
"Host: " + host + "/v2/pushes" + "\r\n" +
"Access-Token: *************"+ "\r\n" +
"Content-Type: application/json"+ "\r\n" +
"Content-Length: 20"+ "\r\n" +
"body: Hello World" + "\r\n\r\n");
Serial.println("request sent");
The request I'm trying to make is below. This works just fine in python
import requests
headers = {
'Access-Token': '***********',
'Content-Type': 'application/json',
}
data = '{"body":"Hello World","title":"Hi","type":"note"}'
response = requests.post('https://api.pushbullet.com/v2/pushes', headers=headers, data=data)
And in cURL:
curl --header 'Access-Token: **********' --header 'Content-Type: application/json' --data-binary '{"body":"Hello World","title":"Hi","type":"note"}' --request POST https://api.pushbullet.com/v2/pushes
When I make the request with the Arduino code it returns "Error 411 (Length Required)!!".
This is probably due to some stupid mistake I've made but if anyone could help me fix my Arduino code I'd be very grateful. Thanks
There are a few mistakes in your code.
your http POST format are incorrect in a)host name, b)uri, and c)header/body separation;
your http body is not a valid json object.
Here is an example on sending the http (without using String):
const char *host = "api.pushbullet.com";
const char *uri = "/post/v2/pushes/";
const char *body ="{\"body\": \"Hello World\"}"; // a valid jsonObject
char postStr[40];
sprintf(postStr, "POST %s HTTP/1.1", uri); // put together the string for HTTP POST
httpsClient.println(postStr);
httpsClient.print("Host: "); httpsClient.println(host);
httpsClient.println("Access-Token: *************");
httpsClient.println("Content-Type: application/json");
httpsClient.print("Content-Length: "); httpsClient.println(strlen(body));
httpsClient.println(); // extra `\r\n` to separate the http header and http body
httpsClient.println(body);
General advice: when you use cURL always use --verbose to see the full HTTP exchange.
In your case it should be
httpsClient.print(String("POST ") + "/v2/pushes" + Link + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Access-Token: *************"+ "\r\n" +
"Content-Type: application/json"+ "\r\n" +
"Content-Length: 20"+ "\r\n" +
"body: Hello World" + "\r\n\r\n");
Note how
the path is "/v2/pushes/" plus identifier ("Link" in your case?)
Host is just "api.pushbullet.com"
Side notes:
make sure you send correct values for Content-Length
consider using HTTPClient if you are not confident with low-level HTTP programming

Trying to connect to host

I'm trying to connect to Google Firebase Firestore using an esp8266 device. I want to do a post request but can't get a connection to the host:
const char *host = "firestore.googleapis.com";
int r=0; //retry counter
while((!httpsClient.connect(host, httpsPort)) && (r < 30)){
delay(50);
Serial.print(".");
r++;
}
httpsClient.print(String("POST ") + "/v1beta1/projects/myproject/databases/(default)/documents/loggings" + " HTTP/1.1\r\n" +
"Host: " + "firestore.googleapis.com" + "\r\n" +
"Content-Type: application/json"+ "\r\n" +
"Content-Length: 240" + "\r\n\r\n" +
postData+ "\r\n" +
"Connection: close\r\n\r\n");
The connect() function doesn't work because the host can't be found (404). How do I need to use the connect function to get a proper connection to the firestore host?
Call httpsClient.setInsecure() before connect(). Key validation is then skipped. It's not secure but maybe that's ok for your use case. httpsPort should be 443. For me connecting to fcm.googleapis.com works if done like this:
WiFiClientSecure client;
client.setInsecure(); // INSECURE!
client.connect("fcm.googleapis.com", 443);

HTTP Error 415 Unsupported media type

I am still on the same problem as:
Upload binary data with HTTP PUT with jersey jaxrs-ri-2.01
But I am one step further. Now I am testing my data upload with this tool:
I'm Only Resting
The problem, and I don't know if it's a client or a server problem is that when I'm testing, I get HTTP 415 - Unsupported Media Type
In the client:
I have checked the PUT method
In the body I have put one blank line (return) and in the second line i wrote test
In the server, It was working until I added this parameter
#FormDataParam("file") InputStream pBodyDataStream
and this code:
try {
OutputStream lOutputStream = new FileOutputStream(new File("F:/test.bin"));
int read = 0;
byte[] bytes = new byte[fragmentSize];
while ((read = pBodyDataStream.read(bytes)) != -1) {
lOutputStream.write(bytes, 0, read);
}
lOutputStream.close();
pBodyDataStream.close();
} catch (IOException e) {
// fragment reception error
// HTTP 500 error
lOutput = xmlError("Upload error while transferring fragment");
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(lOutput).build();
}
Here is a screenshot of the test tool with the parameters:
Here is the cURL investigation:
The command line:
curl -v -H "application/octet-stream" -K params_curl.txt
The cURL parameters file:
url = "localhost:8080/ServeurWS/softplus/biens/arts/2345412/images?user=wow&pass=wow&taille=100&numfrag=1&taillefrag=10&md5=d6aa97d33d459ea3670056e737c99a3d&md6=5da8aa7126701c9840f99f8e9fa54976"
request="PUT"
upload-file="f:/vcredist.bmp"
output = "output.html"
user-agent = "superagent/1.0"
The headers I see, thanks to the -v option:
C:\Users\Dev\Desktop>curl -v -I -H "application/octet-stream" -K params_curl.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> PUT /ServeurWS/softplus/biens/arts/2345412/images?user=wow&pass=wow&taille=100&numfrag=1&taillefrag=10&md5=d6aa97d33d459ea3670056e737c99a3d&md6=5da8aa7126701
c9840f99f8e9fa54976 HTTP/1.1
> Host: localhost:8080
> User-Agent: superagent/1.0
> Accept: */*
> Content-Length: 5686
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
} [5686 bytes data]
* We are completely uploaded and fine
< HTTP/1.1 415 Type de Support Non Supporté
< Server: Apache-Coyote/1.1
< Content-Type: text/html;charset=utf-8
< Content-Length: 1108
< Date: Wed, 02 Dec 2015 13:56:07 GMT
<
{ [1108 bytes data]
100 6794 100 1108 100 5686 11080 56860 --:--:-- --:--:-- --:--:-- 63177
* Connection #0 to host localhost left intact
The output.html file:
HTTP/1.1 100 Continue
HTTP/1.1 415 Type de Support Non Supporté
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1108
Date: Wed, 02 Dec 2015 13:56:07 GMT
<html><head><title>Apache Tomcat/6.0.44 - Rapport d'erreur</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>Etat HTTP 415 - Unsupported Media Type</h1><HR size="1" noshade="noshade"><p><b>type</b> Rapport d'état</p><p><b>message</b> <u>Unsupported Media Type</u></p><p><b>description</b> <u>Le serveur a refusé cette requête car l'entité de requête est dans un format non supporté par la ressource demandée avec la méthode spécifiée.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/6.0.44</h3></body></html>
And there is no error in the Eclipse console...

HTTP 302 - Not found parameter GSessionID - Google Calendar

I need help .
I want to create events on google calendar with a desktop application , when the parameters sent
url = 'https://www.google.com/calendar/feeds/emaill%40gmail.com/private/full';
and then add xml where this event to create
createXML := '<?xml version=''1.0'' encoding=''UTF-8''?>'#13#10 +
'<entry xmlns=''http://www.w3.org/2005/Atom'''#13#10 +
'xmlns:gd=''http://schemas.google.com/g/2005''>'#13#10 +
'<category scheme=''http://schemas.google.com/g/2005#kind'''#13#10 +
'term=''http://schemas.google.com/g/2005#event''></category>'#13#10 +
'<title type=''text''>' + title + '</title>'#13#10 +
'<content type=''text''>' + content + '</content>'#13#10 +
'<gd:transparency'#13#10 +
'value=''http://schemas.google.com/g/2005#event.opaque''>'#13#10 +
'</gd:transparency>'#13#10 +
'<gd:eventStatus'#13#10 +
'value=''http://schemas.google.com/g/2005#event.confirmed''>'#13#10 +
'</gd:eventStatus>'#13#10 +
'<gd:where valueString=''' + location + '''></gd:where>'#13#10 +
'<gd:when startTime=''' + EventStartTime + ''''#13#10 +
'endTime=''' + EventEndTime + '''></gd:when>'#13#10 +
'</entry>';
When I do the POST process the next header appears
HTTP/1.0 302 Moved Temporarily
Expires: Wed, 30 April 2014 17:37:17 GMT
Date: Wed, 30 April 2014 17:37:17 GMT
Set- Cookie: T=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
Expires = Tue, 13 -May- 2014 10:32:28 GMT;
SecureLocation : https://www.google.com:443/calendar/feeds/default/private/full?t=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content- Type: text / html ; charset = UTF -8
Cache- Control: private , max -age = 0
X -Content -Type -Options : nosniff
X -Frame -Options : SAMEORIGIN
X -XSS -Protection : 1; mode = block
Server : GSE
Alternate -Protocol : 443: quic
In the manual, Google listed me I need a variable called " GSessionID " but does not appear to me,
I would please help me with this problem .
I have two projects with authentication: ClientLogin and OAuth 2.0
as I get to get this parameter?
Thanks a lot.
Us Google Translator
It has to work to retrieve the newly loaded gsessionID condition Realize post procedure twice, the second in the exception
try
idHTTP2.Post(URL,XML);
except on E: EIdHTTPProtocolException do
idHTTP2.Post(URL,XML);
end;
Thanks for your time.

why when exiting a Dart async Future is the following error not being caught (correctly)?

I have a problem using Dart postgresql database driver (xxgreg on Github) insofar as when the postgresql server is not running and it needs to be, I am unable to correctly handle the error. I’ve attempted to solve this for a while now, so any help would be appreciated. I can easily work around it by handling it silently and simply testing if the database connection object is null, however I think it should be possible to handle the raising of an error. It should be noted that when the Postgresql server is running, there is no problem.
The error that I am getting is as follows :
“Uncaught Error: Exception: fConnectToDb: Database is not connected
Stack Trace: ………….”
The problem area relates to these lines of code : (Line 663 is called from line 169 below)
663 async.Future<bool> fConnectToDb(String sUri) {
664 async.Completer<bool> oCompleter = new async.Completer<bool>();
665
666 pg.connect(sUri)
667 .catchError((oError) {
668 String sErrorMsg = (oError is SocketException) ?
669 "Database is not connected"
670 : "Fatal error encountered ${oError}";
671 throw("fConnectToDb: ${sErrorMsg}");
//(expanded below)
I have previously encountered problems in this area where at line 671, instead of throwing an exception, I called an internal method which displayed an error, and terminated the program. I found however what appeared to be a problem doing that, and I found in that situation, throwing an error enabled the program to exit the Future method, and not doing that appeared to be the problem. The problem may relate to the Future not being completed, but I don’t know how to do that and also throw an exception.
The overall code in-question is as follows. I put a try at line 167… 406, however that doesn’t catch the error either.
164 /*
165 * Connect to database
166 */
167 try {
168 sCheckpoint = "Connect to Database";
169 fConnectToDb(sUri)
170 .catchError((oError) =>
171 fFatal(sCheckpoint, "Error = \n${oError}"))
172 .then((_) {
173 if (ogDb == null) // ogDb is global object for db connection
174 fFatal(sCheckpoint, "Database did not connect");
175
176 /*
177 * Perform an SQL Select to test connection
178 */
179 ogPrintLine.fPrintForce("Testing Db connection .....");
180 sCheckpoint = "test connection";
181 return fProcessSqlSelect ("SELECT count(*) FROM ${S_TABLE_NAME}",
182 false);
183 }).then((llResult) {
184
…………
…………
// (catch related to line 167)
406 } catch(oError) {fFatal("Program Main()",
407 "Checkpoint ${sCheckpoint}, Error = \n${oError}");}
408 }
………..
………..
660 /*
661 * Connect To Database
662 */
663 async.Future<bool> fConnectToDb(String sUri) {
664 async.Completer<bool> oCompleter = new async.Completer<bool>();
665
666 pg.connect(sUri)
667 .catchError((oError) {
668 String sErrorMsg = (oError is SocketException) ?
669 "Database is not connected"
670 : "Fatal error encountered ${oError}";
671 throw("fConnectToDb: ${sErrorMsg}");
672
673 }).then((pg.Connection oDb) {
674 ogDb = oDb;
675 oCompleter.complete(true);
676 return;
677
678 });
679
680 return oCompleter.future;
681 }
As far as I can determine, it appears to me that it's Ok to throw an error in a Future providing it's followed by a catchError() that doesn't throw an error.
The following code appears to solve the problem that I was having :
/*
* Connect To Database
*/
async.Future<bool> fConnectToDb(String sUri) {
async.Completer<bool> oCompleter = new async.Completer<bool>();
pg.connect(sUri).then((pg.Connection oDb) {
ogDb = oDb; // assign to global database object
oCompleter.complete(true);
return;
}).catchError((oError) =>
fFatal("fConnectToDb", "Error=\n${oError}"));
return oCompleter.future;
}

Resources