I use spray.io to serve HTTP requests. In response there is information about spray framework that I would like to remove. So how to remove "Server: spray-can/1.3.3" from the response header in spray?
You can set this via application.conf:
spray.can {
server {
# The value of the `Server` header to produce.
# Set to the empty string to disable rendering of the server header.
server-header = spray-can/${spray.version}
}
}
Related
Summary
I'm implementing a web service, that is deployed on a Wildfly-15 application server. I'd like to have the Content-Type HTTP response header to include charset=UTF-8. This is necessary for the client to understand my response.
Details
One of my clients always sends its request without specifying charset in Content-Type. Wildfly's web service stack in this case uses the default charset=ISO-8859-1 in the response. See this behavior in undertow code, lines 602-611:
private String extractCharset(HeaderMap headers) {
String contentType = headers.getFirst(Headers.CONTENT_TYPE);
if (contentType != null) {
String value = Headers.extractQuotedValueFromHeader(contentType, "charset");
if (value != null) {
return value;
}
}
return ISO_8859_1;
}
Because my response is, in fact, UTF-8-encoded (and its need to be), this causes trouble on the client side. See the header dumps in the undertow log:
----------------------------REQUEST---------------------------
header=Connection=Keep-Alive
header=SOAPAction=****
header=Accept-Encoding=gzip,deflate
header=Content-Type=text/xml
header=Content-Length=2137
header=User-Agent=Apache-HttpClient/4.1.1 (java 1.5)
header=Host=****
locale=[]
method=POST
....
--------------------------RESPONSE--------------------------
header=Connection=keep-alive
header=Content-Type=text/xml;charset=ISO-8859-1
header=Content-Length=1553
header=Date=Tue, 29 Jan 2019 16:19:38 GMT
status=200
This kind of response leads to the following exception in an IBM Websphere application:
org.springframework.ws.InvalidXmlException: Could not parse XML; nested exception is org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0xffffffff) was found in the element content of the document.
Unfortunately, modifying the client is not an option.
Unsuccessful experiments
My efforts so far went into trying to configure Widlfy's undertow via specifying filters to override HTTP Response headers. I was able to set Content-Encoding only, with the help of Response Header filter. It seems, the Content-Type header is overridden somewhere else along the line.
My second guess was to use Expression Filter with the expression
header(header=Content-Type, value='text/xml;charset=UTF-8')
Unfortunately, it didn't work also.
Question
Can this problem be solved by the configuration of undertow?
Or should I somehow (how?) programmatically set the HTTP response header to include charset=UTF-8?
I have an angular client which is making a POST call to my server. This server needs to get a response by calling another server(server2) with a POST call and pass the response from the server2 to the client. I tried the following approaches.
public Response call(){
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.fromResponse(restClient.post(server2Url)).build();
}
But in the above case the HTTP status code gets transferred but not the response body. The response body is empty
Then I tried:
public Response call() throws URISyntaxException{
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.temporaryRedirect(new URI(server2Url)).build();
}
but the browser client ends up making an OPTIONS call to the server2Url instead of a POST
and I tried.
public Response call() throws URISyntaxException{
String server2Url = "http://server2/path"
RestClient restClient = new RestClient();
return Response.seeOther(new URI(server2Url)).build();
}
but this ends up making a GET call instead of a POST.
How do I make the browser client make a POST call to server2
You can use Html Client from JAX-RS to make your own requests (from server1 to server2) and then return the response from server2 to the angular client.
public Response call() {
String url = "server2 url";
Response response;
try {
response = ClientBuilder
.newClient()
.target(url)
.request()
.post(Entity.json(null), Response.class);
}
catch (Exception e) {
// Whatever you want
return null; // or error
}
// Return the status returned by server 2
return Response.status(response.getStatus()).build();
}
What you are trying to accomplish is covered in the RFC 2616 I just found here.
If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
So it looks like this is out of your hands if you´re not implementing the client.
Edit because I was told that RFC 2616 must not be used any longer.
RFC 7231 states that:
302 Found
The 302 (Found) status code indicates that the target resource
resides temporarily under a different URI. Since the redirection
might be altered on occasion, the client ought to continue to use the
effective request URI for future requests.
The server SHOULD generate a Location header field in the response
containing a URI reference for the different URI. The user agent MAY
use the Location field value for automatic redirection. The server's
response payload usually contains a short hypertext note with a
hyperlink to the different URI(s).
Note: For historical reasons, a user agent MAY change the request
method from POST to GET for the subsequent request. If this
behavior is undesired, the 307 (Temporary Redirect) status code
can be used instead.
What is:
307 Temporary Redirect
The 307 (Temporary Redirect) status code indicates that the target
resource resides temporarily under a different URI and the user agent
MUST NOT change the request method if it performs an automatic
redirection to that URI. Since the redirection can change over time,
the client ought to continue using the original effective request URI
for future requests.
The server SHOULD generate a Location header field in the response
containing a URI reference for the different URI. The user agent MAY
use the Location field value for automatic redirection. The server's
response payload usually contains a short hypertext note with a
hyperlink to the different URI(s).
Note: This status code is similar to 302 (Found), except that it
does not allow changing the request method from POST to GET. This
specification defines no equivalent counterpart for 301 (Moved
Permanently) ([RFC7238], however, defines the status code 308
(Permanent Redirect) for this purpose).
I’m currently trying to setup withRequestTimeout directive for service based on akka-http.
withRequestTimeout(FiniteDuration(1, TimeUnit.SECONDS),req =>
HttpResponse(status = StatusCodes.InternalServerError, entity = "Request timeout"))
For http connection it works fine and returns my custom response, but for https it usually returns No Response and sometimes my custom response. I traced request and it looks like it was cut down before server returned actual response. What can be potential issue that causes it?
I enabled gzip compression for all the responses in my web service (Play 2.4) by following those instructions. Easy to set up, and I can see it works like a charm having checked with curl and wireshark that the responses are sent compressed.
Now I want to be a good developer and add an integration test to make sure no one breaks HTTP compression next week. Here's where the fun begins! My test looks like this:
"use HTTP compression" in {
forAll(endPoints) { endPoint =>
val response = await(
WS.url(Localhost + port + "/api" + endPoint).withHeaders("Accept-Encoding" -> "gzip").get()
)
response.header("Content-Encoding") mustBe Some("gzip")
}
}
However, the test fails as WS's response headers don't include content enconding information, and the body is returned as plain text, uncompressed.
[info] - should use HTTP compression *** FAILED ***
[info] forAll failed, because:
[info] at index 0, None was not equal to Some("gzip") (ApplicationSpec.scala:566)
Checking the traffic in wireshark when running this test I can clearly see the server is returning a gzip-encoded response, so it looks like WS is somehow transparently decompressing the response and stripping the content-encoding headers? Is there a way I can get the plain, compressed response with full headers so I can check whether the response is compressed or not?
I don't think you can do that. If I'm not mistaken , the problem here is that Netty return the content already uncompressed, so the header is removed also.
There is a configuration in AsyncHTTPClient to set that (setKeepEncoding), but unfortunately this only works in version 2.0 and newer, and Play 2.4 WS lib uses version 1.9.x.
Either way, the client Play gives you is already configured, and I don't know if you are able to tweak it. But you can create a new client to emulate that behavior:
// Converted from Java code: I have never worked with those APi's in Scala
val cfg = new AsyncHttpClientConfig.Builder().addResponseFilter(new ResponseFilter {
override def filter[T](ctx: FilterContext[T]): FilterContext[T] = {
val headers = ctx.getRequest.getHeaders
if (headers.containsKey("Accept-Encoding")) {
ctx.getResponseHeaders.getHeaders.put("Content-Encoding", List("gzip"))
}
ctx
}
}).build()
val client: NingWSClient = NingWSClient(cfg)
client.url("...") // (...)
Again, this is just emulating the result you need. Also, probably a more clever logic than just add gzip as Content-Encoding (ex: put the first algorithm requested in "Accepts Encoding") is advised.
Turns out we can't really use Play-WS for this specific test because it already returns the content uncompressed and stripped of the header (see #Salem's insightful answer), so there's no way to check whether the response is compressed.
However it's easy enough to write a test that checks for HTTP compression using standard Java classes. All we care about is whether the server answers in (valid) GZIP form when sending a request with Accept-Encoding: gzip. Here's what I ended up with:
forAll(endPoints) { endPoint =>
val url = new URL(Localhost + port + "/api/" + endPoint)
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestProperty("Accept-Encoding", "gzip")
Try {
new GZIPInputStream(connection.getInputStream)
} must be a 'success
}
I am trying to add a HTTP header into my SOAP request. The code is written in groovy and is using groovy-wslite library. My code looks like the following:
def client = new SOAPClient(AConfig.url)
client.httpClient.sslTrustStoreFile = abcd
client.httpClient.sslTrustStorePassword =AConfig.password
How do I add HTTP header to the client object?
You can't add an HTTP header to the client object itself.
Instead, each SOAP request that the client sends out can have its own set of HTTP headers added to it.
The first parameter to the send method can contain the HTTP headers. Here is an example:
String content = "<....SOAP message body here...>"
SOAPClient client = new SOAPClient(AConfig.url)
Map requestParams = [ headers: [ CustomHeader: "My custom header" ] ]
client.send(requestParams, content)