Hi Mustafa

Thanks for the quick response Sergey, I never intended my question to be a
"Why haven't you don't this, this is stupid" type of question, you guys
have done a great deal of work already

thanks, I've actually haven't taken it like that at all :-). But now that we're seeing users doing some serious stuff with CXF JAXRS we're obviously getting concerned (and I'd say a bit embarrassed :-)) when users report NPEs or some other bugs which could've been prevented earlier on easily enough.

with CXF and it is  very much so appreciated. I will be doing an upgrade
to 2.2.4 and will look to submitting a patch for the other fix so we can
target it for 2.2.5, hopefully before you do :) Thanks again!

The fix I referred to below is already in 2.2.5-SNAPSHOT, the bug you reported was in the MultipartProvider, there's a test on the trunk now which ensures that multiparts POSTs with empty bodies are rejected. See

http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java

#testMultipartRequestNoBody

If you think the way such cases are processed can be improved then please submit a patch. In fact we'll welcome other patches too :-)

thanks,
Sergey


Mustafa

-----Original Message-----
From: Sergey Beryozkin [mailto:[email protected]]
Sent: Friday, 6 November 2009 5:50 AM
To: Sergey Beryozkin; [email protected]
Subject: Re: NPE when doing a post with null content type

MultipartProvider has been fixed to check the ContentLength, if 0 it will
throw 400, sismilarly to what is requested from JAXB
providers by JAXRS 1.1. JAXRS 1.1 actually says that only a JAXB provider
should throw 400 in such cases but given that the support
for Multiparts is not currently standardized and it's clearly a client bug
in this case, I reckon  it's appropriate to throw 400 too
from MultipartProvider

cheers, Sergey

----- Original Message ----- From: "Sergey Beryozkin" <[email protected]>
To: <[email protected]>
Sent: Thursday, November 05, 2009 10:16 AM
Subject: Re: NPE when doing a post with null content type


Hi


This seems to related to the Content-Type list having a null object.
The
HttpHeaderImpl class seems to do the following on line 132



String[] ls =  values.get(0).split(",");



But because content type has a null object, the NPE is thrown.


This issue (HttpHeadersImpl throwing NPE if one of the headers's value
is actually 'null' ) has been fixed in 2.2.3 or 2.2.4,
there's an extra check now in getListValues()...



I have also found another issue where the content-type is set to
multipart/mixed but no post content exists...

<snip/>
--------------------------------------

I get


javax.ws.rs.WebApplicationException:
java.lang.StringIndexOutOfBoundsException: String index out of range:
-1

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:
839)

Now CXF may have deliberately not implemented these checks for some
reason, and left these checks for us to implement via the use of an
interceptor, but I would find that a bit odd.

It is a CXF bug so I agreed it's odd a custom interceptor has to do
these kinds of checks. JAX-RS 1.1 explicitly says what needs
to be done in case when request bodies are not available so this issue
will be fixed for 2.2.3 and I'll try to fix it for the
incoming 2.2.5.

I wish we started implementing with various possible issues like empty
request bodies, etc, in mind from the get-go, but for a
while (and still in some cases today) the goal has been : to do it (a
given feature, etc) asap, make sure the basic case work well
and enhance/improve over time. I'm hoping there're much fewer issues
like the one you're reporting remain and we'll just continue
fixing the lurking bugs out there, if any...

Could the CXF developers provide some insight into these issues and if
I
should implement specific interceptors to perform these checks?

Implementing blocking intercepters is only needed if you're hitting a
CXF bug further down the chain

Our Rest
services return XML error responses and we would like to also do that
in
these cases where the messages are not constructed properly..

Sure, there's a number of ways :

- register a custom ExceptionMapper which captures RuntimeExceptions and
return a custom XML response describing an exception
- register a custom ServletFiler and handle the original exceptions
wrapped in ServletExceptions
- register a custom out fault interceptor with jaxrs:server, write
details to the HttpServletResponse stream and abort the chain -
a test showing how to do it will be available shortly


