HttpPost request including spaces fails - http

When using a HttpPost request I use UTF-8 for proper encoding. When I use a space in one of the parameters, I still get the following error:
Caused by: org.apache.http.ProtocolException: Invalid redirect URI: /seek/nearest.aspx?key=Miami vice&ex=0&cFilter=9a79e6ce-3344-409c-bbe9-496530baf758&children=n
The invalid character in the URL is the space between the "Miami" and "vice".
Hmmm, I thought that the POST request is not put in the URL string.
These are the steps I take to build the HttpPost request. In the "mKeyword" is the string with "Miami vice".
1 - put the request in the NameValue list:
List<NameValuePair> kwNvP = new ArrayList<NameValuePair>();
kwNvP.add(new BasicNameValuePair("ctl00$ContentBody$LocationPanel1$OriginText", mKeyword));
2 - build the URI
String search_url = "http://www.example.com/seek/nearest.aspx";
try {
theUri = new URI( search_url);
} catch ( URISyntaxException e) { etc.
3 - build the post request
HttpPost method = new HttpPost( theUri);
method.addHeader("User-Agent", "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0) Firefox/7.0");
method.addHeader("Pragma", "no-cache");
method.addHeader("Content-Type", "application/x-www-form-urlencoded");
method.addHeader("Accept-Language", "en");
4 - build the content entity
HttpEntity entity = null;
try {
entity = new UrlEncodedFormEntity( kwNvP, HTTP.UTF_8);
}
catch ( UnsupportedEncodingException e) { etc
5 - executing the request
method.setEntity( entity);
HttpResponse res2 = null;
try {
Thread.sleep( (int) (1000 * GeoTools.random( 0.1, 0.3)));
res2 = client2.execute(method);
Log.v( WaypointActivity.TAG, "Status line = " + String.valueOf(res2.getStatusLine()));
} catch (Exception e) {
// --> Coming here ... see the exception trace
Can you help me solving this problem?

Without seeing the complete program or the real target URL I'm not 100% sure ... but this part of the error stands out:
Invalid redirect URI
That implies that your original POST request is not returning a 200 but a 301, and whatever server is handling the redirect is creating the malformed URL, not your code.

Related

Creating error page in servlet filter causes error "Writer already obtained"

I'm creating a custom framework (something like portal) for numerous JSF 1.x and 2.x applications. For that purpose I created a servlet filter that "enrich" application HTML with framework menu, breadcrumb, logout, etc. In that filter I read app's HTML, modify it and write it to an output stream. So far everything worked great but now I'm having problem with creating a custom error page.
I tried to read a response status code and based on that code, I'm creating output HTML:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) req;
HttpServletResponse res = (HttpServletResponse) resp;
StringServletResponseWrapper responseWrapper = new StringServletResponseWrapper(res);
// Invoke resource, accumulating output in the wrapper.
chain.doFilter(req, responseWrapper);
String contentType = res.getContentType();
byte[] data;
if (contentType.contains("text/html")) {
String html = null;
int statusCode = res.getStatus();
LOG.debug("status: {}, committed: {}", statusCode, res.isCommitted());
if (statusCode != 200) {
html = "<!DOCTYPE html>\r\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n" +
"<head>\r\n" +
"<script type=\"text/javascript\" src=\"/path/to/jquery/jquery-1.11.1.min.js\"></script>\r\n" +
"<title>Error</title>\r\n" +
"</head>\r\n" +
"<body>\r\n" +
"<h1>Error</h1>\r\n" +
"</body>\r\n" +
"</html>";
Collection<String> headerNames = res.getHeaderNames();
Map<String, String> headerMap = new HashMap<String, String>();
for (String header : headerNames) {
headerMap.put(header, res.getHeader(header));
}
res.reset();
for (Map.Entry<String,String> entry : headerMap.entrySet()) {
res.setHeader(entry.getKey(), entry.getValue());
}
res.setStatus(statusCode);
response.setContentType("text/html");
} else {
html = responseWrapper.getCaptureAsString();
}
if (ObjectUtils.isNotEmpty(html)) {
// do some modification
String modifiedResponse = doModification(html);
data = modifiedResponse.getBytes("UTF-8");
response.setContentLength(data.length);
response.getOutputStream().write(data); // this line causes error
}
} else {
data = responseWrapper.getCaptureAsBytes();
response.setContentLength(data.length);
response.getOutputStream().write(data);
}
}
This code works without any problem if status code equals 200 (else clause), but when it's not equal to 200 (I triggered 404 error), the following error occures:
com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[Faces Servlet]: java.lang.IllegalStateException: SRVE0209E: Writer already obtained
I don't really understand why does this error appear. The only difference between two cases is HTML content which is valid in both cases. Any help?
Using Websphere Application Server 8.5.5.18.
EDIT: I've tried to call reset() and then set headers and status code again, but that reset() call causes an IllegalStateException - as stated in javadoc, apparently response has already been committed. As far as I understand, flush() method of ServletOutputStream could cause response to be committed, but I'm not calling it anywhere. I've also added some log to see if response really is committed. In both cases (status 200 and 404) response.isCommitted() returns true. Does that mean that response is committed before doFilter is called?
Option 1 - downgrade JAX-RS to 1.1
Once JAX-RS version is changed back to 1.1 the errors in SystemOut.log will not be shown.
Do the following steps:
Change the JAX-RS version to 1.1 using WAS 9 Admin console. See the detailed instructions at
https://www.ibm.com/support/knowledgecenter/SSEQTP_9.0.0/com.ibm.websphere.base.doc/ae/twbs_jaxrs_coexist_adminconsole.html
Option 2 - move chain.doFilter to the end of your doFilter method
chain.doFilter(req, resp);
}
Option 3 - Remove other usages of PrintWriter or OuputStream
Review application to determine if both PrintWriter and OuputStream were obtained. Modify the failing servlet/JSP to only obtain one or the other.

WebException timeout vs HttpWebResponse timeout?

I'm using the Asp.Net WebClient to create an HTTP post.
The below code has try-catch block around the code which catches WebException:
try
{
using (MyWebClient wc = new MyWebClient())
{
wc.Headers[HttpRequestHeader.ContentType] = _lender.ContentType;
wc.Timeout = 200;
return _lender.GetResult(wc.UploadString(_lender.PostUri, _lender.PostValues));
}
}
catch (WebException ex)
{
return new ServiceError(ex.Status.ToString());
}
The main exceptions I'm looking for are timeouts. I've extended WebClient to allow me to set the timeout.
When I set the timeout to say 100ms, an exception is thrown as expected. I can get the WebException status as per the example (it returns "timeout"), however, I want to return status codes too.
If I extract the httpwebresponse using ex.Response I get a null value returned, when I was expecting an associated status code.
Why do I not get an HttpStatus.Request.Timeout?
I have the same problem and I realise a few things while I search for a solution.
WebExceptionStatus enum is not equivalent to http status code that the API you call returned. Instead it is a enum of possible error that may occour during a http call.
The WebExceptionStatus error code that will be returned when you receive an error (400 to 599) from your API is WebExceptionStatus.ProtocolError aka number 7 as int.
When you need to get the response body or the real http status code returned from the api, first you need to check if WebException.Status is WebExceptionStatus.ProtocolError. Then you can get the real response from WebExceptionStatus.Response and read its content.
Sometimes the timeout is handled by the caller (aka your code) so you do not have a response in that case. So you can look if WebException.Status is WebExceptionStatus.Timeout
This is an example:
try
{
...
}
catch (WebException webException)
{
if (webException.Status == WebExceptionStatus.ProtocolError)
{
var httpResponse = (HttpWebResponse)webException.Response;
var responseText = "";
using (var content = new StreamReader(httpResponse.GetResponseStream()))
{
responseText = content.ReadToEnd(); // Get response body as text
}
int statusCode = (int)httpResponse.StatusCode; // Get the status code
}
else if (webException.Status == WebExceptionStatus.ProtocolError)
{
// Timeout handled by your code. You do not have a response here.
}
// Handle other webException.Status errors. You do not have a response here.
}

Error passing parameters into a servlet

I want to implement a servlet to get the parameters from the browser and insert into db using http post not http get.
the servlet will recieve params from a url such as this http://localhost:8080/NewServlet?firstname=me&middlename=you&lastName=secret&location=here , and insert into the db, but Its like I cant do it properly.
here is the piece of code am trying to run
public class NewServlet extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String firstName = request.getParameter("firstname");
String middleName = request.getParameter("middlename");
String lastName = request.getParameter("lastname");
String location = request.getParameter("location");
String result;
java.sql.Connection connDB = null;
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException ex) {
Logger.getLogger(DBConnection.class.getName()).log(Level.SEVERE, null, ex);
}
try {
connDB = DriverManager.getConnection("jdbc:postgresql://" + "localhost" + ":" + 5432 + "/" + "mydb", "username", "secret");
connDB.setAutoCommit(false);
System.out.println("Connection established : [" + connDB.toString() + "]");
java.sql.Statement bankStmt = connDB.createStatement();
java.sql.Statement stt = connDB.createStatement();
bankStmt.execute("INSERT INTO full_names(firstname, secondname, lastname) VALUES('"+firstName+"', '"+middleName+"', '"+lastName+"' )");
java.sql.Statement bnk =connDB.createStatement();
bnk.execute("INSERT INTO employee_details(location) VALUES('"+location+"')");
}
connDB.commit();
} catch (SQLException ex) {
ex.printStackTrace();
try {
connDB.rollback();
} catch (SQLException ex1) {
ex1.printStackTrace();
Logger.getLogger(DBConnection.class.getName()).log(Level.SEVERE, null, ex1);
}
Logger.getLogger(DBConnection.class.getName()).log(Level.SEVERE, null, ex);
}
out.println("<b><font color='blue'>Your FirstName is :</font></b>"
+ "<b>"+ firstName +"</b>" + "<br>");
out.println("<b><font color='blue'>Your Middle Name is :</font></b>"
+ "<b>"+ middleName +"</b>" + "<br>");
out.println("<b><font color='blue'>Your Last Name is :</font></b>"
+ "<b>"+ lastName +"</b>");
}
}
When I try to run the code using the url http://localhost:8080/NewServlet?firstname=me&middlename=you&lastName=secret&location=here
I get the following error:
HTTP Status 405 - HTTP method GET is not supported by this URL
type Status report
message HTTP method GET is not supported by this URL
description The specified HTTP method is not allowed for the requested resource (HTTP method GET is not supported by this URL).
You have only defined the do Post() method in your servlet. But when you are accessing using http://localhost:8080/NewServlet?firstname=me&middlename=you&lastName=secret&location=here , the doGet() is called which you have not defined. Just copy and paste the code in the doPost() method inside a doGet() in the same servlet.
Like this :
public void doGet{
//your code
}
HTTP Status 405 - HTTP method GET is not supported by this URL
Well, this is already the whole answer at its own. You're sending a GET request, but your servlet implementation doesn't support it. According to the code you wrote, it only supports POST requests. You don't have a doGet() implementation anywhere, but only doPost().
I'm not sure what's the functional requirement is and why this error is unclear to you, but to get your code to run, you should either send a POST request instead, or to rename doPost method to doGet in your servlet.
Unrelated to the concrete problem, your code has other problems as well, among others SQL injection holes, DB resource leaking and mingling the view in the controller. To learn servlets properly, you may want to start at our servlets wiki page.

