Java HttpServer can't handle Requests for Context "/" - java

I am currently setting up a Java HttpServer. It is working fine except for one thing:
Whenever I set the HttpContext to "/", it can not handle the request and sais: "500 Internal Server Error
No handler for context". This is the only thing which is not working, everything else was working fine.
private static WOP instance;
private WebServer webServer;
private WOP() {
webServer = new WebServer(8080);
HttpContext httpContext = webServer.getHttpServer().createContext("/");
httpContext.setHandler(this::handleRequest);
webServer.getHttpServer().start();
}
private void handleRequest(HttpExchange httpExchange) throws IOException {
String response = "Hi there!";
httpExchange.sendResponseHeaders(200, response.getBytes().length);//response code and length
OutputStream os = httpExchange.getResponseBody();
os.write(response.getBytes());
os.close();
}

Related

Receive parameter from URL with # symbol

I have problems reading the parameters with the following URL:
http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
Example from: https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3
I receive the request with simple implementation of com.sun.net.httpserver.HttpServer for integration test purposes.
Apparently, the HTTPServer can not handle the # symbol in the URL.
Here is my code. The System.out prints only: /oidc_test_callback
What do I need to do to read the parameter 'access_token'?
class OidcCallbackServer {
private final HttpServer server;
private final OidcCallbackHandler oidcCallbackHandler;
OidcCallbackServer(final int port) throws IOException {
this.server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), port), 0);
this.oidcCallbackHandler = new OidcCallbackHandler();
this.server.createContext("/oidc_test_callback", this.oidcCallbackHandler);
this.server.setExecutor(null); // creates a default executor
this.server.start();
}
private class OidcCallbackHandler implements HttpHandler {
#Override
public void handle(final HttpExchange request) throws IOException {
URI requestURI = request.getRequestURI();
System.out.println(requestURI);
}
}
Here is my URL for the Keycloak Server:
https://keycloak:8443/auth/realms/testRealm/protocol/openid-connect/auth?client_id=my_client_id&redirect_uri=http%3A%2F%2F192.168.202.105%3A50022%2Foidc_test_callback&response_type=id_token&scope=openid+profile&state=vZq7QdXKXsHQ3cF8hczQ4cUgPNjMjfqij-cgI7pIv4E&nonce=wHzXl08I49_OzYkA5lJkn0ZEitWZfJQFEoF12bMoK3A
...and it results in:
http://my-local-ip:50022/oidc_test_callback#state=vZq7QdXKXsHQ3cF8hczQ4cUgPNjMjfqij-cgI7pIv4E&session_state=d23b427b-99fa-4bcb-a939-b66a3e91d77d&id_token=---content-of-id-token---
When "response_type" in the first URL is "code" instead of "id_token" the URL looks like:
http://192.168.202.105:50022/oidc_test_callback?state=VgWjE0IxIc2JV3iZ14KzLsXGeBPtvKeJURnNL2yE9FA&session_state=d23b427b-99fa-4bcb-a939-b66a3e91d77d&code=4cc3a01a-a0d1-482c-8bb6-163a4d7fe287.d23b427b-99fa-4bcb-a939-b66a3e91d77d.f0001f26-ff85-47c6-befa-76f97a68ad02
SO there is no "#" symbol but the common "?".

HttpServletResponse output desination when called from outside browser