thanks, Sergey


Thanks



Mustafa


----- Original Message ----- From: "Mustafa Sezgin" <[email protected]>
To: <[email protected]>
Sent: Thursday, November 05, 2009 7:03 AM
Subject: NPE when doing a post with null content type


Hi all,



Im using CXF 2.2.2 and have come across an issue which I thought would
raise with you guys to see if i should submit a patch..I am doing a
POST
request to a Rest service which accepts a multi part message.  If i
craft
a message such that the following output is produced by CXF



[2009-11-05 17:34:42,512
debug][haseinterceptorchain][12601...@qtp-288204-3
g1n57lim][127.0.0.1][]
Chain org.apache.cxf.phase.phaseinterceptorch...@1bf6406 was created.
Current flow:

 receive [LoggingInInterceptor]

 unmarshal [JAXRSInInterceptor]

 pre-logical [OneWayProcessorInterceptor]

 pre-invoke [MonitoringInterceptor, ExtAPIThrottlingInterceptor,
EventOriginInterceptor]

 invoke [ServiceInvokerInterceptor]

 post-invoke [OutgoingChainInterceptor]



[2009-11-05 17:34:42,512
debug][haseinterceptorchain][12601...@qtp-288204-3
g1n57lim][127.0.0.1][]
Invoking handleMessage on interceptor
org.apache.cxf.interceptor.logginginintercep...@1f6d4ab

[2009-11-05 17:34:42,512 INFO
][loggingininterceptor][12601...@qtp-288204-3 g1n57lim][127.0.0.1][]
Inbound Message

----------------------------

ID: 31

Address: /api/projects/107/mail

Encoding: UTF-8

Content-Type:

Headers: {connection=[Keep-Alive], Host=[localhost:8080],
Content-Length=[0], User-Agent=[Apache-HttpClient/4.0-beta2 (java
1.5)],
Content-Type=[null]}

Payload:

--------------------------------------

Then  I get the following stacktrace



javax.ws.rs.WebApplicationException: java.lang.NullPointerException

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:
839)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:470
)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:43
5)

               at

org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSIn
Interceptor.java:194)

               at

org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInI
nterceptor.java:65)

               at

org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorCha
in.java:236)

               at

org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiation
Observer.java:89)

               at

org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestinat
ion.java:99)

               at

org.apache.cxf.transport.servlet.ServletController.invokeDestination(Servl
etController.java:368)

               at

org.apache.cxf.transport.servlet.ServletController.invoke(ServletControlle
r.java:146)

               at

org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServ
let.java:163)

               at

org.apache.cxf.transport.servlet.AbstractCXFServlet.doPost(AbstractCXFServ
let.java:141)

               at
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

               at
javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

               at
org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1166)

at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilte
rInternal(OpenSessionInViewFilter.java:198)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)

               at

org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216
)

               at

org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)

               at

org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)

               at
org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)

               at

org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCo
llection.java:230)

               at

org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:
114)

               at

org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)

               at org.mortbay.jetty.Server.handle(Server.java:326)

               at
org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)

               at

org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnect
ion.java:915)

               at
org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)

               at
org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)

               at
org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)

               at

org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:
228)

               at

org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:5
82)

Caused by: java.lang.NullPointerException

               at

org.apache.cxf.jaxrs.impl.HttpHeadersImpl.getListValues(HttpHeadersImpl.ja
va:132)

               at

org.apache.cxf.jaxrs.impl.HttpHeadersImpl.getRequestHeaders(HttpHeadersImp
l.java:84)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:
827)

               ... 55 more

This seems to related to the Content-Type list having a null object.
The
HttpHeaderImpl class seems to do the following on line 132



String[] ls =  values.get(0).split(",");



But because content type has a null object, the NPE is thrown.



I have also found another issue where the content-type is set to
multipart/mixed but no post content exists...

For a message such that

[2009-11-05 17:34:51,695 INFO
][loggingininterceptor][12601...@qtp-288204-3 g1n57smk][127.0.0.1][]
Inbound Message

