I'm trying to get familiar with the Google Drive API using the official Java sample. However, after wasting a few hours and attempting to set the sample up two times, I'm still not able to use it as expected.
Instead of displaying a file's content it throws a 404 error in the FileServlet (/svc path). More specifically, service.files().get(fileId).execute(); seems to return null. I've tried it with different files, different MIME types, directly from Google Drive as well as using the Google File Picker.
I've followed the steps described over at https://developers.google.com/drive/examples/java as closely as possible.
Has anyone been able to get the sample running?
edit:
Here's the log output of the FileServlet when requesting the URL /svc?file_id=0B08R9MrOE-ejZTY2M2I5MjAtYmVjZS00OTkyLWI4ZTEtOTg4OGM3YTIxMWEw (the 404 error is thrown at line 78):
2012-04-26 08:21:36.077
com.google.api.client.http.HttpRequest execute: -------------- REQUEST --------------
GET https://www.googleapis.com/drive/v1/files/0B08R9MrOE-ejZTY2M2I5MjAtYmVjZS00OTkyLWI4ZTEtOTg4OGM3YTIxMWEw
Accept-Encoding: gzip
User-Agent: Google-HTTP-Java-Client/1.8.3-beta (gzip)
D 2012-04-26 08:21:36.263
com.google.api.client.http.HttpResponse <init>: -------------- RESPONSE --------------
403 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
date: Thu
date: 26 Apr 2012 06:21:36 GMT
expires: Thu
expires: 26 Apr 2012 06:21:36 GMT
cache-control: private
cache-control: max-age=0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
content-length: 188
server: GSE
x-google-cache-control: remote-fetch
via: HTTP/1.1 GWA
D 2012-04-26 08:21:36.265
com.google.api.client.http.HttpResponse getContent: Response size: 188 bytes
D 2012-04-26 08:21:36.271
com.google.api.client.http.HttpResponse getContent: {
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit Exceeded. Please sign up",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit Exceeded. Please sign up"
}
}
This sounds a lot like "I don't know you" to me, so I have taken another look at my Client ID and Client Secret: I've noticed that there are two Client IDs and Client Secrets being displayed in the API Console, one "Client ID for web applications" and another "Client ID for Drive SDK". I've used the one for web applications previously, so I tried to switch to the one for the Drive SDK. Unfortunately, this doesn't change anything. Same error... :/
As per your logs it seems that your 404 error is caused by a 403 error returned on the request to the Drive API.
Errors from Google APIs usually contains an explanations in their body. In your case:
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit Exceeded. Please sign up",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit Exceeded. Please sign up"
}
}
This one would typically mean that you have not enabled access to the Google Drive API on your Google APIs Console project. In order to do this:
Open your project in the Google APIs Console
Go to the Services section
Enable the Drive SDK and Drive API by clicking the On/Off toggle
Don't forget to configure your app in the Drive SDK section and your OAuth settings in the **API Access" section
This is all described in the Get started > Register an App section of our documentation. You should also make sure that you go through the other sub-sections of Get started.
I eventually managed to get it working. I'm not sure what was the problem before, but here are some tips for those who are facing similar problems:
The "Client ID for web applications" and the "Client ID for Drive SDK" confused me. Unfortunately the documentation doesn't tell you which one to use at which place, but it seems like you only need the "Client ID for web applications".
If you update your Chrome extension or the API console it could take some time until Drive recognizes those changes. For example, changing the OAuth Client ID in the API console could take some time until it takes effect, since everybody's caching. If you are testing your application, deleting cache and cookies helps speed up the process.
Good luck with your applications, and thanks to everybody who helped me!
In my experience, "403 Quota Exceeded" always stems from the HTPP Authorization header not being set.
I used the java OAuth code distributed in Google's dredit sample for a program that goes through the "opens with" flow and likewise recieved the 403 error.
I had to dig into the OAuth code to find the problem, the source of which I haven't seen mentioned elsewhere in regard to the 403 error. Essentially the ExchangeCode method of CredentialMediator assumes there is only one redirect uri and this is the one you are hoping to go to. This wasn't the case for me and resulted in a CodeExchangeException.
To resolve you could massage the list of uris in the client_secrets so the uri you wish to redirect to is first or some such, but if this method could go to any one of a number of uris it will need parameterisation.
I hope this helps someone root out their 403 gremlin.
Related
I meet this error when send a request and get back response with code 401:
com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found
Some people say that:
This error happens beause the server sends a 401 (Unauthorized) but does not give a "WWW-Authenticate" which is a hint for the client what to do next. The "WWW-Authenticate" Header tells the client which kind of authentication is needed (either Basic or Digest). This is usually not very useful in headless http clients, but thats how the standard is defined. The error occurs because the lib tries to parse the "WWW-Authenticate" header but can't.
( android - volley error No authentication challenges found )
But it's quite weird for me because I don't want to use WWW-authenticate things, I just want to get the code 401, but I always get the exception.
How can I bypass this problem? Any suggestion is really appreciated.
I have do some research and come to conclusion that, this is a server issue, that did not follow the convention.
From wiki:
401 Unauthorized (RFC 7235)
Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource. See Basic access authentication and Digest access authentication.
I think the best way to solve this problem is to solve in the server by add the header (something like:
WWW-Authenticate: xBasic realm=""
For me, I cannot change the server, so I have to check the error message to detect that a 401 error:
if (error.getMessage().equalsIgnoreCase("java.io.IOException: No authentication challenges found")){
showLoginError();
}
Not very elegant solution but work for now.
I am using Spring Oauth client setup on my frontend. I'm authentication against my API, which returns this
{
error: "unauthorized"
error_description: "User does not exist"
}
using my rest client (Google Plug: Advance RestClient); which is expected.When I use Spring Oauth Client setup, I was expecting that the error object RestClientException would have that JSON result in the response body however it is empty. See attached image (Watch Console shows what's in the response body).
Right click the image and select open image in new tab to make the image bigger
Request sent
grant_type=c_password&username=test&password=test&client_id=test&client_secret=test
Response
Date: Sun, 26 Apr 2015 20:59:45 GMT
Connection: close
Cache-Control: no-store
Pragma: no-cache
Www-Authenticate: Bearer realm="api/", error="unauthorized", error_description="User does not exist"
Content-Type: application/json;charset=UTF-8
Server: Jetty(7.x.y-SNAPSHOT)
Via: 1.1 vegur
Raw
JSON
This may be a RestTemplate bug - your server (or the proxy) is using a combination of Connection: close and no Content-Length headers.
One way to confirm this: make your server write Content-Length headers (in Spring, adding a ShallowEtagHeaderFilter will do that).
If this workaround fixes this, then this bug has been fixed in SPR-8016 - upgrading the client application to Spring 4.1.5 will solve this.
it seems the actual exception that you are getting is not RestClientException. Just debug the error, it would be something HttpClientErrorException. So catch this exception instead of above one. This exception has methods to get the desired result.
I'm trying to retrieve links from this page: http://www.seas.harvard.edu/academics/areas
There is a link named "Computer Science" in the middle of the page. Its underlying link is given as "/academics/areas/computer-science". I'm able to convert it to an absolute URL with the Java built-in URL class, obtaining "http://www.seas.harvard.edu/academics/areas/computer-science".
When I click the link in Chrome browser, however, the absolute URL changes to "http://www.seas.harvard.edu/computer-science".
So my question is two-fold:
How does the URL redirect work in this page?
Is there any library or method in Java that would help me obtain the URL after redirect?
I need to obtain the URL after redirect because I want to read the source code of the page but the URL before redirect doesn't work for me. I'm using the JSoup library to read from the URL so I suspect it might be a javascript-based redirect.
From curl --dump-header [file] [URL] the file looked like:
HTTP/1.1 301 Moved Permanently
Age: 0
Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0
Content-Type: text/html
Date: Tue, 13 Aug 2013 13:00:12 GMT
ETag: "1376398812"
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 13 Aug 2013 13:00:12 GMT
Location: http://www.seas.harvard.edu/computer-science
Server: nginx
Vary: Accept-Encoding
Via: 1.1 varnish
X-AH-Environment: prod
X-Cache: MISS
X-Drupal-Cache: MISS
X-Redirect-ID: 44
X-Varnish: 2704315535
transfer-encoding: chunked
Connection: keep-alive
As you can see this is a 301 permanent redirect served from the server.
To obtain the data:
You can use HttpURLConnection to connect, but before connecting, call myConn.setInstanceFollowRedirects(true). Redirects are followed and you can get your output stream and read it.
To obtain the URL itself:
You can use HttpURLConnection to connect, but before connecting, call myConn.setInstanceFollowRedirects(false) to not follow redirects. This will save the actual URL in the right place.
The trick here is that for some odd reason, HttpURLConnection doesn't allow to retrieve a header by name unless you parse it as a date.
So, you will need to iterate an integer, calling getHeaderFieldKey after making the connection and checking if it equal to Location and if it is, getting getHeaderField with the same integer to get the location. Annoying, I know. But a location isn't a date and this is a JRE oversight.
I used Fiddler to investigate and the site return for link http://www.seas.harvard.edu/academics/areas/computer-science HTTP 301 response code, that performs the redirect.
I you want to get real URL. You should perform real request to harvard.edu web server and parse response. (Redirect URL is located in Location key in HTTP Header).
Sorry about your second question. I don't have skill in Java.
This SO question may help (httpclient-4-how-to-capture-last-redirect-url)
There is probably e.g. a .htaccess and mod_rewrite redirect. Using Firefox's Console I could see the requests. As you can see below the server is sending back a 301 Moved Permanently message. This tells the browser to redirect to the address returned in the Location header of the response.
The way you obtain the changed URL depends on the way you load the page:
If you use ready libraries & code to load the page to e.g. a DOM object, the you could use that ready HTTP system to load the response, this will probably result to it automatically redirecting -> you will get the URL from the URL of the loaded page. If it does not do that, then you must check for status code 301 or 302 and when those are received then the changed URL is in the Location header of the response.
If you have your own code written to load the response via TCP sockets, then you must just load the response as normal, but again check for the 301 and 302 status codes and do as described in the previous section.
I can only attempt to address Q1 since I'm not a Java programmer. The source code says they're using Drupal, so I speculate that they're using Drupal's global redirect module (SO discussion about Drupal redirect module here). Looking at the module's documentation might shed some light on how to obtain the correct url with Java.
There's also numerous ways within javascript to have url requests automatically redirect to some base page (e.g., CS homepage), while physically navigating the site allows the user to advance to new pages. This is standard practice in many single page web apps. If this is the case, then #hexafraction 's suggestion might be able to help you retrieve the desired url, though I'm unfamiliar with the Java methods (s)he is suggesting.
You can get the Redirect URL from the below code setting followRedirects to false.
You will get the source code of the redirected page if you set it to true and that's the default behavior of Jsoup
Connection con = Jsoup.connect("http://www.seas.harvard.edu/academics/areas/computer-science")
.userAgent("Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36")
.followRedirects(false);
System.out.println("Redirected Url : " + con.execute().header("Location")); //null if followRedirect is true
Document doc = con.get();
System.out.println(doc.html());
System.out.println("=================================================");
I have created a webservice with soap requests.
now the domain has changed on a different server (metanet).
The problem is that all my soap requests done from my android devices generate a 406 error. also If I try the service with the soapui tool it generates the 406 error.
in the access_log file I see: (when done from soapui)
xxx.xx.xxx.xxx - - [27/Jun/2013:14:48:07 +0200] "GET /ws/ HTTP/1.1" 406 1240 "-" "Apache-HttpClient/4.1.1 (java 1.5)"
and in the error_log
[Thu Jun 27 14:48:07 2013] [error] [client xxx.xx.xxx.xxx] mod_security: Access denied with code 406. Pattern match "(TwengaBot|Voila|MJ12bot|Baiduspider|psbot|Yeti|WebofantBot|WebAlta|Bloglines|Java)" at HEADER("USER-AGENT") [severity "EMERGENCY"] [hostname "xxx.xx"] [uri "/ws/"]
I have tried to create a .htaccess file and enter the mime type:
AddType application/xml xml
Anyone some more ideas?
I guess it could be because of the Pattern match 'Java'? how could I resolve this issue?
Your error log "mod_security: Access denied with code" suggests your server is using modsecurity and it looks like you have a rule to prevent robots/ webcrawlers from "TwengaBot|Voila|MJ12bot|Baiduspider|psbot|Yeti|WebofantBot|WebAlta|Bloglines|Java".
You can change that of course and here are some more useful links for you:
http://www.modsecurity.org/documentation/modsecurity-apache/2.5.12/modsecurity2-apache-reference.html
http://www.modsecurity.org/documentation/modsecurity-apache/1.9.3/html-multipage/07-logging.html
http://modsecurity.org/documentation/modsecurity-apache/1.9.3/html-multipage/04-rules.html
http://www.modsecurity.org/projects/modsecurity/index.html
I'm using jCryption and JavaCryption, the server-side implementation of the jCryption JavaScript plug-in.
There appears to be an issue with what seems the Java implementation, in that FireFox's firebug is reporting a "not-well formed" error with the JSON that is returned to the client from the server. So, unlike the thread, "not well-formed" error in Firefox when loading JSON file with XMLHttpRequest, this is coming from the response object, NOT the request object.
I tried adding .JSON, application/json as a MIMEtype to my web server, IIS 7.5, but that didn't help. Then I tried .JSON, text/plain and that didn't help, either.
Do I have to edit the Java code to force application/json, when it sends it back to the client? Or, what can I do to resolve this issue?
Thank you for any help.
Here is the raw output for the first one causing the "not-well formed" error:
HTTP/1.1 200 OK
Content-Length: 294
Server: Microsoft-IIS/7.5
X-Powered-By: Nothing
Date: Tue, 23 Oct 2012 02:10:24 GMT
{"e":"10001","n":"b3fbbe3d2e3599e840a117be08f72726d8ee643dada3805ab24b9a9150d123a7a0902ae45f2f2e194e5462c4f5c3b91cca91b48d1f07c6cd7fab629a331148f66516df05dfa0bd95cc9f477069e60fa54eab8a5586d08436717758d9706b90c884eded7260af1ce5ff70f507b9c5ddb019b6e1313a77f4eab3b2d04a09934d8d","maxdigits":"131"}
Here is the second one:
HTTP/1.1 200 OK
Content-Length: 200
Server: Microsoft-IIS/7.5
X-Powered-By: Nothing
Date: Tue, 23 Oct 2012 02:10:24 GMT
{"challenge":"zf6iI5D8hVDCmMVuHIFy71ikKxcqVzkLplMDKP6Hgz7EPv2STfYjcBlf6ep1wu5OMCCsPKf4dRECpVvr7yIK8kCm0I5c4xTXCkmnyyzBXeHgbvkzGWVmaLzxj5RYajdWLFkvN1waV41FhR+PtK1tOmGe8k57wSZ/yyZUAsvh7NaJf6THc9P9rQ=="}
You need to look at what is in the actual response. You need to look at what the responses content-type header currently says, and what the body of the response contains. Firebug can show you both of those.
There is a good chance that the response body is not JSON at all ... but an HTML error report about some problem with the request (as the server sees it).
Either way, you can't resolve the problem properly until you have worked out what is causing it. Simply assuming that it is content type problem is not a sound strategy.
Based on the response you posted, the problem is most likely due to the fact that there is no Content-Type header. If this response comes from Java, then you probably do need to modify the Java (or JSP) to set the missing header in the response.
Set Content-Type to application/json in jsp file
Setting a Content-type header in a servlet.
(There are other ways to do this if it is impossible to change the servlet or JSP code.)