How do I suppress Jetty 8's default ErrorHandler? - jetty

Jetty is helping my application too much. Whenever some unhandled Exception leaks out the top, Jetty takes it upon itself to build a very verbose response and spam it onto my clients
HTTP/1.1 500 com.mongodb.MongoException: No replica set members available in [ { address:'localhost/127.0.0.1:27017', ok:true, ping:0.49878865, isMaster:false, isSecondary:true, setName:dmReplSet, maxBsonObjectSize:16777216, },{ address:'localhost/127.0.0.1:27018', ok:true, ping:0.2565605, isMaster:false, isSecondary:true, setName:dmReplSet, maxBsonObjectSize:16777216, } ] for { "mode" : "primary"}
along with 14K of stacktrace wrapped in a very nice HTML page. The problem is, I don't want the details of the issue leaking out to the clients and, further, this is a JSON Web App accepting and emitting application/json content NOT the HTML Jetty has decided my clients want. I would like to suppress this default error handling having Jetty emit just that standard HTTP 500 response
HTTP/1.1 500 Internal Server Error
and no body at all. How do I get this done? It seems like I should be able to just tell Jetty to "no error page" in etc/jetty.xml or etc/jetty-webdefault.xml or something.

So this seems most easily solved without binding myself to Jetty too much by <error-page> in web.xml
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>device.webapp.ErrorHandler</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
Implementing ErrorHandler like
package device.webapp;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.httpclient.*;
import org.slf4j.*;
/**
* The ErrorHandler is intended to catch all unhandled Throwables (as configured in the web.xml)
* before they get out to Jetty's verbose ErrorHandler.
*
*/
public class ErrorHandler extends HttpServlet {
private static final long serialVersionUID = 1L;
private Logger log = LoggerFactory.getLogger( ErrorHandler.class );
#Override
protected void service( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException {
// Analyze the servlet exception
Throwable throwable = (Throwable) req.getAttribute( "javax.servlet.error.exception" );
String message = String.format(
"Responding 500 - Server Error on URI %s",
req.getAttribute( "javax.servlet.error.request_uri" ) );
if ( throwable != null ) {
log.error( message, throwable );
} else {
log.warn( "Throwable should not be null!" );
log.error( message );
}
/*
* Interestingly enough, you can't resp.sendError( 500, "Server Error" ) without triggering
* Jetty's DefaultErrorHandler which is the core of the problem we are trying to solve!
*/
resp.setStatus( HttpStatus.SC_INTERNAL_SERVER_ERROR );
}
}
It isn't pretty, but it works.

Related

Calling a Spring Boot 2 REST service with multipart/form-data with Postman results in a EOFException

While working on a personal project on Spring Boot, I have to develop a web service that accepts a file and some metadata, and I have decided to test with a Postman client.
Versions I am using:
Postman version: Postman for Mac Version 7.8.0 OS X 18.7.0 / x64
Java version: 1.8.0_212
Spring boot version: 2.1.1.RELEASE
As metadata will potentially be quite structured, I have decided to use the multipart/form-data content type, consisting in two parts:
a "file" part containing the file
a "body" part containing the json with the metadata
I've configured the call in Postman like this
Now, Spring boot configuration. First of all, I've added the following lines to application.properties:
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=20MB
# Max Request Size
spring.servlet.multipart.max-request-size=25MB
I've then created my controller with the endpoint
#PostMapping(Paths.Registrations.BASE)
#ResponseBody
public PostRegistrationResponseDto postRegistration(#RequestParam("file") MultipartFile file, #RequestParam("body") PostRegistrationRequestDto req) {
PostRegistrationResponseDto resp = new PostRegistrationResponseDto();
resp.setId(new Random().nextLong());
resp.setFileName(req.getFileName());
resp.setRegistrationTime(LocalDateTime.now());
return resp;
}
Unfortunately, the call does not even arrive to Spring: I receive a HTTP 500 error with this body
<!doctype html>
<html lang="en">
<head>
<title>HTTP Status 500 – Internal Server Error</title>
<style type="text/css">
...
</style>
</head>
<body>
<h1>HTTP Status 500 – Internal Server Error</h1>
</body>
</html>
In my server log I get no exception, but when I set the debugger to block on exceptions I saw that tomcat launches an EOF exception with this stack trace
java.io.EOFException
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1208)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1142)
at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:729)
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:352)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:294)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:791)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
I admit I do not even know where to start from... can someone give me some hints of what I'm doing wrong?
Thanks :)
In the end, what I discovered is that Tomcat throws a lot of exceptions, not always meaningful.
The problem I had was not related to that exception, but to the fact that Spring doesn't automatically map the String part to the Dto.
To make everything work, I had to write this component:
package it.aegidea.proofy.api.converters;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.aegidea.proofy.api.dtos.proofyapi.PostRegistrationRequestDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.io.IOException;
#Component
public class PostRegistrationRequestDtoConverter implements Converter<String, PostRegistrationRequestDto> {
private final ObjectMapper objectMapper;
#Autowired
public PostRegistrationRequestDtoConverter(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#Override
public PostRegistrationRequestDto convert(String source) {
try {
return objectMapper.readValue(source, PostRegistrationRequestDto.class);
} catch (IOException e) {
return null;
}
}
}
This way, Spring understood how to map the string to a PostRegistrationRequestDto and could successfully map the request to the types on the endpoint.

Disable auto generated JAX-WS Status Page

When I deploy and run my web service developed with JAX-WS I can see a summary page with some info on it, something like in this picture:
http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat/
For the final implementation we would like to remove this page so that a custom or a blank page is returned while still having access to the web service endpoint.
We are currently running on Tomcat.
There is a field on the WSServlet class that might do what you are looking for: JAXWS_RI_PROPERTY_PUBLISH_STATUS_PAGE (it's value is com.sun.xml.ws.server.http.publishStatusPage).
Looking at the source code from a JAX-WS download it seems that you need to set it as a context parameter in your web.xml file:
<web-app>
<context-param>
<param-name>com.sun.xml.ws.server.http.publishStatusPage</param-name>
<param-value>false</param-value>
</context-param>
...
Seems that HttpAdapter had something similar on it but was taken from an environment variable:
setPublishStatus(
System.getProperty(HttpAdapter.class.getName() + ".publishStatusPage")
.equals("true"));
The code on HttpAdapter is marked deprecated in the javadoc so the context parameter seems the way to go.
I have been trying to solve this for two days, Glassfish 3.1.2.
The only solution was to have
-Dcom.sun.xml.ws.transport.http.HttpAdapter.publishStatusPage=false
I know its old, but wantd to maintain the knowledge. Hope this helps any one with this issue.
I have completed the same task for WebLogic recently.
It was requested to hide/show a status page of a public web service depending on a target environment i.e. hide for production, show for dev.
Nothing of the previous answers worked for me.
The success solution is based on implementation of javax.servlet.Filter.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.HttpMethod;
#WebFilter(urlPatterns = { "/WeblogicWebService" })
public class FilterStatusSoapPage implements Filter {
#Value("${soap.status.page.disabled}")
private boolean flagDisablePublishStatusPage;
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
String queryString = httpReq.getQueryString();
if(flagDisablePublishStatusPage)
if(queryString == null || queryString.trim().isEmpty())
if(HttpMethod.GET.matches(httpReq.getMethod())) {
httpRes.setStatus(HttpServletResponse.SC_OK);
httpRes.getWriter().write("Access to status page of Web
Service is not allowed");
httpRes.getWriter().flush();
httpRes.getWriter().close();
return;
}
} catch (Exception e) {
System.err.println("Error on FilterStatusSoapPage filter");
chain.doFilter(request, response);
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {}
public void destroy() {}
}

Get Jetty HttpClient to follow redirects

I've got a program that uses Jetty version 8 to send an http post. My response handler works, but I'm getting an http response code 303, which is a redirect. I read a comment that jetty 8 has support for following these redirects, but I can not figure out how to set it up. I've tried looking at the javadocs, and I found the RedirectListener class, but no details on how to use it. My attempts at guessing how to code it haven't worked so I'm stuck. All help is appreciated!
Edit
I looked through the jetty source code and found that it will only redirect when the response code is either 301 or 302. I was able to override the RedirectListener to get it to handle repose code 303 as well. After that Joakim's code works perfectly.
public class MyRedirectListener extends RedirectListener
{
public MyRedirectListener(HttpDestination destination, HttpExchange ex)
{
super(destination, ex);
}
#Override
public void onResponseStatus(Buffer version, int status, Buffer reason)
throws IOException
{
// Since the default RedirectListener only cares about http
// response codes 301 and 302, we override this method and
// trick the super class into handling this case for us.
if (status == HttpStatus.SEE_OTHER_303)
status = HttpStatus.MOVED_TEMPORARILY_302;
super.onResponseStatus(version,status,reason);
}
}
Simple enough
HttpClient client = new HttpClient();
client.registerListener(RedirectListener.class.getName());
client.start();
// do your exchange here
ContentExchange get = new ContentExchange();
get.setMethod(HttpMethods.GET);
get.setURL(requestURL);
client.send(get);
int state = get.waitForDone();
int status = get.getResponseStatus();
if(status != HttpStatus.OK_200)
throw new RuntimeException("Failed to get content: " + status);
String content = get.getResponseContent();
// do something with the content
client.stop();

Getting Error while consuming self created webservices which connect Oracle SQL Developer

I am creating a webservices and while consuming getting error like this:
Exception in thread "main" org.apache.axis2.AxisFault: org.apache.axis2.AxisFault: >Mapping qname not fond for the package: oracle.jdbc.driver
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:531)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse>>>>(OutInAxisOperation.java:375)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at com.db.DatabaseClassStub.getDataBaseConnection(DatabaseClassStub.java:185)
at com.db.TestDatabaseClass.main(TestDatabaseClass.java:13)
For creating webservices that Connect Oracle SQL Developer using apache axis2 and eclipse. I have used the following s/w:
1). Eclipse Helios
2). Apache Tomcat 6
3). axis2-1.6.1-bin and axis2-1.6.1-war and also kept "ojdbc5" in tomcat lib folder.
My Webservices creation java code is,
package com.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseClass {
static Connection con = null;
public static Connection getDataBaseConnection()
{
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
try {
con = DriverManager.getConnection("jdbc:oracle:thin:#10.137.12.133:1521:ora11gr2","tran1","training123");
} catch (SQLException e) {
e.printStackTrace();
}
if (con != null) {
System.out.println("You made it, take control your database now!");
} else {
System.out.println("Failed to make connection!");
}
return con;
}
}
and Consuming webservices Java code is:
package com.db;
import java.rmi.RemoteException;
import com.db.DatabaseClassStub.GetDataBaseConnection;
import com.db.DatabaseClassStub.GetDataBaseConnectionResponse;
public class TestDatabaseClass {
public static void main(String[] args) throws RemoteException {
DatabaseClassStub stub = new DatabaseClassStub();
GetDataBaseConnection conn = new GetDataBaseConnection();
GetDataBaseConnectionResponse response = stub.getDataBaseConnection(conn);
System.out.println(response.get_return());
}
}
will you plz let me know where i am doing wrong?whenever i trying to execute TestDatabaseClass.java getting error which i have mentioned earlier. Same code (DatabaseClass.java) when i am executing in simple java project, its giving output but why not in webservices ?
You cannot 'export' a JDBC Connection in a SOAP web service operation: what goes across the wire has to be by definition serializable (as an XML).
You can expose methods/operations that provide the results of a query.