I have a Java web application running under Apache Tomcat (8.0.21.0). Its function is to monitor various external processes and display alerts and periodic updated statuses in a browser. The main HTTP request handler is simple enough.
public class MyApplication extends HttpServlet
{
.
.
.
public void doPost (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
processRequest (request, response);
}
public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
processRequest (request, response);
}
private static void processRequest (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
String strOption = request.getParameter ("option");
int nOption = Integer.parseInt (strOption);
response.setContentType ("text/html");
PrintWriter out = response.getWriter ();
outputPage (out, nOption);
}
private void outputPage (PrintWriter out, int nOption)
{
out.println ("<!DOCTYPE html>");
out.println ("<html>");
out.println ("<head>");
switch (nOption)
{
// title, style and <body> content depend on option passed in request
.
.
.
}
out.println ("</body>);
out.println ("</html>");
}
}
However, the application also includes a TCP Listener and socket, to receive IoT (Internet of Things) messages:
public class MyTCPconnection extends Thread
{
public Socket clientSocket; // socket created by listener
private String url = "[local host address and servlet name]";
.
.
.
public void run ()
{
int RC = 400; // default value = "Bad Request"
try
{
// get bytes from remote process
int receiveBufferSize = clientSocket.getReceiveBufferSize ();
byte[] receiveBuffer = new byte[receiveBufferSize];
int bytesRead = TCPreceive (clientSocket, receiveBuffer); // not shown
if (bytesRead != -1 && bytesRead != 0)
{
String strOption = getOption (receiveBuffer); // not shown
}
HttpPost httpPost = new HttpPost (url);
httpPost.setHeader ("Accept", "text/html,application/xhtml+xml,application/xml");
httpPost.setHeader ("Content-Type", "application/x-www-form-urlencoded");
List<NameValuePair> requestParams = new ArrayList<NameValuePair>();
reqestParams.add (new BasicNameValuePair ("option", value));
CloseableHttpClient httpClient = HttpClients.createDefault ();
CloseableHttpResponse response = httpClient.execute (httpPost);
RC = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString (response.getEntity ());
system.out.println (responseBody);
}
catch (UnknownHostException e)
{
RC = 404;
}
catch (IOException e)
{
RC = 400;
}
TCPsend (clientSocket, RC); // reply to remote process, not shown
}
}
Take for granted that MyTCPconnection.run () generates a valid HTTP request body and submits a POST request to the main application. The problem I have encountered is that, where the POST is made from a web browser (IExplorer, Firefox etc), the application outputs a web page in the browser, but on receiving the POST request from the internal MyTCPconnection instance, it outputs nothing to any browser. Instead, it redirects the entire output to the responseBody.
I thought at first that I merely needed to save the HttpServletResponse and PrintWriter variables from a request from the browser, and pass the saved PrintWriter instance to the function outputPage. However, when I logged these, the results were:
Request from browser:
HttpServletResponse response = org.apache.catalina.connector.ResponseFacade#3e1d266b
PrintWriter out = org.apache.catalina.connector.CoyoteWriter#6bc55aa8
Request from MyTCPconnection.run ():
HttpServletResponse response = org.apache.catalina.connector.ResponseFacade#3e1d266b
PrintWriter out = org.apache.catalina.connector.CoyoteWriter#6bc55aa8
Any hints or hlp would be appreciated

Embedded Jetty web server not working, handler not invoked

I'm trying to embed Jetty 8 (8.1.18.v20150929) into a Java (jdk1.7.0_67) application. I have the following code:
public static final String HTTP_PATH = "/session";
public static final int HTTP_PORT = 9995;
// Open the HTTP server for listening to requests.
logger.info("Starting HTTP server, Port: " + HTTP_PORT + ", Path: "
+ "/session");
httpServer = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(HTTP_PORT);
connector.setHost("localhost");
httpServer.addConnector(connector);
TestHttpHandler handler = new TestHttpHandler(this);
ContextHandler ch = new ContextHandler();
ch.setContextPath(HTTP_PATH);
ch.setHandler(handler);
httpServer.setHandler(ch);
try {
httpServer.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
My handler is pretty basic as a test:
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
logger.debug("Handling");
}
If I run the app and then use CURL to send a GET request to http://localhost:9995/session, then it returns a 200 status but there's no debug output.
If I access http://localhost:9995/session2, I get a 404 error.
I've read many examples online but for some reason I can't seem to get the handler to work properly. Am I doing something wrong? Thanks
I had exactly the same problem, and this is just a misunderstanding about how the Jetty API works. I was expecting to use ContextHandlers as a minimal implementation of REST services, however ContextHandlers are meant to handle requests to an entire context base (for example http://server:80/context-base, i.e. the equivalent of an app in Tomcat). The correct way to solve this question is to use Servlets:
Server server = new Server(9995);
ServletContextHandler root = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
root.setContextPath("/");
ServletHolder holder = new ServletHolder(new HttpServlet() {
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
logger.debug("Handling");
}
});
server.start();
server.join();

sending request to the newly created jetty server for testing purposes

