tomcat not sending the requested http-header - java

I have got a servlet deployed under tomcat/webapps directory and I try to send a curl request to it:
$~ curl -v http://localhost:8080/
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* Adding handle: conn: 0x33e0ee0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x33e0ee0) send_pipe: 1, recv_pipe: 0
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 302 Found
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=<ID>; Path=/; HttpOnly
< Location: http://localhost:8080/
< Content-Type: text/html;charset=EUC-KR
< Content-Length: 0
< Date: Mon, 02 Sep 2013 14:24:53 GMT
<
* Connection #0 to host localhost left intact
This is the web.xml file:
...
<servlet>
<description></description>
<display-name>vController</display-name>
<servlet-name>vController</servlet-name>
<servlet-class>com.vc.cac.controller.vlController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>vController</servlet-name>
<url-pattern>/vController</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.vc.cac.controller.vlController</listener-class>
</listener>
...
in the servlet I tried to print the Host element from header:
String host = request.getHeader("Host");
System.out.println("Host: "+host);
but I get null, so If I try to print any header element I get null as a result. any help?

On Tomcat 7.0.22, the following servlet
#WebServlet(urlPatterns = "/vController")
public class vlController extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
String host = request.getHeader("Host");
System.out.println("Host: "+host);
resp.getWriter().write("host printed");
}
}
with an index.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<jsp:forward page="/vController" />
Heello wRoldasdas
</body>
</html>
The cURL command prints
$ clear; curl -v http://localhost:8080/
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* 0x60002d0f0 is at send pipe head!
* STATE: CONNECT => WAITCONNECT handle 0x60006cac0; line 1032 (connection #0)
* Connected to localhost (127.0.0.1) port 8080 (#0)
* STATE: WAITCONNECT => DO handle 0x60006cac0; line 1151 (connection #0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
>
* STATE: DO => DO_DONE handle 0x60006cac0; line 1236 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x60006cac0; line 1352 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x60006cac0; line 1363 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=7694BACEC0C311357E72DCEA7574540A; Path=/; HttpOnly
Set-Cookie: JSESSIONID=7694BACEC0C311357E72DCEA7574540A; Path=/; HttpOnly
< Content-Type: text/html;charset=ISO-8859-1
Content-Type: text/html;charset=ISO-8859-1
< Content-Length: 12
Content-Length: 12
< Date: Mon, 02 Sep 2013 16:40:11 GMT
Date: Mon, 02 Sep 2013 16:40:11 GMT
<
* STATE: PERFORM => DONE handle 0x60006cac0; line 1533 (connection #0)
* Connection #0 to host localhost left intact
host printed
And the server clearly prints
Host: localhost:8080
In your case, the server responds with 302, so your servlet is never hit. I don't know where your null header is coming from.
Instead of with cURL, try with a Java HTTP client, ex. Apache's HttpClient.

Related

Spring Actuator /info returns an empty body

How to add custom metrics to /info endpoint in Spring Actuator 2.7.0?
Currently have the following related to actuator.
I have verified that info.app.version can retrieve the proper value from pom.xml using #Value.
pom.xml
<version>0.0.1-SNAPSHOT</version>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.7.0</version>
</dependency>
application.properties
info.app.version=#project.version#
management.endpoint.info.enabled=true
management.endpoints.web.exposure.include=info,health
But despite this I am only getting an empty response on /info.
Response header:
< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/vnd.spring-boot.actuator.v3+json
< Transfer-Encoding: chunked
< Date: Wed, 15 Jun 2022 04:12:47 GMT
* Received 7 B chunk
* Received 5 B chunk
* Connection #26 to host localhost left intact
Response body :
{}
My understanding is any property under info is included in /info endpoint. Or does this not work on actuator v2+ ?
Source
From the Spring-Boot 2.6 release notes https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#actuator-env-infocontributor-disabled-by-default
You need to enable the info env property:
management.info.env.enabled=true
Latest spring boot requires two things to be set up:
1- exposing the endpoint in application.properties file:
management.endpoints.web.exposure.include=info, health
You can use a wildcard and expose all endpoints if you want
management.endpoints.web.exposure.include=*
2- enabling info.env in application.properties:
management.info.env.enabled=true

Missing set-cookie header on POST method

When i perform a request using HTTP POST method from Angular, response comes without set-cookie header, contrary when I perform a request using HTTP GET method response comes with set-cookie Header.
I know that when POST method is used a preflight OPTIONS request is automatically issued by a browser. I am looking for advice what can i make so after POST method request client get set-cookie header as it already works with GET method?
My Angular request:
this.http.post<UserDto>("//localhost:8080/users", this.user, {withCredentials: true}).subscribe( user => {
alert("User created successfully.");
});;
Those are response headers i get:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: POST,PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: http://localhost:4200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Sun, 05 May 2019 09:22:55 GMT
Expires: 0
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
And my request headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:8080
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
My Spring Security configuration:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
cors().and().
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().addFilterBefore(
new StatelessCSRFFilter(), CsrfFilter.class);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("POST","PUT","DELETE","GET","OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
I have found such an advice:
" I got it to work by adding a response filter for the pre-flight OPTIONS request that works without credentials.
<security-constraint>
<display-name>No check for options</display-name>
<web-resource-collection>
<web-resource-name>All Access</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
I am not sure how to implement that solution is spring.
The CORS configuration has been set up correctly on the SpringFramework backend, as the methods succeed as expected, and Angular does set the cookies for GET requests. It is only POST operations that do not succeed if not preceded by HTTP.GET request.

Enable HTTP/2 for Spring Boot on Jetty

I have a Spring Boot 2.0.0 RC2 with embedded jetty and I want to enable HTTP/2.
According to docs on how to enable http/2 for jetty I added server.http2.enabled=true to my apllication.properties
And my pom.xml looks like this:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RC2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-alpn-conscrypt-server -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
<version>9.4.8.v20171121</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty.http2/http2-server -->
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>9.4.8.v20171121</version>
</dependency>
</dependencies>
Then I start it and do some GET requests (first one is HTTP1, second is HTTP2). Here is the output:
2018-02-26 18:24:59.670 INFO 20338 --- [ main] o.s.b.web.embedded.jetty.JettyWebServer : Jetty started on port(s) 8080 (http/1.1) with context path '/'
2018-02-26 18:24:59.674 INFO 20338 --- [ main] ru.example.vpndemo.VpnDemoApplication : Started VpnDemoApplication in 4.772 seconds (JVM running for 5.45)
127.0.0.1 - - [26/Feb/2018:15:25:11 +0000] "GET /example/ HTTP/1.1" 200 13
127.0.0.1 - - [26/Feb/2018:15:33:52 +0000] "PRI * HTTP/2.0" 426 0
Why does my 2nd request prints as PRI in console?
Here is a cURL output for HTTP1 request:
$ curl http://localhost:8080/example/ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /example/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Mon, 26 Feb 2018 15:37:03 GMT
< Content-Type: text/plain;charset=utf-8
< Content-Length: 13
<
* Connection #0 to host localhost left intact
Hello Spring!
And here is the output for HTTP2:
$ curl --http2-prior-knowledge http://localhost:8080/example/ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1ac3f90)
> GET /example/ HTTP/2
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection #0 to host localhost left intact
curl: (16) Error in the HTTP2 framing layer
Looks like HTTP2 is still not enabled. If so, how do I enable it for Jetty (I know, that it can be easily enabled for Tomcat or Undertow).
If it is already enabled, then what am I doing wrong to get the desired output?
Any ideas?
Thanks in advance!
UPD
To make sure my cURL is working properly with HTTP2 i started app with Undertow HTTP2. Here is the output:
$ curl --http2-prior-knowledge http://localhost:8080/example/ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x2582f90)
> GET /example/ HTTP/2
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
< content-type: text/plain;charset=UTF-8
< content-length: 13
< date: Mon, 26 Feb 2018 14:31:06 GMT
<
* Connection #0 to host localhost left intact
Hello Spring!
The sequence ...
PRI * HTTP/2.0
SM
Looking like "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" is the "HTTP/2 Connection Preface"
See: https://www.rfc-editor.org/rfc/rfc7540#section-3.5
In HTTP/2, each endpoint is required to send a connection preface as
a final confirmation of the protocol in use and to establish the
initial settings for the HTTP/2 connection. The client and server
each send a different connection preface.
For http/2 and jetty application server via maven dependency management:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
</dependency>

Change Spring WS Fault status code from 500 to 400

I have built Spring WS application (based on Spring WS 2.2.3) that exposes a small web service with couple of Operations. Each Operation receives input parameters to search a backend database and return response. Some of the parameters are mandatory (e.g. Street Name) and the Client have requested that if a request to the service is missing some of these mandatory parameters (e.g. empty Street Name) then my service should return proper SOAP Fault with HTTP status of 400.
My exception handling is working fine and I am able to return the correct SOAP Fault to the client if some a required parameter was missing form the request message and Spring WS takes care of the rest by wrapping a SOAP Fault and sends it back to the client with status code of 500 like the following:
HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml;charset=utf-8
Content-Length: 503
Date: Thu, 10 Dec 2015 22:28:02 GMT
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring xml:lang="en">Street Name is required</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Which is good except that I really want the HTTP status code to be '400 Bad Request' instead of the '500 Internal Server Error' I can't figure out how to change the status code from 500 to 400 and get similar response like the following:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml;charset=utf-8
Content-Length: 503
Date: Thu, 10 Dec 2015 22:28:02 GMT
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring xml:lang="en">Street Name is required</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Any ideas?

Jersey servlet mapping confusion

Can somebody please explain in plain English how this works (or at least why my structure doesn't)? I want a function called ExportLicenseInfo in my Jersey servlet resource, which I have called ExportResource, to map to http://example.com/myApp/export/software_licenses.{year}-{month}.{format}, for example: http://example.com/myApp/export/software_licenses_2013-10.csv
Servlet config in web.xml:
<servlet>
<servlet-name>ExportServlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.mycompany.app.ExportApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
My servlet mapping in web.xml:
<servlet-mapping>
<servlet-name>ExportServlet</servlet-name>
<url-pattern>/export</url-pattern>
</servlet-mapping>
My code with #Path annotations:
#Path("/export")
public class ExportResource {
...
#GET
#Produces({"text/csv", "application/json"})
#Path("/software_licenses_{year: [0-9][0-9][0-9][0-9]}-{month: [0-1][0-9]}.{format}")
public String ExportLicenseInfo( ... ) {
...
}
When I try to access the resource, I get a 404. Jersey trace log:
Feb 21, 2014 2:41:46 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 6 * LoggingFilter - Request received on thread http-bio-8080-exec-67
6 > GET http://localhost:8080/app/export/software_licenses_2013-10.csv
6 > host: localhost:8080
6 > connection: keep-alive
6 > cache-control: max-age=0
6 > accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
6 > user-agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
6 > accept-encoding: gzip,deflate,sdch
6 > accept-language: en
6 > cookie: JSESSIONID=DB64E0B066BDEE8CABFC94686AD6ACDC.test; JSESSIONIDSSO=61B51CEED61F8F6CE8A8DB46B38BAC9F; i18next=en
Feb 21, 2014 2:41:46 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 6 * LoggingFilter - Response received on thread http-bio-8080-exec-67
6 < 404
Try mapping the jersey servlet like this:
<servlet-mapping>
<servlet-name>ExportServlet</servlet-name>
<url-pattern>/export/*</url-pattern>
</servlet-mapping>

Categories