----------------------------

ID: 32

Address: /api/projects/107/mail

Encoding: UTF-8

Content-Type: multipart/mixed

Headers: {content-type=[multipart/mixed], connection=[Keep-Alive],
Host=[localhost:8080], Content-Length=[0],
User-Agent=[Apache-HttpClient/4.0-beta2 (java 1.5)],
Content-Type=[multipart/mixed]}

Payload:

--------------------------------------

I get



javax.ws.rs.WebApplicationException:
java.lang.StringIndexOutOfBoundsException: String index out of range:
-1

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:
839)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:470
)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:43
5)

               at

org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSIn
Interceptor.java:194)

               at

org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInI
nterceptor.java:65)

               at

org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorCha
in.java:236)

               at

org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiation
Observer.java:89)

               at

org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestinat
ion.java:99)

               at

org.apache.cxf.transport.servlet.ServletController.invokeDestination(Servl
etController.java:368)

               at

org.apache.cxf.transport.servlet.ServletController.invoke(ServletControlle
r.java:146)

               at

org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServ
let.java:163)

               at

org.apache.cxf.transport.servlet.AbstractCXFServlet.doPost(AbstractCXFServ
let.java:141)

               at
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

               at
javax.servlet.http.HttpServlet.service(HttpServlet.java:820)

               at
org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1166)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilte
rInternal(OpenSessionInViewFilter.java:198)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(Delega
tingFilterProxy.java:236)

               at

org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFi
lterProxy.java:167)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerReques
tFilter.java:76)

               at

org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandl
er.java:1157)

               at

org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)

               at

org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216
)

               at

org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)

               at

org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)

               at
org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)

               at

org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCo
llection.java:230)

               at

org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:
114)

               at

org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)

               at org.mortbay.jetty.Server.handle(Server.java:326)

               at
org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)

               at

org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnect
ion.java:915)

               at
org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)

               at
org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)

               at
org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)

               at

org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:
228)

               at

org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:5
82)

Caused by: java.lang.StringIndexOutOfBoundsException: String index out
of
range: -1

               at java.lang.String.checkBounds(String.java:398)

               at java.lang.String.<init>(String.java:443)

               at
org.apache.cxf.helpers.IOUtils.newStringFromBytes(IOUtils.java:65)

               at

org.apache.cxf.attachment.AttachmentDeserializer.findBoundaryFromInputStre
am(AttachmentDeserializer.java:142)

               at

org.apache.cxf.attachment.AttachmentDeserializer.initializeRootMessage(Att
achmentDeserializer.java:105)

               at

org.apache.cxf.attachment.AttachmentDeserializer.initializeAttachments(Att
achmentDeserializer.java:85)

               at

org.apache.cxf.interceptor.AttachmentInInterceptor.handleMessage(Attachmen
tInInterceptor.java:60)

               at

org.apache.cxf.jaxrs.ext.MessageContextImpl.createAttachments(MessageConte
xtImpl.java:131)

               at

org.apache.cxf.jaxrs.ext.MessageContextImpl.get(MessageContextImpl.java:58
)

               at

org.apache.cxf.jaxrs.impl.tl.ThreadLocalMessageContext.get(ThreadLocalMess
ageContext.java:38)

               at

org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getMultipartBody(Atta
chmentUtils.java:81)

               at

org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getAttachments(Attach
mentUtils.java:86)

               at

org.apache.cxf.jaxrs.provider.MultipartProvider.readFrom(MultipartProvider
.java:76)

               at

org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:
827)

               ... 55 more

Now CXF may have deliberately not implemented these checks for some
reason, and left these checks for us to implement via the use of an
interceptor, but I would find that a bit odd.

Could the CXF developers provide some insight into these issues and if
I
should implement specific interceptors to perform these checks? Our
Rest
services return XML error responses and we would like to also do that
in
these cases where the messages are not constructed properly..

Thanks



Mustafa





Reply via email to