I get this error when I try to read a XML from a URL:
java.net.ProtocolException: Server redirected too many times (20).
I found a solution, setting the cookies with the following line:
CookieHandler.setDefault(new ListCookieHandler());
Where the "ListCookieHandler" is a class that I define with configurations from my request.
But this doesn't work. In the javadoc from the method "CookieHandler.setDefault" I found:
"Note: non-standard http protocol handlers may ignore this setting".
I think this could be the problem. There another solution for me?
My code is:
int timeout = 120000;
CookieHandler.setDefault(new ListCookieHandler());
HttpURLConnection conn = (HttpURLConnection) new URL("http://...").openConnection();
conn.setReadTimeout(timeout);
conn.setConnectTimeout(timeout);
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append(System.getProperty("line.separator"));
}
System.out.println(StringEscapeUtils.unescapeHtml(builder.toString()));
The complete solution for the ListCookieHandler is in the link: http://www.java2s.com/Code/Java/JDK-6/UsingCookieHandlerinJava5.htm
When I was facing the same error I used:
import java.net.CookieHandler;
import java.net.CookieManager;
CookieHandler.setDefault(new CookieManager());
Use this property before calling the openConnection();
HttpURLConnection.setFollowRedirects(false);
Related
I am developing a REST client using JBOSS app server and RESTEasy 2.3.6. I've included the following line at the beginning of my code:
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
Here's the rest of the snippet:
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(host, port, AuthScope.ANY_REALM), new UsernamePasswordCredentials(userid,password));
ClientExecutor executor = createAuthenticatingExecutor(httpclient, host, port);
String uriTemplate = "http://myhost:8080/webapp/rest/MySearch";
ClientRequest request = new ClientRequest(uriTemplate, executor);
request.accept("application/json").queryParameter("query", searchArg);
ClientResponse<SearchResponse> response = null;
List<MyClass> values = null;
try
{
response = request.get(SearchResponse.class);
if (response.getResponseStatus().getStatusCode() != 200)
{
throw new Exception("REST GET failed");
}
SearchResponse searchResp = response.getEntity();
values = searchResp.getValue();
}
catch (ClientResponseFailure e)
{
log.error("REST call failed", e);
}
finally
{
response.releaseConnection();
}
private ClientExecutor createAuthenticatingExecutor(DefaultHttpClient client, String server, int port)
{
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
HttpHost targetHost = new HttpHost(server, port);
authCache.put(targetHost, basicAuth);
// Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
// Create ClientExecutor.
ApacheHttpClient4Executor executor = new ApacheHttpClient4Executor(client, localContext);
return executor;
}
The above is a fairly simple client that employs the ClientRequest/ClientResponse<T> technique. This is documented here. The above code does work (only left out some trivial variable declarations like host and port). It is unclear to me from the JBOSS documentation as to whether I need to run RegisterBuiltin.register first. If I remove the line completely - my code still functions. Do I really need to include the register method call given the approach I have taken? The Docs say I need to run this once per VM. Secondly, if I am required to call it, is it safe to call more than one time in the same VM?
NOTE: I do understand there are newer versions of RESTEasy for JBOSS, we are not there yet.
Currently I am using Apache http components client V4.3.5. In my case, I can upload small file(1kb), but it is not working on large file(100kb) when I run the code and get the exception "org.apache.http.NoHttpResponseException: 192.168.128.109:443 failed to respond". Can anyone take a look at my code and let me know what causes my issue?
Here is my code:
public static void main(String[] args) throws IOException,
KeyStoreException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(
null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.disableContentCompression();
builder.setSSLSocketFactory(sslsf);
SocketConfig config = SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(300000).build();
builder.setDefaultSocketConfig(config);
CloseableHttpClient httpclient = builder.build();
HttpPost httppost = new HttpPost("https://192.168.128.109/upload");
String encodedAuthorization = DatatypeConverter
.printBase64Binary("admin:itronitr".getBytes());
httppost.setHeader("Authorization", "Basic " + encodedAuthorization);
FileBody bin = new FileBody(new File("c:\\test.txt"));
String boundary = "hK1oPL5_XSfbm6lkCNlKI63rltrew5Bqik0ul";
HttpEntity reqEntity = MultipartEntityBuilder.create()
.setBoundary(boundary).addPart("upfile", bin).build();
httppost.setEntity(reqEntity);
System.out.println(httppost.getEntity().getContentLength());
System.out
.println(httppost.getEntity().getContentType().toString());
CloseableHttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
String content = EntityUtils.toString(resEntity);
System.out.println(content);
} catch (Exception exc) {
exc.printStackTrace();
}
}
Thanks,
Bill
Finally I fix the issue and it is caused by buffer size. By default, buffer size of httpclient is 8k. So I change it to 4k and my code works well.
Here is the code that changes buffer size:
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setBufferSize(4128)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultConnectionConfig(connectionConfig)
.build();
This is what worked for me; may or may not work for you!!
I recently encountered the same issue and tried all the suggestions whatever I was able to find on internet i.e upgrading httpClient to latest version and adding a re-try handler ; but none fixed it for me.
I already had a re-try handler built in my code and was running on the latest Apache client, but it was still failing with the exception Caused by: org.apache.http.NoHttpResponseException: xxxxx:443 failed to respond
So, took me almost 2 days to debug this issue and find the root cause (at-least in my case)
There seems to be a bug in older Java versions up to Java 11.0.3 included that prevents Apache HTTP Client from sending payloads bigger than 16368 bytes caused by https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8214339.
I was running on java 11.0.2 and when I upgraded to 11.0.10, it worked for me and I was able to send the bigger payload without any code changes
I also faced the similar problem. I went through many blogs and forums and tried various things but none worked for me. So, I tried a workaround. I added retry handler as below. And it worked for me:
HttpClientBuilder.create()
.setDefaultCredentialsProvider(provider)
.setRetryHandler(new DefaultHttpRequestRetryHandler() {
#Override
public boolean retryRequest(final IOException exception, final int executionCount, final HttpContext context) {
if (exception instanceof NoHttpResponseException) {
return true;
}
return super.retryRequest(exception, executionCount, context);
}
})
.build();
Although it is not a correct fix and just a workaround but it is working for me for now. I'll stick to this solution till I won't get any permanent solution. Sharing it here in case someone might get benefit from it.
Could someone explain why this httpunit test case keeps failing in wc.getResponse with "bad file descriptor". I added the is.close() as a guess and moved it before and after the failure but that had no effect. This tests put requests to a Dropwizard app.
public class TestCircuitRequests
{
static WebConversation wc = new WebConversation();
static String url = "http://localhost:8888/funl/circuit/test.circuit1";
#Test
public void testPut() throws Exception
{
InputStream is = new FileInputStream("src/test/resources/TestCircuit.json");
WebRequest rq = new PutMethodWebRequest(url, is, "application/json");
wc.setAuthentication("FUNL", "foo", "bar");
WebResponse response = wc.getResponse(rq);
is.close();
}
No responses? So I'll try myself based on what I learned fighting this.
Httpunit is an old familiar tool that I'd use if I could. But it hasn't been updated in more than two years, so I gather its support for #PUT requests isn't right.
So I converted to Jersey-client instead. After a bunch of struggling I wound up with this code which does seem to work:
#Test
public void testPut() throws Exception
{
InputStream is = new FileInputStream("src/test/resources/TestCircuit.json");
String circuit = StreamUtil.readFully(is);
is.close();
Authenticator.setDefault(new MyAuthenticator());
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
com.sun.jersey.api.client.WebResource service = client.resource(url);
Builder builder = service.accept(MediaType.APPLICATION_JSON);
builder.entity(circuit, MediaType.APPLICATION_JSON);
builder.put(String.class, circuit);
return;
}
This intentionally avoids JAX-RS automatic construction of beans from JSON strings.
I would like to use SVNDiffClient to get wc local changes,
equivalent of 'svn diff -rBASE', which is exactly what this example is suposed to do.
However, running the code from example throws 'org.tmatesoft.svn.core.SVNException: svn: At least one revision must be non-local for a pegged diff', which is exactly what documentation says it would.
I would like to be able to compare WORKING to BASE without hitting the server, to see if there were any changes.
Can this be accomplished using SVNKit?
You may also use old API:
final SVNClientManager clientManager = SVNClientManager.newInstance();
try {
final SVNDiffClient diffClient = clientManager.getDiffClient();
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
diffClient.doDiff(workingCopyDirectory, SVNRevision.BASE, workingCopyDirectory, SVNRevision.WORKING, SVNDepth.INFINITY, false, outputStream, null);
System.out.println(outputStream);
} finally {
clientManager.dispose();
}
You may use new API:
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final SvnDiff diff = svnOperationFactory.createDiff();
diff.setSources(SvnTarget.fromFile(workingCopyDirectory, SVNRevision.BASE), SvnTarget.fromFile(workingCopyDirectory, SVNRevision.WORKING));
diff.setOutput(byteArrayOutputStream);
diff.run();
I want to do a POST request to an HTTP Servlet I wrote myself. Good case (HTTP response Code 200) always works fine by using URL.openConnection() method. But when I receive a desired error response code (e.g. 400) then I thought I have to use HttpUrlConnection.getErrorStream(). But the ErrorStream object is null though I am sending data back from the servlet in error case (I want to evaluate this data to generate error messages).
This is what my code looks like:
HttpURLConnection con = null;
try {
//Generating request String
String request = "request="+URLEncoder.encode(xmlGenerator.getStringFromDocument(xmlGenerator.generateConnectRequest(1234)),"UTF-8");
//Receiving HttpUrlConnection (DoOutput = true; RequestMethod is set to "POST")
con = openConnection();
if (con != null){
PrintWriter pw = new PrintWriter(con.getOutputStream());
pw.println(request);
pw.flush();
pw.close();
InputStream errorstream = con.getErrorStream();
BufferedReader br = null;
if (errorstream == null){
InputStream inputstream = con.getInputStream();
br = new BufferedReader(new InputStreamReader(inputstream));
}else{
br = new BufferedReader(new InputStreamReader(errorstream));
}
String response = "";
String nachricht;
while ((nachricht = br.readLine()) != null){
response += nachricht;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
So my question is, why returns getErrorStream() null though status code is 400 (I can see it in the IOException that is thrown when it calls con.getInputStream())
Thanks
From the java documentation on getErrorStream():
Returns the error stream if the connection failed but the server sent useful data nonetheless. The typical example is when an HTTP server responds with a 404, which will cause a FileNotFoundException to be thrown in connect, but the server sent an HTML help page with suggestions as to what to do.
This method will not cause a connection to be initiated. If the connection was not connected, or if the server did not have an error while connecting or if the server had an error but no error data was sent, this method will return null. This is the default.
So if you didn't get to the server (bad url for example) or the server didn't send anything in the response, getErrorStream() will return null.
InputStream inputStream = null;
try {
inputStream = connection.getInputStream();
} catch(IOException exception) {
inputStream = connection.getErrorStream();
}
It is like when you set response header status code as anything beyond 200, the connection object is reset. it will generate SocketTimeoutException while getting the inputstream but when it comes in the catch it gives you the inputstream anyway, what you are expecting.
Digging a little bit into JDK code, I finally find the reason. HttpURLConnection#getErrorStream() returns null when receiving a 401 or 407, not because the noop implementation in the abstract class, but because HttpURLConnection closes/clears the connection immediately if it sees a 401/407 when in streaming mode(i.e., POST). See the source of the concrete implementation of HttpURLConnection: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/net/www/protocol/http/HttpURLConnection.java#1079
That said, when you catch an IOException when calling getInputStream(), the connection to server is already closed and the underlining socket is cleared, so you would always get null when calling getErrorStream().
The other options many have suggested is to check the status code before calling getInputStream or getErrorStream. This won't for 401 and 407 either because the internal errorStream is only set when you call getInputStream, i.e., it's a basically a copy of the inputStream when status code != 200. But again when you call getInputStream, the connection will be closed.
Put the statement conn.setAllowUserInteraction(true); before execute the request and the connection will not be closed, even receiving 401 status.
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setAllowUserInteraction(true); // <<<--- ### HERE
//do something
conn.connect();
boolean isError = (conn.getResponseCode() >= 400);
InputSteam is = isError ? con.getErrorStream() : con.getInputStream();
As suggested in the Android documentation:
String responseString;
try {
responseString = readInputStream(con.getInputStream());
} catch (final IOException e) {
// This means that an error occurred, read the error from the ErrorStream
try {
responseString = readInputStream(con.getErrorStream());
} catch (IOException e1) {
throw new IllegalStateException("Unable to read error body.", e);
}
}
private String readInputStream(final InputStream inputStream) throws IOException {
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuilder responseString = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
responseString.append(line);
}
bufferedReader.close();
return responseString.toString();
}