I'm writing integration JUnit test. My task is to test whether the response of my local server is correct. The mentioned server takes as a GET parameter an address of page to be analysed (for example: localhost:8000/test?url=http://www.example.com).
To avoid being dependent on www.example.com I want to start for this particular test my own jetty server, which always serves the same content.
private static class MockPageHandler extends AbstractHandler {
public void handle(String target,Request baseRequest, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
final String responseString = loadResource("index.html");
response.getWriter().write(responseString);
baseRequest.setHandled(true);
}
}
public void test() throws Exception {
final int PORT = 8080;
final Server server = new Server(PORT);
server.setHandler(new MockPageHandler());
server.start();
final ContentResponse response =
client.newRequest("http://localhost:8000/test?url=http://localhost:8080").send();
/* some assertions. */
server.stop();
server.join();
}
Every time I execute this test, the handle method in MockPageHandler is never invoked.
Do you have any suggestions why this not works?
P.S. When I remove server.stop() and in browser type http://localhost:8080 the proper page is shown.
Quick answer:
Remove the server.join() line. That line makes the junit thread wait until the server thread stops. Which is not needed for unit testing.
Long answer:
What we (the jetty developers) have learned about using jetty embedded servers with junit.
Use the #Before and #After annotations to start and stop the server if you have 1 test method, or some requirement that the server be pristine between test methods.
Example #Before / #After (Jetty 9.x):
public class MyTest
{
private Server server;
private URI serverUri;
#Before
public void startServer() throws Exception
{
this.server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // let connector pick an unused port #
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
// Serve capture servlet
context.addServlet(new ServletHolder(new MyServlet()),"/my/*");
// Start Server
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
this.serverUri = new URI(String.format("http://%s:%d/",host,port));
}
#After
public void stopServer()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
}
#Test
public void testMe()
{
// Issue request to server
URI requestUri = serverUri.resolve("/my/test");
// assert the response
}
}
This technique makes the server start on port 0, which is a magic number that tells the underlying stack to pick an empty port and start listening. The test case then asks the server what port number it is listening on and builds out the serverUri field to be appropropriate for this test run.
This technique works great, however, it will start/stop the server for each method.
Enter, the better technique, use the #BeforeClass and #AfterClass annotations to start/stop the server once for the entire test class, running all of the methods inside of the test class against this started server.
Example #BeforeClass / #AfterClass (Jetty 9.x):
public class MyTest
{
private static Server server;
private static URI serverUri;
#BeforeClass
public static void startServer() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // let connector pick an unused port #
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
// Serve capture servlet
context.addServlet(new ServletHolder(new MyServlet()),"/my/*");
// Start Server
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("http://%s:%d/",host,port));
}
#AfterClass
public static void stopServer()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
}
#Test
public void testMe()
{
// Issue request to server
URI requestUri = serverUri.resolve("/my/test");
// assert the response
}
}
Doesn't look much different? Yes, the changes are subtle. #Before became #BeforeClass, #After became #AfterClass. The start/stop methods are now static. The server and serverUri fields are now static.
This technique is used where we have dozens of test methods that access the same server, and those requests do not alter the state in the server. This speeds up the test case execution by simply not recreating the server between each test method.
Give a try to "com.jayway.restassured" for your http test. too easy to write some test :
#Test
public void testNotGetAll() {
expect().
statusCode(404).
when().
get(baseUrl+"/games/");
}
this method call "http://mywebserver.local:8080/rest/games/" and verify that a 404 http status code is returned.
And this approach synchronised with a Jetty server (for example) started at pre-integration-test in the maven lifecycle, you match the perfect mix to process integration test !

How to send requests and receive responses to/from an Apache CXF-based service?