How do I get responseText when server sends 500 error on WebRequest.Create(URL).GetResponse()

I am calling a json web service that sends error messages by setting StatusCode to 500 and then sending error message as response text (such as { "Message": "InvalidUserName" } ).
Problem is that ASP.NET does not give me the response text if web service sends statuscode 500.
try
{
WebRequest request = WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string result = streamReader.ReadToEnd();
streamReader.Close();
response.Close();
return result;
}
catch (Exception e)
{
// If web service sends 500 error code then we end up here.
// But there is no way to get response text :-(
}
Is there a way to solve this? Also: I am controlling the web service, so it might be a solution to do some change their. (Note: I need to call the service using plain WebRequest stuff - in this case it will not work with other methods such as adding as WebReference etc)
Any ideas?
Catch WebException instead. It has a Response property containing the response. Be sure to check for null before using it.

Groovy/Grails posting XML over HTTP (using REST plugin)

I am trying HTTP Post an XML string to a WebMethods server using basic auth. I was trying to use the REST plugin which sits on top of HTTP Builder. I've tried a few things all resulting in a 0 length response. Using Firefox poster I have used the exact same XML and user auth and the WebMethods response is to echo back the request with some extra info, so it is something I am doing in the code below that is wrong. Hope someone has a pointer for doing a HTTP Post of XML.
string orderText = "<item>
<item>1</item>
<price>136.000000</price>
</item>"
def response = withHttp(uri: "https://someserver.net:4433") {
auth.basic 'user', 'pass'
// have tried body: XmlUtil.serialize(orderText)
def r = post(path: '/invoke/document', body: orderText, contentType: XML, requestContentType: XML)
{ resp, xml ->
log.info resp.status
log.info resp.data
resp.headers.each {
log.info "${it.name} : ${it.value}"
}
}
log.info r
return r
}
Logs say:
04-02-2011 14:19:39,894 DEBUG HTTPBuilder - Response code: 200; found handler: OrdersService$_closure1_closure2_closure3_closure4#36293b29
04-02-2011 14:19:39,895 INFO HTTPBuilder - Status: 200
04-02-2011 14:19:39,896 INFO HTTPBuilder - Data: null
04-02-2011 14:19:39,896 INFO HTTPBuilder - XML: null
04-02-2011 14:19:39,913 INFO HTTPBuilder - Content-Type : application/EDIINT; charset=UTF-8
04-02-2011 14:19:39,913 INFO HTTPBuilder - Content-Length : 0
Cheers,
Steve
Here is what I ended up with. It is quite standard use of common HTTP Client
For basic auth over SSL you can simply have your url like: https://user:pass#www.target.com/etc
Grails remember to copy the HTTPClient jar to the lib folder or in my case I installed the REST plugin which includes HTTPClient anyway.
There are good docs on the HTTPClient site: http://hc.apache.org/httpcomponents-client-ga/
import org.apache.http.HttpEntity
import org.apache.http.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.DefaultHttpClient
def sendHttps(String httpUrl, String data) {
HttpClient httpClient = new DefaultHttpClient()
HttpResponse response
try {
HttpPost httpPost = new HttpPost(httpUrl)
httpPost.setHeader("Content-Type", "text/xml")
HttpEntity reqEntity = new StringEntity(data, "UTF-8")
reqEntity.setContentType("text/xml")
reqEntity.setChunked(true)
httpPost.setEntity(reqEntity)
log.info "executing request " + httpPost.getRequestLine()
response = httpClient.execute(httpPost)
HttpEntity resEntity = response.getEntity()
log.info response.getStatusLine()
if (resEntity != null) {
log.with {
info "Response content length: " + resEntity.getContentLength()
if (isDebugEnabled()) {
debug "Response Chunked?: " + resEntity.isChunked()
debug "Response Encoding: " + resEntity.contentEncoding
debug "Response Content: " + resEntity.content.text
}
}
}
// EntityUtils.consume(resEntity);
}
finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpClient.getConnectionManager().shutdown()
}
return response.getStatusLine()
}
try it this way:
HTTPBuilder builder = new HTTPBuilder( url )
builder.request( Method.POST ) {
// set uriPath, e.g. /rest/resource
uri.path = uriPath
requestContentType = ContentType.XML
// set the xml body, e.g. <xml>...</xml>
body = bodyXML
// handle response
response.success = { HttpResponseDecorator resp, xml ->
xmlResult = xml
}
}
I guess there's no need to get it done that difficult, I use a simpler approach (by the way you don't need extra plugins). So consider the next piece of code, and of course I'm ommiting the authentication part
class YourController{
static allowedMethods = [operation:['POST','GET']]
def operation(){
def xmlRequest = request.reader.text
println xmlRequest
//TODO: XML postprocessing, here you might use XmlParser.ParseText(xmlRequest)
}
}
I know this might be out of context because you are asking for the REST plugin, yet I wanted to share this since there's another alternative.
I'm using grails 2.3.2 and Firefox RESTClient to test the webservice.

Resources