beginning to work with Jackrabbit 2.6.3 and commons httpclient 3.
I've written a simple webDav client to upload a file to a server and want to test it against jackrabbit's standalone server's default repository. Simply I just want to put a file in the default repository.
my httpclient connects and the method begins buffering my file. Trouble is, I can't seem to work what URL I should point my http method at to correctly put it in the repository. The standalone server is running on:
http://localhost:8080.
I seem to either get a 405 PUT not supported or 404 or 403 or the even more curious "repository '/' does not begin with '/default' for all the urls I've tried. I can see the default repository content if I point my browser at:
http://localhost:8080/repository/default/
Simply, my question is, what is the url to do this with a PutMethod? As rudimentary as that sounds.
I've included some truncated code for the class I've written, specifically the method I'm working with at the moment, I think it should be enough to show my approach is correct.
public void insertFile(byte[] content, String id) throws Exception {
PutMethod httpMethod = new PutMethod("http://localhost:8080/repository/default/");
InputStream is = new ByteArrayInputStream(content);
FileMetaData meta = new FileMetaData();
meta.address = destUri;
meta.id = id;
meta.mimeType = Files.probeContentType(Paths.get(meta.address));
RequestEntity requestEntity = new InputStreamRequestEntity(is, meta.mimeType);
httpMethod.setRequestEntity(requestEntity);
try {
int statusCode = client.executeMethod(httpMethod);
if (statusCode != HttpStatus.SC_OK) System.err.println("Method failed: " + httpMethod.getStatusLine());
byte[] responseBody = httpMethod.getResponseBody();
System.out.println(new String(responseBody));
} catch (HttpException e) {
System.err.println("Fatal protocol violation: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("Fatal transport error: " + e.getMessage());
e.printStackTrace();
} finally {
httpMethod.releaseConnection();
}
}
I'm sure it's a simple answer, but trawling the docs don't seem to show up any resources or tutorials relating to this. Any help appreciated.
Really silly, totally thought that the requestEntity would send some data on file and use that as a file name, instead I have to specify that myself. PROTIP: Step away from the computer for 5 - 10 minutes. For anyone else with my issue it should be '"yourUrl/repository/default" + fileName'. Easy.
Related
How to implement reverse http as described in link using OkHttp
Currently my implementation is something like
Issue is I have to parse http responses which I don't feel safe, its just a coarse implementation, if someone can provide a better alternative
String request = "POST /reverse HTTP/1.1\r\n" +
"Upgrade: PTTH/1.0\r\n" +
"Connection: Upgrade\r\n" +
"\r\n";
Socket socket = null;
try {
socket = client.socketFactory().createSocket(ip, port);
final PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// send the reverse http request
out.write(request);
out.flush();
// read the reverse http response
String reverseResponse = readResponse(in);
if (!reverseResponse.trim().startsWith("HTTP/1.1 101 Switching Protocols")) {
throw new IOException("can't setup reverse connection");
}
while (!stopped) {
String eventData = readResponse(in);
out.write("HTTP/1.1 200 OK\r\n" +
"Content- Length: 0\r\n\" + " +
"\r\n");
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Trivia: Coincidentally, there is a different guy who drafted a similar solution and coincidentally named it reverse-http as well. This spec has a Reference Java Implementation, but not useful to you, since you are in no control of the server side.
On track:
I could find a Javascript implementation for the reverse-http that you are interested in here. Take a look for implementation hints, but, I guess you already have details.
For your problem, you would need a code fragment that can handle http requests (an http server functionality), while being embedded in a http client library.
Using Okhttp (I hope you are referring this) to achieve what you want may be a bit of work. It provides Websocket support, which is a more evolved version of reverse-http. So, you may try customizing the Websocket implementation of okhttp for your case.
A simplistic solution like yours, where you need not parse the http response can be achieved by adapting the code of popular NanoHTTPD library. Latest releases have added more dependency but an older release has just 1 java file, with no dependency and ideal for such adaptations.
I am replacing a .NET web service with a Java CXF web service using SOAP and JAXWS. The Client is fixed, and believe it or not, black-boxed. I am trying to get the service to work identically using the Java Service and the original .NET client. I have tried many approaches and confirmed that the response to the client is identical (bytes) to the .NET service. I have tried returning the Windows response from the Java service to no avail which means I have an issue related to the transmission, possibly encoding. I noticed that the response transfer-encoding=[chunked] - which I suspect may be an issue. I have not found a way to change this on the server...but since I cant modify the client, I need a work around. I am not familiar with the .NET API but here is the message I get:
BTW - the Error from the client is [6] ERROR - [sweeper].[SweeperService.CollectSettingsInformation] <11501> (9990) There is an error in XML document (1, 2). at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
at client.ReadMessageEnvelope(String xml)
at client.Translate(String xml)
at client.CollectSettingsInformation()
ANY Ideas would be appreciated.
Adapted from several other similar solutions:
public void handleMessage(Message message) {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage() || message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedOutputStream cs = new CachedOutputStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
IOUtils.closeQuietly(cs);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
csnew.flush();
IOUtils.closeQuietly(csnew);
int bytes = Math.toIntExact(currentEnvelopeMessage.getBytes().length);
HttpServletResponse response = (HttpServletResponse) message.get(AbstractHTTPDestination.HTTP_RESPONSE);
if(null != response){
log.debug("Setting Content Length: " + bytes);
response.setContentLength(bytes);
}
InputStream replaceInStream = IOUtils.toInputStream(currentEnvelopeMessage, "UTF-8");
os.flush();
if (os instanceof CopyingOutputStream)
((CopyingOutputStream)os).copyFrom( replaceInStream );
else
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
message.setContent(OutputStream.class, os);
IOUtils.closeQuietly(os);
} catch (IOException ioe) {
log.warn("Unable to perform change.", ioe);
throw new RuntimeException(ioe);
}
}
}
I am implementing an Android app that should upload data to CouchDB. Since I have restricted the admin access to one account, I have to authenticate before inserting a new database. And this is what I am currently struggling with: Authenticate and insert a new database. Operating via Terminal and using curl, everything is working out fine the following way:
> curl -X PUT http://admin_name:admin_password#url:port/database_to_be_inserted
First approach
My first approach was to simply do the same via HTTP PUT in my code like that:
private boolean putJSON(String json, String url) {
// url = http://admin_name:admin_password#url:port/database_to_be_inserted
HttpClient client = new DefaultHttpClient();
HttpPut put = new HttpPut(url);
try {
StringEntity stringEntity = new StringEntity(json,"utf-8");
put.setEntity(stringEntity);
put.setHeader("Content-type", "application/json; charset=utf-8");
put.setHeader("Accept", "application/json");
HttpResponse response = client.execute(put);
// ... buffered input reading on response...
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
However, doing so I retrieve the following error and JSON array:
Authentication error: Unable to respond to any of these challenges: {}
{"error":"unauthorized","reason":"You are not a server admin."}
The point is, that using the same method for inserting a new user works out perfectly. So, if I am using the above method with a correctly formatted user JSON-Dictionary and the following url, the user is inserted correctly.
http://admin_name:admin_password#url:port/_users/org.couchdb.user:user_name
This should prove, that I am using the right admin data at least, shouldn't it?
Second approach
So, by now, I am trying to authenticate using the "Authorization" option in my HTTP PUT's header:
private boolean putDatabase(String userName, String password, String url) {
// url = "http://url:port/database_to_be_inserted"
HttpClient client = new DefaultHttpClient();
HttpPut put = new HttpPut(url);
String authenticationData = userName+":"+password;
String encoding = Base64.encodeToString(authenticationData.getBytes(Charset.forName("utf-8")), Base64.DEFAULT);
put.setHeader("Authorization", "Basic " + encoding);
try {
put.setHeader("Content-type", "application/json; charset=utf-8");
put.setHeader("Accept", "application/json");
HttpResponse response = client.execute(put);
// ... buffered input reading on response...
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Still no success in inserting the database. The response I am parsing says:
Host not found
I have double checked the admin name, password, and url and everything seems correct. Does anyone of you see why this might not work out?
Ok, the answer is simple: The above code (at least the one of my second approach) is working fine. My mistake was to not explicitly specify the port via which the CouchDB should be accessed. This is, how I accidentally called the method:
putDatabase("adminName", "adminPassword", "http://url/database_to_be_inserted");
However, this is how I should have called it:
putDatabase("adminName", "adminPassword", "http://url:port/database_to_be_inserted");
Who is using iriscouch like me and does not know which port to specify here, can look it up in the config file. Using Futon this can be found in the entry "httpd > port" here:
> http://your_url_spec.iriscouch.com/_utils/config.html
More general and without Futon this can be found (and if you wish so edited) via command-line in the local.ini of your own CouchDB installation:
~$ cat etc/couchdb/local.ini
Hi I am writing a program that goes through many different URLs and just checks if they exist or not. I am basically checking if the error code returned is 404 or not. However as I am checking over 1000 URLs, I want to be able to do this very quickly. The following is my code, I was wondering how I can modify it to work quickly (if possible):
final URL url = new URL("http://www.example.com");
HttpURLConnection huc = (HttpURLConnection) url.openConnection();
int responseCode = huc.getResponseCode();
if (responseCode != 404) {
System.out.println("GOOD");
} else {
System.out.println("BAD");
}
Would it be quicker to use JSoup?
I am aware some sites give the code 200 and have their own error page, however I know the links that I am checking dont do this, so this is not needed.
Try sending a "HEAD" request instead of get request. That should be faster since the response body is not downloaded.
huc.setRequestMethod("HEAD");
Again instead of checking if response status is not 400, check if it is 200. That is check for positive instead of negative. 404,403,402.. all 40x statuses are nearly equivalent to invalid non-existant url.
You may make use of multi-threading to make it even faster.
Try to ask the next DNS Server
class DNSLookup
{
public static void main(String args[])
{
String host = "stackoverflow.com";
try
{
InetAddress inetAddress = InetAddress.getByName(host);
// show the Internet Address as name/address
System.out.println(inetAddress.getHostName() + " " + inetAddress.getHostAddress());
}
catch (UnknownHostException exception)
{
System.err.println("ERROR: Cannot access '" + host + "'");
}
catch (NamingException exception)
{
System.err.println("ERROR: No DNS record for '" + host + "'");
exception.printStackTrace();
}
}
}
Seems you can set the timeout property, make sure it is acceptable. And if you have many urls to test, do them parallelly, it will be much faster. Hope this will be helpful.
I'm accessing a server for web service calls. When I'm developing on the same network as the server, I can access the web service by its internal IP address but not its external IP address. However, if I'm not on the network, I can only access it by its external IP address. What's the best way to try one of the IP addresses and then fall back on the other?
Here's a sample of my code for accessing only one or the other:
protected String retrieve() {
Log.v(TAG, "retrieving data from url: " + getURL());
HttpPost request = new HttpPost(getURL());
try {
StringEntity body = new StringEntity(getBody());
body.setContentType(APPLICATION_XML_CONTENT_TYPE);
request.setEntity(body);
HttpConnectionParams.setConnectionTimeout(client.getParams(), CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(client.getParams(), SOCKET_TIMEOUT);
HttpResponse response = client.execute(request);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.e(TAG, "the URL " + getURL() + " returned the status code: " + statusCode + ".");
return null;
}
HttpEntity getResponseEntity = response.getEntity();
if (getResponseEntity != null) {
return EntityUtils.toString(getResponseEntity);
}
} catch (IOException e) {
Log.e(TAG, "error retrieving data.", e);
request.abort();
}
return null;
}
/*
* #return the URL which should be called.
*/
protected String getURL() {
return INTERNAL_SERVER_URL + WEB_APP_PATH;
}
Look at own IP address of your android. You can get it like stated here.
Then you can decide:
if you are in subnet of your office (e.g. 192.168.0.0/16) - use internal address
if you are in other subnet - use external address
Building on the very good comment by harism, I would simply use a static boolean to choose the IP and thus avoid pinging the wrong IP every time:
public static final Boolean IS_DEBUG = true; // or false
// all your code here
if (DEBUG)
ip = xxx.xxx.xxx.xxx;
else
ip = yyy.yyy.yyy.yyy;
This isn't exactly something you can easily fix in software. The right answer I think is fixing the filters/configuration that route traffic to your internal web server or by properly configuring DNS to return the proper IP depending on where you are (inside or outside the network). More information can be found here:
Accessing internal network resource using external IP address
http://www.astaro.org/astaro-gateway-products/network-security-firewall-nat-qos-ips-more/6704-cant-acces-internal-webserver-via-external-ip.html
and by Googling something like "external IP doesn't work on internal network"
You could put retry code in the catch clause for IOException
protected String retrieve(String url) {
Log.v(TAG, "retrieving data from url: " + url);
HttpPost request = new HttpPost(url);
try {
StringEntity body = new StringEntity(getBody());
body.setContentType(APPLICATION_XML_CONTENT_TYPE);
request.setEntity(body);
HttpConnectionParams.setConnectionTimeout(client.getParams(), CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(client.getParams(), SOCKET_TIMEOUT);
HttpResponse response = client.execute(request);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.e(TAG, "the URL " + getURL() + " returned the status code: " + statusCode + ".");
return null;
}
HttpEntity getResponseEntity = response.getEntity();
if (getResponseEntity != null) {
return EntityUtils.toString(getResponseEntity);
}
} catch (IOException e) {
if(url.equals(EXTERNAL_URL){
return retrieve(INTERNAL_URL);
}
Log.e(TAG, "error retrieving data.", e);
request.abort();
}
return null;
}
Note: Like most people have said, this probably is not a great solution for a production release, but for testing it would probably work just fine.
You could change your retrieve() call to take the host as a parameter. On startup, try to ping each possible host. Do a simple retrieve call to something that returns very fast (like maybe a test page). Work through each possible host you want to try. Once you found one that works, save that host and use it for all future calls.
1st, you should be able to handle the case on the runtime. I'd very strongly recommend vs the different builds.. For example: try the external, if fails the internal.
Some heuristics meanwhile:
Internal IP implies the network is the same. So you can check it, if it's the same try the internal address 1st, otherwise the external has precedence.
Later,save the mapping of the local ip address to the successfully connected one and look it up to alter the precedence.
The resolution itself may be carried by requesting the root '/' of the server with a timeout (you can use 2 different threads to carry the task simultaneously, if you feel like it).
Morealso, if you have access to the router/firewall it can be made to recognize the external addresses and properly handle it. So you can end up with the external address that works properly.
I would put this kind of environment-specific information in a properties file (or some kind of configuration file anyway). All you need is a file with one line (obviously you would change the IP address to what you need):
serverUrl=192.168.1.1
Java already has a built-in feature for reading and writing these kinds of files (see the link above). You could also keep database connection information etc. in this file. Anything environment-specific really.
In your code it looks like you are using constants to hold the server URL. I would not suggest that. What happens when the server URL changes? You'd need to modify and re-compile your code. With a configuration file, however, no code changes would be necessary.
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
and:
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod("http://www.myinnersite.com");
int responseCode = client.executeMethod(method);
if (responseCode != 200) {
method = new GetMethod("http://www.myoutersite.com");
}
etc...