How to mock a complex REST call from the server side?

While working with javascript that uses REST services extensively -- including using vocabs like GET, PUT, POST, DELETES, etc; I have found it hard to mock the server side so front end development can go on independently (of back end).
It is also useful to sometimes capture multi-step data, so we can help reproduce the entire chain of REST even (or bugs related to the front end that are triggered from these chains)
What tools can I use to mock REST calls, esp stateful ones? (i.e. if I do a PUT on some resource, I expect the next GET on it to change somehow)
I tried SOAPUI 4.0.1 and it's REST mocking is disappointing. Plus, my need is beyond single state mocking (which anyone can do with a static .json file). I need to do state transition type of mocks; working with Content-Range headers would be best.
Anyone?
I actually ended up creating my own Java REST Mock Engine that can basically mock any response. As long as you can handcraft or cut-paste a text file that simulates the entire http response, you can use my solution to mock the service.
Here's the servlet:
package com.mockrest.debug;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class MockGridData
*/
public class MockRest extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public MockRest() {
super();
// TODO Auto-generated constructor stub
}
#Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
sub:{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String setdata = request.getParameter("__setdata");
if (setdata!=null && setdata.length()>0){
System.err.println("Setting Data...");
HttpSession sess = request.getSession(true);
String data = "/"+request.getParameter("__setdata");
sess.setAttribute("data", data);
try{
InputStream is = getServletContext().getResourceAsStream(data);
if (is!=null){
is.close();
response.getWriter().write("Successfully pointed next REST call to:"+data);
}
else{
response.sendError(500, "Cannot find resource:"+data);
}
}
catch (IOException ioe){
response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
}
}
else{
System.err.println("Fetching Data...");
HttpSession sess = request.getSession(false);
if (sess==null || sess.getAttribute("data")==null){
response.sendError(500,"Session invalid or no Previous Data Set!");
}
String rsrc = (String)sess.getAttribute("data");
System.err.println("Resource Being used:"+rsrc);
InputStream is = getServletContext().getResourceAsStream(rsrc);
if (is!=null){
String statusline = readLine(is);
Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
Matcher m = statusPat.matcher(statusline);
if (m!=null && m.matches()){
int status = Integer.valueOf(m.group(1));
response.setStatus(status, m.group(2));
}
else{
throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
}
String line;
Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
while ((line=readLine(is))!=null){
if (line.length()==0){
// end of headers
break;
}
Matcher m2 = httpHeaderPat.matcher(line);
if (m2!=null && m2.matches()){
response.setHeader(m2.group(1), m2.group(2));
}
}
OutputStream os = response.getOutputStream();
byte[] buf = new byte[1024];
int size;
while ((size=is.read(buf))>0){
os.write(buf, 0, size);
}
os.flush();
}
}
}
}
private String readLine(InputStream is) throws IOException {
StringBuffer sb = new StringBuffer();
char c;
while ((c=(char)is.read())!='\n'){
sb.append(c);
}
if (sb.charAt(sb.length()-1) == '\r'){
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
}
To configure it, place prebuilt response files inside your WebContent folder. I usually end these files with .http extensions.
An example init.http file is below. Pretend we placed this file inside a folder called data inside WebContent:
HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json
[
{
"id": "249F0",
"field1": " Global",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
},
{
"id": "962581",
"field2": "Europe",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
}
]
Headers must separate with body by an empty line (no spaces, nada). People familiar with http will notice it's a pure http response. This is on purpose.
You can use this tool to simulate any of the http headers you want the response to have; even going so far to respond with different server header(in my example, I simulated the response pretending to be IIS 6.0); or a different HTTP status code, etc.
To invoke it from your browser/javascript; first prime it with:
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
Then in your javascript or REST AJAX call, if it goes to
http://yourserver/yourweb/MockGridData
with any method or parameter; it will get the http response you previously crafted with; even down to the Content-Range; Cache headers; etc. If you then need the subsequent AJAX call to return something else, simply call with __setdata again. I suggest you setup a few buttons to do the explicit state transition in your web app.
Assuming everything is setup, for a simulated REST chain, a developer may do:
invoke
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
run a javascript module that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
click a button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step1.http
run another javascript step that will result in calling (say, with PUT)
http://yourserver/yourweb/MockGridData
click another button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step2.http
run another javascript step that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
but this time expecting different result than #4.
This should even work with binary and gzipped responses, but I haven't tested that.
Here is another homegrown rest-mocking tool: https://github.com/mkotsur/restito.