I am looking for sample examples implementing all the features of HTTP/2(Client-Server) like STREAMS,FRAMES PUSH_PROMISE,HPACK with detailed configuration using JETTY EMBEDDED(Jetty 10/Jetty 11) ?
It should be able to run at localhost and also if ssl certificates are needed for low level https2 detailed way to implement that.
The examples in the documentations are not every clear and are explained in parts. I tried a lot with them. Hopefully a successfully answer to this will help a lot of amateurs who wants to implement low level h2 with embedded jetty. Can anyone help me with the reference ?
Code for reference for others.
H2Server.java
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.UnaryOperator;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.GoAwayFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.parser.Parser;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import static java.lang.System.Logger.Level.INFO;
import java.io.OutputStream;
#SuppressWarnings("unused") public class H2Server {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// Create a Server instance.
QueuedThreadPool serverExecutor = new QueuedThreadPool();
serverExecutor.setName("server");
// server = new Server(serverExecutor);
Server server = new Server(serverExecutor);
// ServerSessionListener sessionListener = new ServerSessionListener.Adapter();
ServerSessionListener sessionListener = new ServerSessionListener.Adapter() {
#Override
public Map<Integer, Integer> onPreface(Session session) {
System.out.println("onPreface Called");
// Customize the settings, for example:
Map<Integer, Integer> settings = new HashMap<>();
// Tell the client that HTTP/2 push is disabled.
settings.put(SettingsFrame.ENABLE_PUSH, 0);
settings.put(SettingsFrame.ENABLE_CONNECT_PROTOCOL, 8);
return settings;
}
#Override
public void onAccept(Session session) {
System.out.println("onAccept Called");
InetSocketAddress remoteAddress = session.getRemoteAddress();
System.getLogger("http2").log(INFO, "Connection from {0}", remoteAddress);
}
#Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
System.out.println("onNewStream Called");
// This is the "new stream" event, so it's guaranteed to be a request.
MetaData.Request request = (MetaData.Request) frame.getMetaData();
if (frame.isEndStream()) {
respond(stream, request);
return null;
} else {
// Return a Stream.Listener to handle the request events,
// for example request content events or a request reset.
return new Stream.Listener.Adapter() {
#Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
// Get the content buffer.
ByteBuffer buffer = frame.getData();
// Consume the buffer, here - as an example - just log it.
// System.getLogger("http2").log(INFO, "Consuming buffer {0}", buffer);
System.getLogger("http2").log(INFO, "Consuming buffer {0}", buffer);
System.out.println("Consuming buffer {0} " +StandardCharsets.UTF_8.decode(buffer).toString());
// Tell the implementation that the buffer has been consumed.
callback.succeeded();
// By returning from the method, implicitly tell the implementation
// to deliver to this method more DATA frames when they are available.
if (frame.isEndStream()) {
System.out.println("EndStream");
respond(stream, request);
}
}
};
}
}
private void respond(Stream stream, MetaData.Request request) {
// Prepare the response HEADERS frame.
System.out.println("respond Called");
// The response HTTP status and HTTP headers.
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200,
HttpFields.EMPTY);
if (HttpMethod.GET.is(request.getMethod())) {
// The response content.
ByteBuffer resourceBytes = getResourceBytes(request);
System.out.println("Request==GET resourceBytes== "+ StandardCharsets.UTF_8.decode(resourceBytes).toString());
// Send the HEADERS frame with the response status and headers,
// and a DATA frame with the response content bytes.
stream.headers(new HeadersFrame(stream.getId(), response, null, false))
.thenCompose(s -> s.data(new DataFrame(s.getId(), resourceBytes, true)));
} else {
// Send just the HEADERS frame with the response status and headers.
System.out.println("Request==POST response== "+ response);
String content1 = "{\"greet\": \"Welcome!!!\"}";
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode(content1);
//stream.headers(new HeadersFrame(stream.getId(), response, null, true));
stream.headers(new HeadersFrame(stream.getId(), response, null, false))
.thenCompose(s -> s.data(new DataFrame(s.getId(), buffer1, true)));
}
}
private ByteBuffer getResourceBytes(MetaData.Request request)
{
return ByteBuffer.allocate(1024);
}
};
// HTTP Configuration
HttpConfiguration httpConfig = new HttpConfiguration();
// httpConfig.setSecureScheme("https");
httpConfig.setSecureScheme("https");
// httpConfig.setSecurePort(8443);
httpConfig.setSecurePort(8443);
httpConfig.setSendXPoweredBy(true);
httpConfig.setSendServerVersion(true);
// httpConfig.setRequestHeaderSize(16 * 1024);
// HTTPS Configuration
HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
// Create a ServerConnector with RawHTTP2ServerConnectionFactory.
RawHTTP2ServerConnectionFactory http2 = new RawHTTP2ServerConnectionFactory(httpConfig, sessionListener);
// Configure RawHTTP2ServerConnectionFactory, for example:
// Configure the max number of concurrent requests.
http2.setMaxConcurrentStreams(128);
// Enable support for CONNECT.
http2.setConnectProtocolEnabled(true);
// Create the ServerConnector.
ServerConnector connector = new ServerConnector(server, http2);
// connector.setPort(8080);
connector.setPort(8443);
connector.setHost("localhost");
connector.setAcceptQueueSize(128);
// Add the Connector to the Server
server.addConnector(connector);
// Start the Server so it starts accepting connections from clients.
server.start();
// new H2Server().testNoPrefaceBytes();
}
}
H2Client.java
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
public class H2Client {
public static void main(String[] args) throws Exception {
HTTP2Client http2Client = new HTTP2Client();
http2Client.start();
ClientConnector connector = http2Client.getClientConnector();
// Address of the server's encrypted port.
SocketAddress serverAddress = new InetSocketAddress("localhost", 8443);
// SocketAddress serverAddress = new InetSocketAddress("http://www.google.com/", 8080);
// Address of the server's encrypted port.
// SocketAddress serverAddress = new InetSocketAddress("localhost", 8443);
// CompletableFuture<Session> sessionCF = http2Client.connect(connector.getSslContextFactory(), serverAddress, new Session.Listener.Adapter());
CompletableFuture<Session> sessionCF = http2Client.connect(serverAddress, new Session.Listener.Adapter()
{
#Override
public Map<Integer, Integer> onPreface(Session session)
{
System.out.println("onPreface Called");
Map<Integer, Integer> configuration = new HashMap<>();
// Disable push from the server.
configuration.put(SettingsFrame.ENABLE_PUSH, 0);
// Override HTTP2Client.initialStreamRecvWindow for this session.
configuration.put(SettingsFrame.INITIAL_WINDOW_SIZE, 1024 * 1024);
return configuration;
}
});
Session session = sessionCF.get();
/*
// Configure the request headers.
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, "Jetty HTTP2Client {version}");
// The request metadata with method, URI and headers.
MetaData.Request request = new MetaData.Request("GET", HttpURI.from("http://localhost:61432"), HttpVersion.HTTP_2, requestHeaders);
// MetaData.Request request = new MetaData.Request("GET", HttpURI.from("https://www.google.com/"), HttpVersion.HTTP_2, requestHeaders);
// The HTTP/2 HEADERS frame, with endStream=true
// to signal that this request has no content.
HeadersFrame headersFrame = new HeadersFrame(request, null, true);
// Open a Stream by sending the HEADERS frame.
session.newStream(headersFrame,new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
#Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
System.out.println("onHeaders Called");
MetaData metaData = frame.getMetaData();
// Is this HEADERS frame the response or the trailers?
if (metaData.isResponse())
{
MetaData.Response response = (MetaData.Response)metaData;
System.out.println( "Received response {0}== "+ response);
}
else
{
System.out.println("Received trailers {0}== " + metaData.getFields());
}
}
#Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
System.out.println("onData Called");
// Get the content buffer.
ByteBuffer buffer = frame.getData();
// Consume the buffer, here - as an example - just log it.
System.out.println("Consuming buffer {0}" +buffer);
// Tell the implementation that the buffer has been consumed.
callback.succeeded();
// By returning from the method, implicitly tell the implementation
// to deliver to this method more DATA frames when they are available.
}
});
*/
// Configure the request headers.
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.CONTENT_TYPE, "application/json");
// The request metadata with method, URI and headers.
MetaData.Request request = new MetaData.Request("POST", HttpURI.from("http://localhost:8443/"), HttpVersion.HTTP_2, requestHeaders);
// MetaData.Request request = new MetaData.Request("POST", HttpURI.from("0.0.0.0:63780"), HttpVersion.HTTP_2, requestHeaders);
// The HTTP/2 HEADERS frame, with endStream=false to
// signal that there will be more frames in this stream.
HeadersFrame headersFrame = new HeadersFrame(request, null, false);
// Open a Stream by sending the HEADERS frame.
// CompletableFuture<Stream> streamCF = session.newStream(headersFrame, new Stream.Listener.Adapter());
// Open a Stream by sending the HEADERS frame.
CompletableFuture<Stream> streamCF = session.newStream(headersFrame, new Stream.Listener.Adapter()
{
public void onHeaders(Stream stream, HeadersFrame frame)
{
System.out.println("onHeaders Called");
MetaData metaData = frame.getMetaData();
// Is this HEADERS frame the response or the trailers?
if (metaData.isResponse())
{
MetaData.Response response = (MetaData.Response)metaData;
System.out.println( "Received response {0}== "+ response);
}
else
{
System.out.println("Received trailers {0}== " + metaData.getFields());
}
}
#Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
System.out.println("onData Called");
// Get the content buffer.
ByteBuffer buffer = frame.getData();
// Consume the buffer, here - as an example - just log it.
System.out.println("Consuming buffer {0}" +StandardCharsets.UTF_8.decode(buffer).toString());
// Tell the implementation that the buffer has been consumed.
callback.succeeded();
// By returning from the method, implicitly tell the implementation
// to deliver to this method more DATA frames when they are available.
}
});
// Block to obtain the Stream.
// Alternatively you can use the CompletableFuture APIs to avoid blocking.
Stream stream = streamCF.get();
// The request content, in two chunks.
String content1 = "{\"greet\": \"hello world\"}";
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode(content1);
String content2 = "{\"user\": \"jetty\"}";
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode(content2);
// Send the first DATA frame on the stream, with endStream=false
// to signal that there are more frames in this stream.
CompletableFuture<Stream> dataCF1 = stream.data(new DataFrame(stream.getId(), buffer1, false));
// Only when the first chunk has been sent we can send the second,
// with endStream=true to signal that there are no more frames.
dataCF1.thenCompose(s -> s.data(new DataFrame(s.getId(), buffer2, true)));
// end::newStreamWithData[]
System.out.println("EOF");
/*
*/
}
}
Trying everyting but it does not work :(
The complete code and example can be found here: https://examples.javacodegeeks.com/core-java/nio/java-nio-ssl-example/
Also you can download the full source (it is only 3 classes) by clicking here: https://examples.javacodegeeks.com/wp-content/uploads/2015/12/NioSSLExample.zip
Thanks for any help!
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
public class NioSSLExample
{
public static void main(String[] args) throws Exception
{
InetSocketAddress address = new InetSocketAddress("www.amazon.com", 443);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.connect(address);
channel.configureBlocking(false);
int ops = SelectionKey.OP_CONNECT | SelectionKey.OP_READ;
SelectionKey key = channel.register(selector, ops);
// create the worker threads
final Executor ioWorker = Executors.newSingleThreadExecutor();
final Executor taskWorkers = Executors.newFixedThreadPool(2);
// create the SSLEngine
final SSLEngine engine = SSLContext.getDefault().createSSLEngine();
engine.setUseClientMode(true);
engine.beginHandshake();
final int ioBufferSize = 32 * 1024;
final NioSSLProvider ssl = new NioSSLProvider(key, engine, ioBufferSize, ioWorker, taskWorkers)
{
#Override
public void onFailure(Exception ex)
{
System.out.println("handshake failure");
ex.printStackTrace();
}
#Override
public void onSuccess()
{
System.out.println("handshake success");
SSLSession session = engine.getSession();
try
{
System.out.println("local principal: " + session.getLocalPrincipal());
System.out.println("remote principal: " + session.getPeerPrincipal());
System.out.println("cipher: " + session.getCipherSuite());
}
catch (Exception exc)
{
exc.printStackTrace();
}
//HTTP request
StringBuilder http = new StringBuilder();
http.append("GET / HTTP/1.0\r\n");
http.append("Connection: close\r\n");
http.append("\r\n");
byte[] data = http.toString().getBytes();
ByteBuffer send = ByteBuffer.wrap(data);
this.sendAsync(send);
}
#Override
public void onInput(ByteBuffer decrypted)
{
// HTTP response
byte[] dst = new byte[decrypted.remaining()];
decrypted.get(dst);
String response = new String(dst);
System.out.print(response);
System.out.flush();
}
#Override
public void onClosed()
{
System.out.println("ssl session closed");
}
};
// NIO selector
while (true)
{
key.selector().select();
Iterator keys = key.selector().selectedKeys().iterator();
while (keys.hasNext())
{
keys.next();
keys.remove();
ssl.processInput();
}
}
}
}
http.append("GET / HTTP/1.0\r\n");
http.append("Connection: close\r\n");
http.append("\r\n");
While this is in theory a correct HTTP/1.0 request in practice, most systems today require that a Host header is included. While this is mandatory only with HTTP/1.1 it is needed if an IP address hosts multiple domains:
http.append("GET / HTTP/1.0\r\n");
http.append("Host: www.amazon.com\r\n");
http.append("\r\n");
Also note that the Connection: close is unnecessary since it is implicit with HTTP/1.0 (but not with HTTP/1.1).
Apart from that HTTP is way more complex than this simple request and even this one had its problems as you saw. If you need to implement it for yourself please study the standards instead of making assumptions of how servers react or looking only at a few examples.
I got an Webapplication including a webservice. The app is running on a tomcat where an SSL certificate is installed. The application and the webservice is running. If I try to use the webservice through the browser by entering:
https://myapp:8080/myapp/rest/test/hello
I got a working XML, which my webservices produces. Now I wrote an Client application, which is trying to consume this webservice, getting the XML and parsing it. It loads the truststore, get certificate and then establish SSL handshake. Works as designed!
But by trying to start a GET Request to the Webservice, I got an empty Response from it. I tried to log as much as possible and I logged the request which is being made:
GET https://myapp:8080/myapp/rest/test/hello returned a response status of 401 Unauthorized
Because I dont get any exception, my question is, why is the webservice working, when I use it through the browser but not through code?
Following the code used by my client:
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.ArrayList;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Logger;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import execution_units.SQLTestExecutionUnit;
import execution_units.ScriptTestExecutionUnit;
import execution_units.UnixTestExecutionUnit;
public class WebServiceGET {
/*
* VARIABLES
*/
// Client
private Client clt_output = null;
// ClientConfig
private ClientConfig cnf_output = null;
private SSLContext ctx_ssl = null;
// ClientResponse
private ClientResponse clr_output = null;
// WebResources
private WebResource wre_output = null;
// Booleans for Connections
private boolean boo_output_connection = false;
// Parsing
private ResponseParsingUnit rpu_parser = null;
// Log
private Logger log = null;
/*
* CONSTRUCTOR
*/
public WebServiceGET(String str_server_url, String str_host_name, int int_timeout, String str_truststore_path,
String str_truststore_password, int int_exit_xmlinvalid, int int_exit_notestcases) {
// Add Class to Log4J framework
log = Logger.getLogger("wsg");
log.info("\t\tLog for Web Service GET initialized.");
// Create SSL Configs
try {
ctx_ssl = SSLContext.getInstance("TLS");
KeyStore truststore = KeyStore.getInstance("JKS");
truststore.load(new FileInputStream(str_truststore_path), str_truststore_password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(truststore);
ctx_ssl.init(null, tmf.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(ctx_ssl.getSocketFactory());
cnf_output = new DefaultClientConfig();
cnf_output.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
new HTTPSProperties(null, ctx_ssl));
} catch (Exception ex) {
ex.printStackTrace();
}
/* OUTPUT */
// Create client
try {
clt_output = Client.create(cnf_output);
} catch (Exception x) {
log.warn("\tInterrupted while cnf_output created client. Exception: ", x);
}
// Set timeout (read- and connection- receive the same value.)
clt_output.setConnectTimeout(int_timeout * 1000);
clt_output.setReadTimeout(int_timeout * 1000);
// Tireless Connection Establishment to WebService
while (!boo_output_connection) {
// Stitch URL together
try {
log.debug("\tConnection-URL (Output): " + str_server_url);
wre_output = clt_output.resource(str_server_url);
// Set MediaType (XML)
clr_output = wre_output.accept(MediaType.TEXT_XML).get(ClientResponse.class);
log.debug("\toutput status info (Output): " + "\tSTATUS==>" + clr_output.getStatusInfo()
+ "\tStringResponse==>" + clr_output.toString());
// following code is not necessary, because the reponse from server is always empty!
} catch (Exception ex) {
log.warn("\tConnection for GET-Request could not be established! Exception: ", ex);
try {
log.debug("\tTry to reconnect with server in : " + int_timeout + " [s]");
Thread.sleep(int_timeout * 1000);
} catch (Exception ex_sub) {
log.warn("\tInterrupted while sleeping. Exception: ", ex_sub);
}
}
}
}
}
History for context:
I am trying to run a web job from an HTTP Client. The file is a ZIP file . and contains a java class and bat file to run that java class. This runs okay when i do from POSTMAN. But when i use HTTP client, i get the following error always " '---i-NPsGbTVUpaP0CeJxMQVrHoDHvaxo3' is not recognized as an internal or external command" - Please help – Jagaran yesterday
#Jagaran if it only happen from some clients, it is likely unrelated. Please ask a new question – David Ebbo 21 hours ago
No any HTTP Client i am using in java, it is the same. it works in CURL or loading from web console. My sample code below – Jagaran 2 hours ago
No any HTTP Client i am using in java, it is the same. it works in CURL or loading from web console.
Do you have any sample Java based HTTP Client where I can publish Azure Web Job? I have tried all Java REST clients.
May be i am doing something wrong. The error I get in Azure console is '---i-NPsGbTVUpaP0CeJxMQVrHoDHvaxo3' is not recognized as an internal or external command, [08/25/2017 09:30:22 > e7f683: ERR ] operable program or batch file.o
I feel Content type = applciation /zip is not happening correctly when using java. Please help us.
Sample Code:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.http.entity.ContentType;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
/**
* #author jagaran.das
*
*/
public class AIPHTTPClient {
/**
* #param args
* #throws IOException
*/
#SuppressWarnings({ "unused", "rawtypes" })
public static void main(String[] args) throws IOException {
try {
URI uri = new AIPHTTPClient().getURI();
HttpResponse<InputStream> jsonResponse = Unirest.put("https://<URL>/api/triggeredwebjobs/TestJOb")
.basicAuth("$AzureWebJobTestBRMS", "XXXXX")
.header("content-disposition","attachement; filename=acvbgth.bat")
.field("file", new FileInputStream(new File(uri))
,ContentType.create("content-type: application/zip"),"AzureWebJob.zip").asBinary();
System.out.println(jsonResponse.getStatusText());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public InputStream readZip() {
ZipFile zipFile = null;
ZipEntry zipEntry = zipFile.getEntry("run.bat");
InputStream stream = null;
/* try {
zipFile = new ZipFile("/Users/jagaran.das/Documents/work/AIP/AzureWebJob.zip");
java.util.Enumeration<? extends ZipEntry> entries = zipFile.entries();
while(entries.hasMoreElements()){
ZipEntry entry = entries.nextElement();
stream = zipFile.getInputStream(entry);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} */
try {
stream = zipFile.getInputStream(zipEntry);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stream;
}
public URI getURI() throws MalformedURLException {
File file = new File("/Users/jagaran.das/Documents/work/AIP/azure-poc/AzureWebJob.zip");
URI fileUri = file.toURI();
System.out.println("URI:" + fileUri);
URL fileUrl = file.toURI().toURL();
System.out.println("URL:" + fileUrl);
URL fileUrlWithoutSpecialCharacterHandling = file.toURL();
System.out.println("URL (no special character handling):" + fileUrlWithoutSpecialCharacterHandling);
return fileUri;
}
}
I've been a little too harsh in my answer before really trying stuff out. Apologies. I've now tried out your snippet and looks like you're hitting an issue with Unirest - probably this one.
My advice would be to just move to Apache's HTTP library.
Here's a working sample:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.File;
public class App
{
public static void main( String[] args )
{
File sourceZipFile = new File("webjob.zip");
String kuduApiUrl = "https://yoursitename.scm.azurewebsites.net/api/zip/site/wwwroot/app_data/jobs/triggered/job988/";
HttpEntity httpEntity = EntityBuilder.create()
.setFile(sourceZipFile)
.build();
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
"$yoursitename", "SiteLevelPasSw0rD"
);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create()
.setDefaultCredentialsProvider(provider)
.build();
HttpPut putRequest = new HttpPut(kuduApiUrl);
putRequest.setEntity(httpEntity);
// Kudu's Zip API expects application/zip
putRequest.setHeader("Content-type", "application/zip");
try {
HttpResponse response = client.execute(putRequest);
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
String resBody = EntityUtils.toString(entity, "UTF-8");
System.out.println(statusCode);
System.out.println(resBody);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
That's sending Content-Type: application/zip and the raw zip contents in the body (no multipart horse manure). I've probably over-engineered the sample.. but it is what it is.
The upload is successful and the WebJob published:
Glad for you that you have solved the issue and I try to provide a workaround for your reference.
Deploy WebJob to azure , in addition to using REST API, you can also use the FTP way. Of course, the premise is that you need to know the directory uploaded by webjob via KUDU.
I offer you the snippet of code below via FTP4J libiary:
import java.io.File;
import it.sauronsoftware.ftp4j.FTPClient;
public class UploadFileByFTP {
private static String hostName = <your host name>;
private static String userName = <user name>;
private static String password = <password>;
public static void main(String[] args) {
try {
// create client
FTPClient client = new FTPClient();
// connect host
client.connect(hostName);
// log in
client.login(userName, password);
// print address
System.out.println(client);
// change directory
client.changeDirectory("/site/wwwroot/App_Data/jobs/continuous");
// current directory
String dir = client.currentDirectory();
System.out.println(dir);
File file = new File("D:/test.zip");
client.upload(file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
You can follow this tutorial to configure your parameters.
I am developing a Java client which creates the service provider dynamically with Inbound Authentication set to OAuth in WSO2 Identity Server. The code goes as follows
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.wso2.carbon.authenticator.proxy.AuthenticationAdminStub;
import org.wso2.carbon.um.ws.api.WSRealmBuilder;
import org.wso2.carbon.um.ws.api.stub.ClaimValue;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.UserStoreManager;
import org.wso2.carbon.identity.application.common.model.xsd.InboundAuthenticationConfig;
import org.wso2.carbon.identity.application.common.model.xsd.InboundAuthenticationRequestConfig;
import org.wso2.carbon.identity.application.common.model.xsd.ServiceProvider;
import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceStub;
import org.wso2.carbon.identity.oauth.stub.*;
import org.wso2.carbon.identity.oauth.stub.dto.OAuthConsumerAppDTO;
public class IdentityClient {
private final static String SERVER_URL = "https://localhost:9443/services/";
public static void main(String[] args) throws RemoteException, OAuthAdminServiceException {
String appName = "Sample_App_3";
System.setProperty("javax.net.ssl.trustStore", "wso2carbon.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
try {
OAuthAdminServiceStub stub = new OAuthAdminServiceStub(null,
SERVER_URL + "OAuthAdminService");
IdentityApplicationManagementServiceStub IAMStub = new IdentityApplicationManagementServiceStub(
null, SERVER_URL + "IdentityApplicationManagementService");
ServiceClient client = stub._getServiceClient();
ServiceClient IAMClient = IAMStub._getServiceClient();
authenticate(client);
OAuthConsumerAppDTO consumerApp = new OAuthConsumerAppDTO();
consumerApp.setApplicationName(appName);
consumerApp.setOAuthVersion("OAuth-2.0");
consumerApp.setCallbackUrl("http://localhost:8080/playground2/oauth2client");
consumerApp.setGrantTypes(
"authorization_code implicit password client_credentials refresh_token "
+ "urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm");
/* OAuthAdminProxy.registerOAuthApplicationData(consumerApp); */
stub.registerOAuthApplicationData(consumerApp);
System.out.println("Application created successfully");
authenticate(IAMClient);
InboundAuthenticationRequestConfig iaReqConfig = new InboundAuthenticationRequestConfig();
iaReqConfig.setInboundAuthKey(stub.getOAuthApplicationDataByAppName(appName)
.getOauthConsumerKey());
iaReqConfig.setInboundAuthType(stub.getOAuthApplicationDataByAppName(appName)
.getOauthConsumerSecret());
InboundAuthenticationRequestConfig[] iaReqConfigList = { iaReqConfig };
InboundAuthenticationConfig ib = new InboundAuthenticationConfig();
ib.setInboundAuthenticationRequestConfigs(iaReqConfigList);
ServiceProvider serviceProvider = new ServiceProvider();
serviceProvider.setApplicationName(
stub.getOAuthApplicationDataByAppName(appName).getApplicationName());
serviceProvider.setInboundAuthenticationConfig(ib);
IAMStub.createApplication(serviceProvider);
System.out.println("Service Provider created");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void authenticate(ServiceClient client) {
Options option = client.getOptions();
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername("admin");
auth.setPassword("admin");
auth.setPreemptiveAuthentication(true);
option.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth);
option.setManageSession(true);
}
}
Once I run this code, the service provider is getting created in the WSO2 Identity Server which I could see in the management console. The OAuth configuration which has been done vis-a-vis the service provider is not showing up and it is empty with just a 'configure' link. Had I understood WSO2 IS properly then I should be getting the consumer key and consumer secret under Inbound Authentication Configuration --> OAuth/OpenID Connect Configuration drop down.
Please help me in what should be done right ?
Try changing your client as bellow,
import java.rmi.RemoteException;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.wso2.carbon.identity.application.common.model.xsd.InboundAuthenticationConfig;
import org.wso2.carbon.identity.application.common.model.xsd.InboundAuthenticationRequestConfig;
import org.wso2.carbon.identity.application.common.model.xsd.Property;
import org.wso2.carbon.identity.application.common.model.xsd.ServiceProvider;
import org.wso2.carbon.identity.application.mgt.stub.IdentityApplicationManagementServiceStub;
import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceException;
import org.wso2.carbon.identity.oauth.stub.OAuthAdminServiceStub;
import org.wso2.carbon.identity.oauth.stub.dto.OAuthConsumerAppDTO;
public class IdentityClient {
private final static String SERVER_URL = "https://localhost:9443/services/";
public static void main(String[] args) throws RemoteException, OAuthAdminServiceException {
String appName = "Sample_App_5";
String appDescription = "Test description";
System.setProperty("javax.net.ssl.trustStore", "wso2carbon.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
try {
OAuthAdminServiceStub stub = new OAuthAdminServiceStub(null,
SERVER_URL + "OAuthAdminService");
IdentityApplicationManagementServiceStub IAMStub = new IdentityApplicationManagementServiceStub(
null, SERVER_URL + "IdentityApplicationManagementService");
ServiceClient client = stub._getServiceClient();
ServiceClient IAMClient = IAMStub._getServiceClient();
authenticate(client);
authenticate(IAMClient);
ServiceProvider serviceProvider = new ServiceProvider();
serviceProvider.setApplicationName(appName);
serviceProvider.setDescription(appDescription);
IAMStub.createApplication(serviceProvider);
OAuthConsumerAppDTO consumerApp = new OAuthConsumerAppDTO();
consumerApp.setApplicationName(appName);
consumerApp.setOAuthVersion("OAuth-2.0");
consumerApp.setCallbackUrl("http://localhost:8080/playground2/oauth2client");
consumerApp.setGrantTypes(
"authorization_code implicit password client_credentials refresh_token "
+ "urn:ietf:params:oauth:grant-type:saml2-bearer iwa:ntlm");
/* OAuthAdminProxy.registerOAuthApplicationData(consumerApp); */
stub.registerOAuthApplicationData(consumerApp);
System.out.println("Application created successfully");
System.out.println(stub.getOAuthApplicationDataByAppName(appName).getOauthConsumerKey());
authenticate(IAMClient);
InboundAuthenticationRequestConfig iaReqConfig = new InboundAuthenticationRequestConfig();
iaReqConfig.setInboundAuthKey(stub.getOAuthApplicationDataByAppName(appName).getOauthConsumerKey());
iaReqConfig.setInboundAuthType("oauth2");
Property property = new Property();
property.setName("oauthConsumerSecret");
property.setValue(stub.getOAuthApplicationDataByAppName(appName).getOauthConsumerSecret());
Property[] properties = { property };
iaReqConfig.setProperties(properties);
InboundAuthenticationRequestConfig[] iaReqConfigList = { iaReqConfig };
InboundAuthenticationConfig ib = new InboundAuthenticationConfig();
ib.setInboundAuthenticationRequestConfigs(iaReqConfigList);
serviceProvider = IAMStub.getApplication(appName);
serviceProvider.setApplicationName(
stub.getOAuthApplicationDataByAppName(appName).getApplicationName());
serviceProvider.setInboundAuthenticationConfig(ib);
IAMStub.updateApplication(serviceProvider);
System.out.println("Service Provider created");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void authenticate(ServiceClient client) {
Options option = client.getOptions();
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setUsername("admin");
auth.setPassword("admin");
auth.setPreemptiveAuthentication(true);
option.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth);
option.setManageSession(true);
}
}
Problem is createApplication does not save the configurations other than the name and the description. You have to call updateApplication to save other application configurations.