Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jetty12 migration help #12158

Closed
johmn123-wq opened this issue Aug 13, 2024 · 5 comments · Fixed by #12160
Closed

Jetty12 migration help #12158

johmn123-wq opened this issue Aug 13, 2024 · 5 comments · Fixed by #12160
Labels
Bug For general bugs on Jetty side

Comments

@johmn123-wq
Copy link

johmn123-wq commented Aug 13, 2024

Jetty version(s)
migration from Jetty 11.0.x to Jetty 12.0.x

Jetty Environment
Applicable for jetty-12 ee10

Java version/vendor (use: java -version)
Java17

OS type/version

Description
Here is the code for 11.0.x

public class ApacheServerHandler extends AbstractHandler{

   private ApacheServerHandler(){
       client = HttpClients.createDeafult();
   }

@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{

  String newHost = request.getHeader('sb_host');
 if(newHost.endsWith("/")){
     newHost  = StringUtils.substring(newHost, 0, newHost.length() - 1);  
  }

HttpUriRequest = null;
String method = request.getMethod();
String queryString = getQueryString(baseRequest);
String path = baseRequest.getPathInfo();
Enumeration<String>headers = request.getHeaderNames();

String newUrl = String.format("http://%s%s", newHost, path, queryString);

if("GET".equalsIgnoreCase(method){
  uriRequest = new HttpGet(newUrl);
}
else if("POST".equalsIgnoreCase(method){
  uriRequest = new HttpPost(newUrl);
}
else if("PUT".equalsIgnoreCase(method){
  uriRequest = new HttpPut(newUrl);
}
else{
  baseRequest.setHandled(false);
}

if(uriRequest instanceof HttpEntityEncloseingRequest){
  HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) uriRequest;
  entityRequest.setEntity(new InputStreamEntity(request.getInputStream()));
}

while(headers.hasMoreElements()){
    String headerName = headers.nextElement();
    if(headerName.equalIgnoreCase('Content-length'))
       continue;
    uriRequest.addHeader(headerName, baseRequest.getHeader(headerName));

    try(ClosableHttpResponse resp = client.execute(uriRequest)){
         for(Header header: resp.getAllHeaders){
                response.addHeader(header.getName(), header.getValue());
         } 
         String body = EntityUtils.toString(resp.getEntity());
         reponse.getOutputStream().write(body.getBytes())
   }

  baseRequest.setHandled(true);

}

private String getQueryString(Request request){
   
      String queryString = baseRequest.getQueryString();
      if(queryString == null){
              return "";
       }
      return queryString;
 }

}

Here is the migrated code to jetty12 where getOutStream, setHandled, response.add() etc functions are not supported.

public class ApacheServerHandler extends Handler.Abstract{

   private ApacheServerHandler(){
       client = HttpClients.createDeafult();
   }

@Override
public void handle(Request request, Response response, Callback callback) throws IOException, ServletException{

  String newHost = request.getHeaders().get('sb_host');
  if(newHost.endsWith("/")){
     newHost  = StringUtils.substring(newHost, 0, newHost.length() - 1);  
   }
 
 HttpUriRequest = null;
 String method = request.getMethod();
 String queryString = request.getHttpURI().getQuery();
 String path = request.getHttpURI().getPath();
 Enumeration<String>headers = request.getHeaders().getFieldNames();

 String newUrl = String.format("http://%s%s", newHost, path, queryString);

 if("GET".equalsIgnoreCase(method){
   uriRequest = new HttpGet(newUrl);
 }
 else if("POST".equalsIgnoreCase(method){
   uriRequest = new HttpPost(newUrl);
 }
 else if("PUT".equalsIgnoreCase(method){
   uriRequest = new HttpPut(newUrl);
 }
 else{
   baseRequest.**setHandled**(false);
 } 

 if(uriRequest instanceof HttpEntityEncloseingRequest){
  HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) uriRequest;
  entityRequest.setEntity(new InputStreamEntity(Request.asInputStream(requrest), ContentType.create(request.getHeaders().getHtHeader.**CONTENT_TYPE**.asString()))));
 }

while(headers.hasMoreElements()){
    String headerName = headers.nextElement();
    if(headerName.equalIgnoreCase('Content-length'))
       continue;
    uriRequest.addHeader(headerName, baseRequest.getHeader(headerName));

    try(ClosableHttpResponse resp = client.execute(uriRequest)){
         for(Header header: resp.getAllHeaders){
                response.**add**(header.**getName**(), header.**getValue**());
         } catch(ParseException e){
                throw new IOException(e);
     } 

         String body = EntityUtils.toString(resp.getEntity());
         reponse.getOutputStream().write(body.getBytes())
   }

   baseRequest.**setHandled**(true);
   return false;

 }


 }
@johmn123-wq johmn123-wq added the Bug For general bugs on Jetty side label Aug 13, 2024
@sbordet
Copy link
Contributor

sbordet commented Aug 13, 2024

@johmn123-wq thanks, we are updating the documentation.

I'll point you to the PR with the updated documentation, rather than duplicating the answers here.

sbordet added a commit that referenced this issue Aug 13, 2024
Updated documentation with section about migration of Handler code from Jetty 11 to Jetty 12.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
@sbordet
Copy link
Contributor

sbordet commented Aug 13, 2024

@johmn123-wq please see #12160.

Let us know if there is something missing, and we will expand.

@sbordet
Copy link
Contributor

sbordet commented Aug 13, 2024

Specific to your example, you can replace:

if("GET".equalsIgnoreCase(method)

with

if (HttpMethod.GET.is(method)

Also consider using HttpHeader.CONTENT_LENGTH.is(headerName).

You do not need to call request.setHandled(false), replace that with return false.

At the end of the handle() method, remove the call to request.setHandled(true) and just return true.

The last missing piece is that you must complete the Callback when you return true from the handle() method -- your code currently does not.

IIUC, your code also seems wrong as it calls client.execute() for every header? Maybe there are just too many braces around.

In any case, your code looks like a proxy, so consider using Jetty's ProxyHandler, so you don't have to maintain this code.

If you really want to do it on your own, when you receive the response from the external server you contacted with the client, you now have:

reponse.getOutputStream().write(body.getBytes())

change it to be:

response.write(true, ByteBuffer.wrap(body.getBytes()), callback)

where the last parameter callback is the Callback object passed to handle().
In this way, when the write() is complete, also the request/response processing will be completed.

@sbordet sbordet linked a pull request Aug 13, 2024 that will close this issue
@johmn123-wq
Copy link
Author

johmn123-wq commented Aug 14, 2024

@sbordet
yes there was mismatch of braces, Here is the modified code as per your suggestion.

public class ApacheServerHandler extends Handler.Abstract{

private ApacheServerHandler(){
client = HttpClients.createDeafult();
}

@OverRide
public void handle(Request request, Response response, Callback callback) throws IOException, ServletException{

String newHost = request.getHeaders().get('sb_host');
if(newHost.endsWith("/")){
newHost = StringUtils.substring(newHost, 0, newHost.length() - 1);
}

HttpUriRequest = null;
String method = request.getMethod();
String queryString = request.getHttpURI().getQuery();
String path = request.getHttpURI().getPath();
Enumerationheaders = request.getHeaders().getFieldNames();

String newUrl = String.format("http://%s%s", newHost, path, queryString);

if(HttpMethod.GET.matches(method)){
uriRequest = new HttpGet(newUrl);
}
else if(HttpMethod.POST.matches(method)){
uriRequest = new HttpPost(newUrl);
}
else if(HttpMethod.PUT.matches(method)){
uriRequest = new HttpPut(newUrl);
}
else{
return true;
}

if(uriRequest instanceof HttpEntityEncloseingRequest){
HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) uriRequest;
entityRequest.setEntity(Content.Source.asInputStream(request),
ContentType.create(request.getHeaders().get(HttpHeaders.CONTENT_TYPE)));
}

while(headers.hasMoreElements()){
String headerName = headers.nextElement();
if(headerName.equalIgnoreCase('Content-length'))
continue;
uriRequest.addHeader(headerName, baseRequest.getHeader(headerName));
}

try(ClosableHttpResponse resp = client.execute(uriRequest)){
     for(Header header: resp.getAllHeaders){
            response.**add**(header.**getName**(), header.**getValue**());
     } catch(ParseException e){
            throw new IOException(e);
 } 

     String body = EntityUtils.toString(resp.getEntity());
     reponse.write(true, ByteBuffer.wrap(body.getBytes()), callback);

     return false;

}

Can you please provide the alternative of this block of code 'response.add(header.getName(), header.getValue())' adding each of these headers to a new HTTP response.

HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) uriRequest;
entityRequest.setEntity(Content.Source.asInputStream(request),
ContentType.create(request.getHeaders().get(HttpHeaders.CONTENT_TYPE))); having an issue with method setEntity in interface org.apache.hc.core5.http.httpEntityContainer cannot be applied to given types;
required : org.apache.hc.core5.http.httpEntity
found: java.io.inputStream, org.apache.hc.core5.http.ContetntType
reason: actual and formal aregument lists differ in length.

Need you assistance here.

@sbordet
Copy link
Contributor

sbordet commented Aug 14, 2024

Can you please provide the alternative of this block of code 'response.add(header.getName(), header.getValue())' adding each of these headers to a new HTTP response.

I already pointed you to use HttpFields and its APIs, see its javadocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side
Projects
No open projects
Status: ✅ Done
Development

Successfully merging a pull request may close this issue.

2 participants