I have several servlets, which
take JSON-encoded requests as inputs,
process them and
return responses to the client as JSON-encoded objects.
Up to now I used Android as client (sample Android code see below).
Now I want to write a plain old Java program, which would send requests and receive the responses (do the same as the Android code). For this purpose I wrote a Java test (code see below, section Java code) and ran it.
At the client side I get this error:
21:43:38.930 [main] ERROR r.a.c.t.TestAcceptanceProcedure1 -
java.io.IOException: Server returned HTTP response code: 405 for URL: http://myserver/myapp/rest/GetUserIdService
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.6.0_23]
at testclient.TestAcceptanceProcedure1.test(TestAcceptanceProcedure1.java:47) ~[test-classes/:na]
In the server log, I see this message:
WARNING: No operation matching request path "/myapp/rest/GetUserIdService" is found, Relative Path: /, HTTP Method: GET, ContentType: */*, Accept: text/html,image/gif,image/jpeg,*/*,*/*;q=.2,. Please enable FINE/TRACE log level for more details
Question: How should I change my Java test to fix this error?
Note that the server is up and running (when I execute the Android code, it works).
Android code:
Sending the request and receiving the response:
final GetSimulationStatusRequest request = new GetSimulationStatusRequest();
final String json = Utils.convertToJson(request, getClass());
final String serverUrl = Utils.getServerUrl(this, "GetSimulationStatusService");
final IGetSimulationStatusAsyncTask getSimulationStatusTask =
asyncTaskFactory.createGetSimulationStatusAsyncTask(getWebServiceHelper());
Utils.setRequestAndServerUrl(json, serverUrl, getSimulationStatusTask);
final GetSimulationStatusResponse simulationStatusReponse =
getSimulationStatusTask.get();
Utils.convertToJson:
public static String convertToJson(final Object aRequest, Class<? extends Activity> aClass) {
final ObjectMapper mapper = new ObjectMapper();
String json = null;
try {
json = mapper.writeValueAsString(aRequest);
} catch (final JsonProcessingException exception) {
Log.e(aClass.getSimpleName(), exception.getLocalizedMessage(),
exception);
}
return json;
}
Utils.setRequestAndServerUrl:
public static void setRequestAndServerUrl(final String aJson,
final String aServerUrl, final IAsyncTask aTask) {
aTask.addNameValuePair("request", aJson);
aTask.sendRequest(new String[] { aServerUrl });
}
GetSimulationStatusAsyncTask:
public class GetSimulationStatusAsyncTask
extends AsyncTask<String, String, GetSimulationStatusResponse>
implements IGetSimulationStatusAsyncTask {
private static final String TAG = GetSimulationStatusAsyncTask.class.getSimpleName();
private IWebServiceTaskHelper helper;
private ICcpResponseParser<GetSimulationStatusResponse> responseParser =
new CcpResponseParser<GetSimulationStatusResponse>();
public GetSimulationStatusAsyncTask(final IWebServiceTaskHelper aHelper) {
helper = aHelper;
}
#Override
public void addNameValuePair(final String aName, final String aValue) {
helper.addNameValuePair(aName, aValue);
}
#Override
protected GetSimulationStatusResponse doInBackground(String... aArgs) {
return (GetSimulationStatusResponse)Utils.processResponse(this.helper, TAG, responseParser,
GetSimulationStatusResponse.class, aArgs);
}
#Override
public void sendRequest(final String[] aArgs) {
execute(aArgs);
}
}
Java code:
#Test
public void test() throws JsonProcessingException, MalformedURLException {
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.connect();
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
}
private String convertToJson(final GetUserIdRequest aRequest) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(aRequest);
}
private String getServerUrl(final String aServiceName)
{
return "http://myserver.com/myapp/rest/" + aServiceName;
}
Update 1 (09.10.2013 12:23 MSK):
#Path("/GetSimulationStatusService")
public class GetSimulationStatusService extends BaseCcpService {
private GetSimulationStatusRequestParser requestParser =
new GetSimulationStatusRequestParser();
#POST
#Produces("text/plain")
public String getSimulationStatus(#FormParam("request") final String aRequestJson)
throws JsonProcessingException
{
final GetSimulationStatusRequest request = requestParser.convert(aRequestJson);
final GetSimulationStatusResponse response = new GetSimulationStatusResponse();
response.setRequestId(request.getId());
response.setCycle(getPersistence().getCurrentCycle(request.getUserId()));
response.setLabourForce(getPersistence().getLabourForceSimulationParameter(
request.getUserId()));
return getObjectMapper().writeValueAsString(response);
}
}
Update 2 (09.10.2013 20:48 MSK): When I change the code like shown below, I get 500 HTTP response. At the server side, the aRequest argument of the method GetUserIdService.getUserId is null.
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.setRequestMethod("POST"); // Added this line
connection.connect();
Update 3 (09.10.2013 23:15): This one works:
#Test
public void test() throws JsonProcessingException, MalformedURLException
{
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.connect();
outputStream = connection.getOutputStream();
IOUtils.write("request=" + requestAsString, outputStream);
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
The 405 HTTP error code means that given method (GET) is not supported by the endpoint. Probably instead of GET request you want to send POST. I don't know what kind of request is sent by Android client.
Do you have endpoint specification/documentation?
Here you'll find information how to invoke POST using plain Java API. If you can use external libraries in your test then it can be achieved a lot easier using RESTEasy.

Categories